00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00031
00032
00033 #include <cxxtls/ftp.h>
00034 #include <cxxtls/strtool.h>
00035 #include <cxxtls/simple_regex.h>
00036 #include <stdlib.h>
00037 #include <portable_io.h>
00038 #include <string.h>
00039 #include <signal.h>
00040
00041 namespace cxxtls
00042 {
00043
00044 using namespace std;
00045
00046 static string error_text;
00047
00048 static string open ("open ");
00049 static string user ("user ");
00050 static string quit ("quit ");
00051 static string dir ("dir ");
00052 static string getf ("get ");
00053 static string putf ("put ");
00054 static string delf ("del ");
00055 static string cd ("cd ");
00056 static string eol ("\n");
00057 static string space (" ");
00058 static string echo ("echo ");
00059 static string oparen (" ( ");
00060 static string cparen (" ) ");
00061
00062 #ifdef _MSC_VER
00063 static string ftp (" ftp -n <ftp.cmd ");
00064 static string sh ("cmd /c ");
00065 #else
00066 static string ftp (" | ftp -n 2>/dev/null ");
00067 static string sh ("sh -c '");
00068 #endif
00069
00070 static string semic (" ; ");
00071 static string star ("*");
00072 static string binary ("binary ");
00073
00074 static bool is_ftp_error(char const *line)
00079 {
00080 static char const *loginfailure="Login Failed.";
00081 static char const *loginIncorrect="Login incorrect.";
00082 static char const *notconnected="Not connected.";
00083 static char const *user="User ";
00084
00085 if( 0 == strncmp(line, loginfailure, strlen(loginfailure))
00086 ||
00087 0 == strncmp(line, loginfailure, strlen(loginIncorrect))
00088 )
00089 {
00090 error_text = "error: incorrect username or password";
00091 return true;
00092 }
00093
00094 if(0 == strncmp(line, notconnected, strlen(notconnected)))
00095 {
00096 error_text = "error: invalid ftp site";
00097 return true;
00098 }
00099
00100 if(0 == strncmp(line, user, strlen(user)))
00101 {
00102 error_text = "error: user cannot log in";
00103 return true;
00104 }
00105
00106 return false;
00107
00108 }
00109
00110 static bool is_ftp_dir_line(char const *buffer)
00111
00112
00113
00114
00115 {
00116 return buffer[0] == 'd' ||
00117 buffer[0] == 'l' ||
00118 buffer[0] == '-';
00119 }
00120
00121 bool
00122 FTP::
00123 parse_ftp_dir_text(char const *buffer, FileStatus *statbuf, FileName *filename)
00124
00125
00126
00127
00128
00129 {
00130
00131
00132
00133
00134 StrTool::stringlist_t line;
00135
00136
00137 int patterns = StrTool::parse_words(buffer, &line, 9);
00138
00139 if(patterns != 9)
00140 return false;
00141
00142 StrTool::stringlist_t::const_iterator scan = line.begin();
00143
00144 string const& permissions = *scan++;
00145 string const& links = *scan++;
00146 string const& owner = *scan++;
00147 string const& group = *scan++;
00148 string const& size = *scan++;
00149 string const& month = *scan++;
00150 string const& day = *scan++;
00151 string const& year = *scan++;
00152
00153 string name = *scan;
00154
00155 {
00156
00157 if(!is_ftp_dir_line(permissions.c_str()))
00158 return false;
00159
00160 if(permissions.size() < 10)
00161 return false;
00162
00163
00164
00165 size_t offset = name.size();
00166
00167 {
00168 static string arrow(" -> ");
00169
00170 string::iterator where = std::search(name.begin(), name.end(),
00171 arrow.begin(), arrow.end()
00172 );
00173
00174 if(where != name.end())
00175 offset = where - name.begin();
00176 }
00177
00178
00179
00180 if(offset > 0 && offset < name.size() )
00181 name.erase(name.begin() + offset,
00182 name.end()
00183 );
00184
00185 if(name[name.size() - 1] == '\n')
00186 name.erase(name.end() -1);
00187
00188 *filename = name;
00189
00190 int tmp;
00191
00192 sscanf(size.c_str(), "%d", &tmp);
00193
00194 statbuf->size = tmp;
00195
00196 statbuf->owner_id = -2;
00197 statbuf->group_id = -2;
00198
00199 statbuf->mode.construct_from_string(permissions);
00200
00201
00202 string time_buf(month);
00203
00204 time_buf += " ";
00205 time_buf += day;
00206 time_buf += " ";
00207 time_buf += year;
00208
00209 statbuf->time.construct_from_string(time_buf);
00210
00211 string const* t = &group;
00212 t = &owner;
00213 t = &links;
00214
00215 return true;
00216 }
00217
00218
00219 return false;
00220 }
00221
00222
00223 string
00224 FTP::
00225 error()
00226 {
00227 return error_text;
00228 }
00229
00230 static int child_alarm_occurred=0;
00231
00232 extern "C" void child_alarm_handler(int signum)
00233 {
00234 #ifndef _MSC_VER
00235 child_alarm_occurred=1;
00236 #ifdef __IBMCXX_
00237 signal(SIGCHLD, child_alarm_handler);
00238 #endif
00239 #endif
00240 }
00241
00242
00243 static FILE* ftplog = 0;
00244
00245
00246 int
00247 FTP::
00248 stat_matching(char const *hostname,
00249 char const *username,
00250 char const *password,
00251 char const *pattern,
00252 std::list<FileInfo> *result
00253 )
00254
00255
00256
00257
00258
00259
00260 {
00261 int matches=0;
00262 int dirents_found=0;
00263
00264 if(!password || password[0] == 0)
00265 {
00266 error_text="Sorry, empty passwords not supported";
00267 return -1;
00268 }
00269
00270 FileName ftp_program = FileName::find_executable("ftp");
00271
00272 if(ftp_program.size() == 0)
00273 {
00274 error_text="Sorry, couldn't find 'ftp' executable in path";
00275 return -1;
00276 }
00277
00278 error_text="";
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288 FileName dirname(pattern);
00289
00290 FileName basename = dirname.basename();
00291
00292 dirname = dirname.dirname();
00293
00294 if(pattern[0] == 0 || strcmp(pattern,"*") == 0)
00295 {
00296 dirname="";
00297 pattern="*";
00298 basename=pattern;
00299 }
00300
00301 #ifdef _MSC_VER
00302
00303 string command(sh + space + ftp_program + " -n <ftp.cmd" );
00304
00305 FileName cmdfile("ftp.cmd");
00306
00307 bool err =
00308 cmdfile.write(
00309 open + space + hostname + "\r\n" +
00310 user + space + username + space + password + "\r\n" +
00311 dir + space + dirname + "\r\n" +
00312 quit + "\r\n"
00313 );
00314
00315 if(err)
00316 {
00317 error_text="couldn't write to file ftp.cmd";
00318 return -1;
00319 }
00320
00321
00322 #else
00323 string command(sh +
00324 oparen + echo + open + space + hostname + semic +
00325 echo + user + space + username + space + password + semic +
00326 echo + dir + space + dirname + semic +
00327 echo + quit + semic +
00328 cparen + ftp
00329 + "'"
00330 );
00331 #endif
00332
00333
00334
00335
00336
00337
00338
00339 child_alarm_handler(0);
00340 child_alarm_occurred = 0;
00341
00342
00343
00344 if(ftplog) fputs(command.c_str(), ftplog);
00345
00346
00347 FILE *f = popen(command.c_str(), "r");
00348
00349 if(!f)
00350 {
00351 error_text = "error: command wouldn't start\n " + command;
00352 return -1;
00353 }
00354
00355 char buffer[max_ftp_line_length];
00356
00357
00358
00359
00360
00361 int records_read = 0;
00362
00363 while(!child_alarm_occurred && fgets(buffer, max_ftp_line_length, f))
00364 {
00365 ++records_read;
00366
00367 int l = strlen(buffer);
00368
00369 if(buffer[l-1] == '\n') --l;
00370 if(buffer[l-1] == '\r') --l;
00371 buffer[l] = 0;
00372
00373 if(ftplog) { fputs(buffer, ftplog); fflush(ftplog); }
00374
00375 if( !is_ftp_dir_line(buffer) )
00376 {
00377
00378 if(is_ftp_error(buffer))
00379 {
00380 if(records_read == 0)
00381 {
00382 error_text = "Login failure";
00383 }
00384 pclose(f);
00385 return -1;
00386 }
00387
00388
00389 continue;
00390 }
00391
00392 FileInfo thisfile;
00393
00394 if( !parse_ftp_dir_text(buffer, &thisfile.status_, &thisfile.name_) )
00395 continue;
00396
00397 ++dirents_found;
00398
00399 if(thisfile.name_.matches(basename))
00400 {
00401 ++matches;
00402 result->push_back(thisfile);
00403 }
00404
00405 }
00406
00407 #ifndef _MSC_VER
00408 signal(SIGCHLD, SIG_IGN);
00409 #endif
00410
00411 pclose(f);
00412
00413 return matches;
00414
00415 }
00416
00417
00418 bool
00419 FTP::
00420 put(string hostname,
00421 string username,
00422 string password,
00423 FileName filename,
00424 string localfile
00425 )
00426 {
00427 error_text="";
00428
00429 FileName ftp_program = FileName::find_executable("ftp");
00430
00431 if(ftp_program.size() == 0)
00432 {
00433 error_text="Sorry, couldn't find 'ftp' executable in path";
00434 return -1;
00435 }
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447 #ifdef _MSC_VER
00448
00449 string command(sh + space + ftp_program + " -n <ftp.cmd");
00450
00451 FileName cmdfile("ftp.cmd");
00452
00453 cmdfile.write(
00454 open + space + hostname + "\r\n" +
00455 user + space + username + space + password + "\r\n" +
00456 cd + space + filename.dirname() + "\r\n" +
00457 binary + "\r\n" +
00458 putf + space + localfile + space + filename.basename() + "\r\n" +
00459 quit + "\r\n"
00460 );
00461
00462 #else
00463 string command(sh +
00464 oparen + echo + open + space + hostname + semic +
00465 echo + user + space + username + space + password + semic +
00466 echo + cd + space + filename.dirname() + semic +
00467 echo + binary + semic +
00468 echo + putf + space + localfile + space + filename.basename() + space + semic +
00469 echo + quit + semic +
00470 cparen + ftp +
00471 "'"
00472 );
00473 #endif
00474
00475
00476
00477
00478
00479
00480
00481 if(ftplog) fputs(command.c_str(), ftplog);
00482
00483 FILE *f = popen(command.c_str(), "r");
00484
00485 if(!f)
00486 {
00487 error_text = "error: command wouldn't start\n " + command;
00488 return -1;
00489 }
00490
00491 char buffer[max_ftp_line_length];
00492
00493
00494
00495
00496
00497 int records_read=0;
00498
00499 while(fgets(buffer, max_ftp_line_length, f))
00500 {
00501 ++records_read;
00502
00503 {
00504 if(is_ftp_error(buffer))
00505 {
00506 pclose(f);
00507 return -1;
00508 }
00509 }
00510
00511 }
00512
00513 #ifndef _MSC_VER
00514 if(records_read == 0)
00515 {
00516 error_text = "error: ftp wouldn't start -- PATH problem maybe?";
00517 pclose(f);
00518 return -1;
00519 }
00520 #endif
00521
00522 pclose(f);
00523 return false;
00524
00525 }
00526
00527
00528 bool
00529 FTP::
00530 get(string hostname,
00531 string username,
00532 string password,
00533 FileName filename,
00534 string localfile
00535 )
00536 {
00537 error_text="";
00538
00539 FileName ftp_program = FileName::find_executable("ftp");
00540
00541 if(ftp_program.size() == 0)
00542 {
00543 error_text="Sorry, couldn't find 'ftp' executable in path";
00544 return -1;
00545 }
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557 #ifdef _MSC_VER
00558 string command(sh + space + ftp_program + " -n <ftp.cmd");
00559
00560 FileName cmdfile("ftp.cmd");
00561
00562 cmdfile.write(
00563 open + space + hostname + "\r\n" +
00564 user + space + username + space + password + "\r\n" +
00565 binary + "\r\n" +
00566 getf + space + filename.basename() +
00567 space + localfile +
00568 "\r\n" +
00569 quit + "\r\n"
00570 );
00571
00572 #else
00573 string command(sh +
00574 oparen + echo + open + space + hostname + semic +
00575 echo + user + space + username + space + password + semic +
00576 echo + cd + space + filename.dirname() + semic +
00577 echo + binary + semic +
00578 echo + getf + space + filename.basename() + space + localfile + space + semic +
00579 echo + quit + semic +
00580 cparen + ftp +
00581 "'"
00582 );
00583 #endif
00584
00585
00586
00587
00588
00589 FILE *f = popen(command.c_str(), "r");
00590
00591 if(!f)
00592 {
00593 error_text = "error: command wouldn't start\n " + command;
00594 return -1;
00595 }
00596
00597 char buffer[max_ftp_line_length];
00598
00599
00600
00601
00602
00603 while(fgets(buffer, max_ftp_line_length, f))
00604 {
00605 {
00606 if(is_ftp_error(buffer))
00607 {
00608 pclose(f);
00609 return -1;
00610 }
00611 }
00612
00613 }
00614
00615 pclose(f);
00616
00617 if(localfile.size())
00618 filename = localfile;
00619 else
00620 filename = filename.basename();
00621
00622 if(!filename.exists())
00623 {
00624 error_text = "error: requested file did not download";
00625 return true;
00626 }
00627
00628 return false;
00629
00630 }
00631
00632
00633 bool
00634 FTP::
00635 del(string hostname,
00636 string username,
00637 string password,
00638 FileName filename
00639 )
00640 {
00641 error_text="";
00642
00643 FileName ftp_program = FileName::find_executable("ftp");
00644
00645 if(ftp_program.size() == 0)
00646 {
00647 error_text="Sorry, couldn't find 'ftp' executable in path";
00648 return -1;
00649 }
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660 #ifdef _MSC_VER
00661
00662 string command(sh + space + ftp_program + " -n <ftp.cmd");
00663
00664 FileName cmdfile("ftp.cmd");
00665
00666 cmdfile.write(
00667 open + space + hostname + "\r\n" +
00668 user + space + username + space + password + "\r\n" +
00669 cd + space + filename.dirname() + "\r\n" +
00670 delf + space + filename.basename() + "\r\n" +
00671 quit + "\r\n"
00672 );
00673
00674
00675 #else
00676 string command(sh +
00677 oparen + echo + open + space + hostname + semic +
00678 echo + user + space + username + space + password + semic +
00679 echo + cd + space + filename.dirname() + semic +
00680 echo + delf + space + filename.basename() + space + semic +
00681 echo + quit + semic +
00682 cparen + ftp +
00683 "'"
00684 );
00685 #endif
00686
00687
00688
00689
00690
00691 FILE *f = popen(command.c_str(), "r");
00692
00693 if(!f)
00694 {
00695 error_text = "error: command wouldn't start\n " + command;
00696 return -1;
00697 }
00698
00699 char buffer[max_ftp_line_length];
00700
00701
00702
00703
00704
00705
00706
00707 while(fgets(buffer, max_ftp_line_length, f))
00708 {
00709
00710 {
00711 if(is_ftp_error(buffer))
00712 {
00713 pclose(f);
00714 return -1;
00715 }
00716 }
00717
00718 }
00719
00720 pclose(f);
00721 return false;
00722
00723 }
00724
00725 }