Back to index

nordugrid-arc-nox  1.1.0~rc6
Lister.cpp
Go to the documentation of this file.
00001 // -*- indent-tabs-mode: nil -*-
00002 
00003 #ifdef HAVE_CONFIG_H
00004 #include <config.h>
00005 #endif
00006 
00007 #ifdef WIN32 
00008 #include <arc/win32.h>
00009 #include <fcntl.h>
00010 #endif
00011 
00012 #include <list>
00013 #include <string>
00014 
00015 #include <globus_common.h>
00016 #include <globus_ftp_control.h>
00017 #include <globus_object.h>
00018 
00019 #include <arc/DateTime.h>
00020 #include <arc/Logger.h>
00021 #include <arc/StringConv.h>
00022 #include <arc/URL.h>
00023 #include <arc/data/FileInfo.h>
00024 #include <arc/globusutils/GlobusErrorUtils.h>
00025 #include <arc/globusutils/GSSCredential.h>
00026 
00027 #include "Lister.h"
00028 
00029 
00030 static char default_ftp_user[] = "ftp";
00031 static char default_gsiftp_user[] = ":globus-mapping:";
00032 static char default_ftp_pass[] = "user@";
00033 static char default_gsiftp_pass[] = "user@";
00034 
00035 static void dos_to_unix(char *s) {
00036   if (!s)
00037     return;
00038   int l = strlen(s);
00039   for (; l;) {
00040     l--;
00041     if ((s[l] == '\r') || (s[l] == '\n'))
00042       s[l] = ' ';
00043   }
00044 }
00045 
00046 namespace Arc {
00047 
00048   static Logger logger(Logger::rootLogger, "Lister");
00049 
00050   bool SetAttributes(FileInfo& fi, const char *facts) {
00051     const char *name;
00052     const char *value;
00053     const char *p = facts;
00054 
00055     for (; *p;) {
00056       name = p;
00057       value = p;
00058       if (*p == ' ')
00059         break; // end of facts
00060       if (*p == ';') {
00061         p++;
00062         continue;
00063       }
00064       for (; *p; p++) {
00065         if (*p == ' ')
00066           break;
00067         if (*p == ';')
00068           break;
00069         if (*p == '=')
00070           value = p;
00071       }
00072       if (name == value)
00073         continue; // skip empty names
00074       value++;
00075       if (value == p)
00076         continue; // skip empty values
00077       if (((value - name - 1) == 4) && (strncasecmp(name, "type", 4) == 0)) {
00078         if (((p - value) == 3) && (strncasecmp(value, "dir", 3) == 0))
00079           fi.SetType(FileInfo::file_type_dir);
00080         else if (((p - value) == 4) && (strncasecmp(value, "file", 4) == 0))
00081           fi.SetType(FileInfo::file_type_file);
00082         else
00083           fi.SetType(FileInfo::file_type_unknown);
00084       }
00085       else if (((value - name - 1) == 4) &&
00086                (strncasecmp(name, "size", 4) == 0)) {
00087         std::string tmp_s(value, (int)(p - value));
00088         fi.SetSize(stringtoull(tmp_s));
00089       }
00090       else if (((value - name - 1) == 6) &&
00091                (strncasecmp(name, "modify", 6) == 0)) {
00092         std::string tmp_s(value, (int)(p - value));
00093         if (tmp_s.size() < 14)
00094           fi.SetCreated(stringtoi(tmp_s)); // UNIX time
00095         else
00096           fi.SetCreated(tmp_s); // ISO time
00097       }
00098     }
00099     return true;
00100   }
00101 
00102   Lister::callback_status_t Lister::wait_for_callback() {
00103     callback_status_t res;
00104     globus_mutex_lock(&mutex);
00105     while (callback_status == CALLBACK_NOTREADY)
00106       globus_cond_wait(&cond, &mutex);
00107     res = callback_status;
00108     callback_status = CALLBACK_NOTREADY;
00109     globus_mutex_unlock(&mutex);
00110     return res;
00111   }
00112 
00113   Lister::callback_status_t Lister::wait_for_data_callback() {
00114     callback_status_t res;
00115     globus_mutex_lock(&mutex);
00116     while (data_callback_status == CALLBACK_NOTREADY)
00117       globus_cond_wait(&cond, &mutex);
00118     res = data_callback_status;
00119     data_callback_status = CALLBACK_NOTREADY;
00120     globus_mutex_unlock(&mutex);
00121     return res;
00122   }
00123 
00124   void Lister::resp_destroy() {
00125     globus_mutex_lock(&mutex);
00126     if (resp_n > 0) {
00127       globus_ftp_control_response_destroy(resp + (resp_n - 1));
00128       resp_n--;
00129     }
00130     globus_mutex_unlock(&mutex);
00131   }
00132 
00133   void Lister::resp_callback(void *arg, globus_ftp_control_handle_t*,
00134                              globus_object_t *error,
00135                              globus_ftp_control_response_t *response) {
00136     Lister *it = (Lister*)arg;
00137     globus_mutex_lock(&(it->mutex));
00138     if (error != GLOBUS_SUCCESS) {
00139       it->callback_status = CALLBACK_ERROR;
00140       std::string tmp = globus_object_to_string(error);
00141       logger.msg(INFO, "Failure: %s", tmp);
00142       if (response)
00143         logger.msg(INFO, "Response: %s", response->response_buffer);
00144     }
00145     else {
00146       if (it->resp_n < LISTER_MAX_RESPONSES) {
00147         memmove((it->resp) + 1, it->resp,
00148                 sizeof(globus_ftp_control_response_t) * (it->resp_n));
00149         if (response->response_buffer) {
00150           globus_ftp_control_response_copy(response, it->resp);
00151         } else {    // invalid reply causes *_copy to segfault
00152           it->resp->response_buffer = (globus_byte_t*)strdup("000 ");
00153           it->resp->response_buffer_size = 5;
00154           it->resp->response_length = 4;
00155           it->resp->code = 0;
00156           it->resp->response_class = GLOBUS_FTP_UNKNOWN_REPLY;
00157         }
00158         (it->resp_n)++;
00159       }
00160       it->callback_status = CALLBACK_DONE;
00161       if(response->response_buffer) {
00162         dos_to_unix((char*)(response->response_buffer));
00163         logger.msg(VERBOSE, "Response(%i): %s", (int)(response->response_length), response->response_buffer);
00164       }
00165     }
00166     globus_cond_signal(&(it->cond));
00167     globus_mutex_unlock(&(it->mutex));
00168   }
00169 
00170   void Lister::list_read_callback(void *arg,
00171                                   globus_ftp_control_handle_t*,
00172                                   globus_object_t *error,
00173                                   globus_byte_t*,
00174                                   globus_size_t length,
00175                                   globus_off_t,
00176                                   globus_bool_t eof) {
00177     Lister *it = (Lister*)arg;
00178     if(!it->data_activated) return;
00179     length += it->list_shift;
00180     if (error != GLOBUS_SUCCESS) {
00181       /* no such file or connection error - assume no such file */
00182       logger.msg(INFO, "Error getting list of files (in list)");
00183       std::string tmp = globus_object_to_string(error);
00184       logger.msg(INFO, "Failure: %s", tmp);
00185       logger.msg(INFO, "Assuming - file not found");
00186       globus_mutex_lock(&(it->mutex));
00187       it->data_callback_status = CALLBACK_ERROR;
00188       globus_cond_signal(&(it->cond));
00189       globus_mutex_unlock(&(it->mutex));
00190       return;
00191     }
00192     /* parse names and add to list */
00193     /* suppose we are receiving ordered blocks of data (no multiple streams) */
00194     char *name;
00195     (it->readbuf)[length] = 0;
00196     name = it->readbuf;
00197     it->list_shift = 0;
00198     for (;;) {
00199       if ((*name) == 0)
00200         break;
00201       globus_size_t nlen;
00202       nlen = strcspn(name, "\n\r");
00203       name[nlen] = 0;
00204       logger.msg(VERBOSE, "list record: %s", name);
00205       if (nlen == length)
00206         if (!eof) {
00207           memmove(it->readbuf, name, nlen);
00208           it->list_shift = nlen;
00209           break;
00210         }
00211       if (nlen == 0) { // skip empty std::string
00212         if (length == 0)
00213           break;
00214         name++;
00215         length--;
00216         continue;
00217       }
00218       char *attrs = name;
00219       if (it->facts) {
00220         for (; *name;) {
00221           nlen--;
00222           length--;
00223           if (*name == ' ') {
00224             name++;
00225             break;
00226           }
00227           name++;
00228         }
00229       }
00230       if(it->free_format) {
00231         // assuming it is 'ls -l'-like
00232         // a lot of attributes followed by filename
00233         // NOTE: it is not possible to reliably distinguish files
00234         // with empty spaces. So assuming no such files.
00235         char* name_start = strrchr(name,' ');
00236         if(name_start) {
00237           nlen-=(name_start-name+1);
00238           length-=(name_start-name+1);
00239           name=name_start+1;
00240         };
00241       };
00242       std::list<FileInfo>::iterator i;
00243       if (name[0] == '/') {
00244         i = it->fnames.insert(it->fnames.end(), FileInfo(name));
00245       } else {
00246         std::string name_ = !it->path.empty() ? it->path : "/";
00247         // Workaround for bug in our gridftp server!
00248         if(name[0]) {
00249           name_ += "/";
00250           name_ += name;
00251         }
00252         i = it->fnames.insert(it->fnames.end(), FileInfo(name_));
00253       }
00254       if (it->facts)
00255         SetAttributes(*i, attrs);
00256       if (nlen == length)
00257         break;
00258       name += (nlen + 1);
00259       length -= (nlen + 1);
00260       if (((*name) == '\r') || ((*name) == '\n')) {
00261         name++;
00262         length--;
00263       }
00264     }
00265     if (!eof) {
00266       if (globus_ftp_control_data_read(it->handle, (globus_byte_t*)
00267                                        ((it->readbuf) + (it->list_shift)),
00268                                        sizeof(it->readbuf) -
00269                                        (it->list_shift) - 1,
00270                                        &list_read_callback, arg) !=
00271           GLOBUS_SUCCESS) {
00272         logger.msg(INFO, "Failed reading list of files");
00273         globus_mutex_lock(&(it->mutex));
00274         it->data_callback_status = CALLBACK_ERROR;
00275         globus_cond_signal(&(it->cond));
00276         globus_mutex_unlock(&(it->mutex));
00277       }
00278       return;
00279     }
00280     it->data_activated = false;
00281     globus_mutex_lock(&(it->mutex));
00282     it->data_callback_status = CALLBACK_DONE;
00283     globus_cond_signal(&(it->cond));
00284     globus_mutex_unlock(&(it->mutex));
00285     return;
00286   }
00287 
00288   void Lister::list_conn_callback(void *arg,
00289                                   globus_ftp_control_handle_t *hctrl,
00290                                   unsigned int,
00291                                   globus_bool_t,
00292                                   globus_object_t *error) {
00293     /* if(!callback_active) return; */
00294     Lister *it = (Lister*)arg;
00295     if (error != GLOBUS_SUCCESS) {
00296       std::string tmp = globus_object_to_string(error);
00297       logger.msg(INFO, "Failure: %s", tmp);
00298       globus_mutex_lock(&(it->mutex));
00299       it->data_callback_status = CALLBACK_ERROR;
00300       globus_cond_signal(&(it->cond));
00301       globus_mutex_unlock(&(it->mutex));
00302       return;
00303     }
00304     it->list_shift = 0;
00305     it->fnames.clear();
00306     it->data_activated = true;
00307     if (globus_ftp_control_data_read(hctrl, (globus_byte_t*)(it->readbuf),
00308                                      sizeof(it->readbuf) - 1,
00309                                      &list_read_callback, arg) !=
00310         GLOBUS_SUCCESS) {
00311       logger.msg(INFO, "Failed reading data");
00312       globus_mutex_lock(&(it->mutex));
00313       it->data_callback_status = CALLBACK_ERROR;
00314       globus_cond_signal(&(it->cond));
00315       globus_mutex_unlock(&(it->mutex));
00316       return;
00317     }
00318   }
00319 
00320   globus_ftp_control_response_class_t Lister::send_command(const char *command, const char *arg, bool wait_for_response, char **sresp, char delim) {
00321     char *cmd = NULL;
00322     if (sresp)
00323       (*sresp) = NULL;
00324     if (command) { /* if no command - waiting for second reply */
00325       globus_mutex_lock(&mutex);
00326       for (int i = 0; i < resp_n; i++)
00327         globus_ftp_control_response_destroy(resp + i);
00328       resp_n = 0;
00329       callback_status = CALLBACK_NOTREADY;
00330       globus_mutex_unlock(&mutex);
00331       {
00332         std::string cmds(command);
00333         if(arg) {
00334           cmds += " ";
00335           cmds += arg;
00336         }
00337         logger.msg(VERBOSE, "Command: %s", cmds);
00338         cmds += "\r\n";
00339         cmd = (char*)malloc(cmds.length()+1);
00340         if (cmd == NULL) {
00341           logger.msg(ERROR, "Memory allocation error");
00342           return GLOBUS_FTP_UNKNOWN_REPLY;
00343         }
00344         strncpy(cmd,cmds.c_str(),cmds.length()+1);
00345         cmd[cmds.length()] = 0;
00346       }
00347       if (globus_ftp_control_send_command(handle, cmd, resp_callback, this)
00348           != GLOBUS_SUCCESS) {
00349         logger.msg(VERBOSE, "%s failed", command);
00350         if (cmd)
00351           free(cmd);
00352         return GLOBUS_FTP_UNKNOWN_REPLY;
00353       }
00354       logger.msg(DEBUG, "Command is being sent");
00355     }
00356     if (wait_for_response) {
00357       globus_mutex_lock(&mutex);
00358       while ((callback_status == CALLBACK_NOTREADY) && (resp_n == 0)) {
00359         logger.msg(DEBUG, "Waiting for response");
00360         globus_cond_wait(&cond, &mutex);
00361       }
00362       free(cmd);
00363       if (callback_status != CALLBACK_DONE) {
00364         logger.msg(DEBUG, "Callback got failure");
00365         callback_status = CALLBACK_NOTREADY;
00366         if (resp_n > 0) {
00367           globus_ftp_control_response_destroy(resp + (resp_n - 1));
00368           resp_n--;
00369         }
00370         globus_mutex_unlock(&mutex);
00371         return GLOBUS_FTP_UNKNOWN_REPLY;
00372       }
00373       if ((sresp) && (resp_n > 0)) {
00374         if (delim == 0) {
00375           (*sresp) = (char*)malloc(resp[resp_n - 1].response_length);
00376           if ((*sresp) != NULL) {
00377             memcpy(*sresp, (char*)(resp[resp_n - 1].response_buffer + 4),
00378                    resp[resp_n - 1].response_length - 4);
00379             (*sresp)[resp[resp_n - 1].response_length - 4] = 0;
00380             logger.msg(VERBOSE, "Response: %s", *sresp);
00381           }
00382           else
00383             logger.msg(ERROR, "Memory allocation error");
00384         }
00385         else {
00386           /* look for pair of enclosing characters */
00387           logger.msg(VERBOSE, "Response: %s", resp[resp_n - 1].response_buffer);
00388           char *s_start = (char*)(resp[resp_n - 1].response_buffer + 4);
00389           char *s_end = NULL;
00390           int l = 0;
00391           s_start = strchr(s_start, delim);
00392           if (s_start) {
00393             s_start++;
00394             if (delim == '(')
00395               delim = ')';
00396             else if (delim == '{')
00397               delim = '}';
00398             else if (delim == '[')
00399               delim = ']';
00400             s_end = strchr(s_start, delim);
00401             if (s_end)
00402               l = s_end - s_start;
00403           }
00404           if (l > 0) {
00405             (*sresp) = (char*)malloc(l + 1);
00406             if ((*sresp) != NULL) {
00407               memcpy(*sresp, s_start, l);
00408               (*sresp)[l] = 0;
00409               logger.msg(VERBOSE, "Response: %s", *sresp);
00410             }
00411           }
00412         }
00413       }
00414       globus_ftp_control_response_class_t resp_class =
00415         GLOBUS_FTP_UNKNOWN_REPLY;
00416       if (resp_n > 0) {
00417         resp_class = resp[resp_n - 1].response_class;
00418         globus_ftp_control_response_destroy(resp + (resp_n - 1));
00419         resp_n--;
00420       }
00421       if (resp_n == 0)
00422         callback_status = CALLBACK_NOTREADY;
00423       globus_mutex_unlock(&mutex);
00424       return resp_class;
00425     }
00426     else
00427       return GLOBUS_FTP_POSITIVE_COMPLETION_REPLY;
00428     /* !!!!!!! Memory LOST - cmd !!!!!!!! */
00429   }
00430 
00431   Lister::Lister(GSSCredential& credential)
00432     : inited(false),
00433       handle(NULL),
00434       resp_n(0),
00435       callback_status(CALLBACK_NOTREADY),
00436       connected(false),
00437       pasv_set(false),
00438       data_activated(false),
00439       credential(credential),
00440       port((unsigned short int)(-1)) {
00441     if (globus_cond_init(&cond, GLOBUS_NULL) != GLOBUS_SUCCESS) {
00442       logger.msg(ERROR, "Failed initing condition");
00443       return;
00444     }
00445     if (globus_mutex_init(&mutex, GLOBUS_NULL) != GLOBUS_SUCCESS) {
00446       logger.msg(ERROR, "Failed initing mutex");
00447       globus_cond_destroy(&cond);
00448       return;
00449     }
00450     handle = (globus_ftp_control_handle_t*)
00451              malloc(sizeof(globus_ftp_control_handle_t));
00452     if (handle == NULL) {
00453       logger.msg(ERROR, "Failed allocating memory for handle");
00454       globus_mutex_destroy(&mutex);
00455       globus_cond_destroy(&cond);
00456     }
00457     if (globus_ftp_control_handle_init(handle) != GLOBUS_SUCCESS) {
00458       logger.msg(ERROR, "Failed initing handle");
00459       globus_mutex_destroy(&mutex);
00460       globus_cond_destroy(&cond);
00461       free(handle);
00462       handle = NULL;
00463       return;
00464     }
00465     inited = true;
00466   }
00467 
00468   int Lister::close_connection() {
00469     if (!connected)
00470       return 0;
00471     logger.msg(VERBOSE, "Closing connection");
00472     if (globus_ftp_control_quit(handle, resp_callback, this) !=
00473         GLOBUS_SUCCESS)
00474       if (globus_ftp_control_force_close(handle, resp_callback, this) !=
00475           GLOBUS_SUCCESS) {
00476         logger.msg(INFO, "Failed to close connection 1");
00477         return -1;
00478       }
00479     if (wait_for_callback() != CALLBACK_DONE) {
00480       if (globus_ftp_control_force_close(handle, resp_callback, this) !=
00481           GLOBUS_SUCCESS) {
00482         logger.msg(INFO, "Failed to close connection 2");
00483         return -1;
00484       }
00485       if (wait_for_callback() != CALLBACK_DONE) {
00486         logger.msg(INFO, "Failed to close connection 3");
00487         return -1;
00488       }
00489     }
00490     connected = false;
00491     logger.msg(VERBOSE, "Closed successfully");
00492     return 0;
00493   }
00494 
00495   Lister::~Lister() {
00496     close_connection();
00497     if (inited) {
00498       if (globus_ftp_control_handle_destroy(handle) == GLOBUS_SUCCESS) {
00499         free(handle);
00500         handle = NULL;
00501       }
00502       else {
00503         logger.msg(VERBOSE, "Memory leak (globus_ftp_control_handle_t)");
00504         handle = NULL;
00505       }
00506       globus_mutex_destroy(&mutex);
00507       globus_cond_destroy(&cond);
00508     }
00509   }
00510 
00511   int Lister::setup_pasv(globus_ftp_control_host_port_t& pasv_addr) {
00512     if(pasv_set) return 0;
00513     char *sresp;
00514     GlobusResult res;
00515     if (send_command("PASV", NULL, true, &sresp, '(') !=
00516         GLOBUS_FTP_POSITIVE_COMPLETION_REPLY) {
00517       if (sresp) {
00518         logger.msg(INFO, "PASV failed: %s", sresp);
00519         free(sresp);
00520       }
00521       else
00522         logger.msg(INFO, "PASV failed");
00523       return -1;
00524     }
00525     pasv_addr.port = 0;
00526     if (sresp) {
00527       int port_low, port_high;
00528       if (sscanf(sresp, "%i,%i,%i,%i,%i,%i",
00529                  &(pasv_addr.host[0]), &(pasv_addr.host[1]),
00530                  &(pasv_addr.host[2]), &(pasv_addr.host[3]),
00531                  &port_high, &port_low) == 6)
00532         pasv_addr.port = ((port_high & 0x000FF) << 8) | (port_low & 0x000FF);
00533     }
00534     if (pasv_addr.port == 0) {
00535       logger.msg(INFO, "Can't parse host and port in response to PASV");
00536       if (sresp)
00537         free(sresp);
00538       return -1;
00539     }
00540     free(sresp);
00541     logger.msg(VERBOSE, "Data channel: %d.%d.%d.%d %d", pasv_addr.host[0],
00542                pasv_addr.host[1], pasv_addr.host[2], pasv_addr.host[3],
00543                pasv_addr.port);
00544     if (!(res = globus_ftp_control_local_port(handle, &pasv_addr))) {
00545       logger.msg(INFO, "Obtained host and address are not acceptable");
00546       logger.msg(INFO, "Failure: %s", res.str());
00547       return -1;
00548     }
00549     /* it looks like _pasv is not enough for connection - start reading
00550        immediately */
00551     data_callback_status = (callback_status_t)CALLBACK_NOTREADY;
00552     if (globus_ftp_control_data_connect_read(handle, &list_conn_callback,
00553                                              this) != GLOBUS_SUCCESS) {
00554       logger.msg(INFO, "Failed to open data channel");
00555       pasv_set = false;
00556       return -1;
00557     }
00558     pasv_set = true;
00559     return 0;
00560   }
00561 
00562   int Lister::handle_connect(const URL& url) {
00563     GlobusResult res;
00564     /* get listing */
00565     fnames.clear();
00566     globus_ftp_control_auth_info_t auth;
00567 
00568     if ((url.Protocol() != "ftp") &&
00569         (url.Protocol() != "gsiftp")) {
00570       logger.msg(ERROR, "Unsupported protocol in url %s", url.str());
00571       return -1;
00572     }
00573 
00574     bool reconnect = true;
00575 
00576     if (connected)
00577       if ((host == url.Host()) &&
00578           (port == url.Port()) &&
00579           (scheme == url.Protocol()) &&
00580           (username == url.Username()) &&
00581           (userpass == url.Passwd())) {
00582         /* same server - check if connection alive */
00583         logger.msg(VERBOSE, "Reusing connection");
00584         if (send_command("NOOP", NULL, true, NULL) ==
00585             GLOBUS_FTP_POSITIVE_COMPLETION_REPLY)
00586           reconnect = false;
00587       }
00588 
00589     path = url.Path();
00590     if ((path.length() != 0) && (path[path.length() - 1] == '/'))
00591       path.resize(path.length() - 1);
00592     if (reconnect) {
00593       connected = false;
00594       pasv_set = false;
00595       port = url.Port();
00596       scheme = url.Protocol();
00597       host = url.Host();
00598       username = url.Username();
00599       userpass = url.Passwd();
00600       /*
00601          !!!!!!!!!!!!!!!!!!!!!!!!!!!
00602          disconnect here ???????????
00603        */
00604       if (!(res = globus_ftp_control_connect(handle,
00605                                              const_cast<char*>(host.c_str()),
00606                                              port, &resp_callback, this))) {
00607         logger.msg(ERROR, "Failed connecting to server %s:%d",
00608                    host.c_str(), port);
00609         logger.msg(ERROR, "Failure: %s", res.str());
00610         return -1;
00611       }
00612       if (wait_for_callback() != CALLBACK_DONE) {
00613         logger.msg(ERROR, "Failed to connect to server %s:%d",
00614                    host.c_str(), port);
00615         resp_destroy();
00616         return -1;
00617       }
00618       resp_destroy();
00619       char *username_ = const_cast<char*>(username.c_str());
00620       char *userpass_ = const_cast<char*>(userpass.c_str());
00621       globus_bool_t use_auth;
00622       if (scheme == "gsiftp") {
00623         if (username.empty())
00624           username_ = default_gsiftp_user;
00625         if (userpass.empty())
00626           userpass_ = default_gsiftp_pass;
00627         if (globus_ftp_control_auth_info_init(&auth, credential,
00628                                               GLOBUS_TRUE, username_,
00629                                               userpass_, GLOBUS_NULL,
00630                                               GLOBUS_NULL) !=
00631             GLOBUS_SUCCESS) {
00632           logger.msg(ERROR, "Bad authentication information");
00633           return -1;
00634         }
00635         use_auth = GLOBUS_TRUE;
00636       }
00637       else {
00638         if (username.empty())
00639           username_ = default_ftp_user;
00640         if (userpass.empty())
00641           userpass_ = default_ftp_pass;
00642         if (globus_ftp_control_auth_info_init(&auth, GSS_C_NO_CREDENTIAL,
00643                                               GLOBUS_FALSE, username_,
00644                                               userpass_, GLOBUS_NULL,
00645                                               GLOBUS_NULL) !=
00646             GLOBUS_SUCCESS) {
00647           logger.msg(ERROR, "Bad authentication information");
00648           return -1;
00649         }
00650         use_auth = GLOBUS_FALSE;
00651       }
00652       if (globus_ftp_control_authenticate(handle, &auth, use_auth,
00653                                           resp_callback, this) !=
00654           GLOBUS_SUCCESS) {
00655         logger.msg(ERROR, "Failed authenticating");
00656         return -1;
00657       }
00658       if (wait_for_callback() != CALLBACK_DONE) {
00659         logger.msg(ERROR, "Failed authenticating");
00660         resp_destroy();
00661         return -1;
00662       }
00663       resp_destroy();
00664       connected = true;
00665     }
00666     return 0;
00667   }
00668 
00669   int Lister::retrieve_file_info(const URL& url,bool names_only) {
00670     if(handle_connect(url) != 0) return -1;
00671     globus_ftp_control_response_class_t cmd_resp;
00672     char *sresp;
00673     if (url.Protocol() == "gsiftp") {
00674       cmd_resp = send_command("DCAU", "N", true, &sresp, '"');
00675       if ((cmd_resp != GLOBUS_FTP_POSITIVE_COMPLETION_REPLY) &&
00676           (cmd_resp != GLOBUS_FTP_PERMANENT_NEGATIVE_COMPLETION_REPLY)) {
00677         if (sresp) {
00678           logger.msg(INFO, "DCAU failed: %s", sresp);
00679           free(sresp);
00680         }
00681         else
00682           logger.msg(INFO, "DCAU failed");
00683         return -1;
00684       }
00685       free(sresp);
00686     }
00687     globus_ftp_control_dcau_t dcau;
00688     dcau.mode = GLOBUS_FTP_CONTROL_DCAU_NONE;
00689     globus_ftp_control_local_dcau(handle, &dcau, GSS_C_NO_CREDENTIAL);
00690     globus_ftp_control_host_port_t pasv_addr;
00691     facts = true;
00692     free_format = false;
00693     if(!names_only) {
00694       /* try MLST */
00695       cmd_resp = send_command("MLST", path.c_str(), true, &sresp);
00696       if (cmd_resp == GLOBUS_FTP_PERMANENT_NEGATIVE_COMPLETION_REPLY) {
00697         logger.msg(INFO, "MLST is not supported - trying LIST");
00698         free(sresp);
00699         /* run NLST */
00700         if (setup_pasv(pasv_addr) != 0)
00701           return -1;
00702         facts = false;
00703         free_format = true;
00704         cmd_resp = send_command("LIST", path.c_str(), true, &sresp);
00705       } else {
00706         // MLST replies through control channel
00707         // 250 -
00708         //  information
00709         // 250 -
00710         if (cmd_resp != GLOBUS_FTP_POSITIVE_COMPLETION_REPLY) {
00711           logger.msg(INFO, "Immediate completion expected: %s", sresp);
00712           free(sresp);
00713           return -1;
00714         }
00715         // Try to collect full response
00716         char* nresp = strchr(sresp,'\n');
00717         if(nresp) {
00718           ++nresp;
00719         } else {
00720           free(sresp);
00721           cmd_resp = send_command(NULL, NULL, true, &sresp);
00722           if(cmd_resp != GLOBUS_FTP_UNKNOWN_REPLY) {
00723             logger.msg(INFO, "Missing information in reply: %s", sresp);
00724             free(sresp);
00725             return -1;
00726           }
00727           nresp=sresp;
00728         }
00729         char* fresp = NULL;
00730         if(nresp) {
00731           if(*nresp == ' ') ++nresp;
00732           fresp=strchr(nresp,'\n');
00733           // callback
00734           *fresp=0;
00735           list_shift = 0;
00736           fnames.clear();
00737           int nlength = strlen(nresp);
00738           if(nlength > sizeof(readbuf)) nlength=sizeof(readbuf);
00739           memcpy(readbuf,nresp,nlength);
00740           list_read_callback(this,handle,GLOBUS_SUCCESS,
00741                              (globus_byte_t*)readbuf,nlength,0,1);
00742         };
00743         if(fresp) {
00744           ++fresp;
00745         } else {
00746           free(sresp);
00747           cmd_resp = send_command(NULL, NULL, true, &sresp);
00748           if(cmd_resp != GLOBUS_FTP_POSITIVE_COMPLETION_REPLY) {
00749             logger.msg(INFO, "Missing final reply: %s", sresp);
00750             free(sresp);
00751             return -1;
00752           }
00753           fresp=sresp;
00754         }
00755         free(sresp);
00756         return 0; 
00757       }
00758     } else {
00759       if (setup_pasv(pasv_addr) != 0) return -1;
00760       facts = false;
00761       free_format = true;
00762       cmd_resp = send_command("LIST", path.c_str(), true, &sresp);
00763     }
00764     if (cmd_resp == GLOBUS_FTP_POSITIVE_COMPLETION_REPLY) {
00765       /* completion is not expected here */
00766       pasv_set = false;
00767       logger.msg(INFO, "Unexpected immediate completion: %s", sresp);
00768       if (sresp) free(sresp);
00769       return -1;
00770     }
00771     if ((cmd_resp != GLOBUS_FTP_POSITIVE_PRELIMINARY_REPLY) &&
00772         (cmd_resp != GLOBUS_FTP_POSITIVE_INTERMEDIATE_REPLY)) {
00773       if (sresp) {
00774         logger.msg(INFO, "LIST/MLST failed: %s", sresp);
00775         free(sresp);
00776       }
00777       else
00778         logger.msg(INFO, "LIST/MLST failed");
00779       return -1;
00780     }
00781     free(sresp);
00782     return transfer_list();
00783   }
00784 
00785   int Lister::retrieve_dir_info(const URL& url,bool names_only) {
00786     if(handle_connect(url) != 0) return -1;
00787     globus_ftp_control_response_class_t cmd_resp;
00788     char *sresp = NULL;
00789     if (url.Protocol() == "gsiftp") {
00790       cmd_resp = send_command("DCAU", "N", true, &sresp, '"');
00791       if ((cmd_resp != GLOBUS_FTP_POSITIVE_COMPLETION_REPLY) &&
00792           (cmd_resp != GLOBUS_FTP_PERMANENT_NEGATIVE_COMPLETION_REPLY)) {
00793         if (sresp) {
00794           logger.msg(INFO, "DCAU failed: %s", sresp);
00795           free(sresp);
00796         }
00797         else
00798           logger.msg(INFO, "DCAU failed");
00799         return -1;
00800       }
00801       free(sresp);
00802     }
00803     globus_ftp_control_dcau_t dcau;
00804     dcau.mode = GLOBUS_FTP_CONTROL_DCAU_NONE;
00805     globus_ftp_control_local_dcau(handle, &dcau, GSS_C_NO_CREDENTIAL);
00806     globus_ftp_control_host_port_t pasv_addr;
00807     facts = true;
00808     free_format = false;
00809     if (setup_pasv(pasv_addr) != 0)
00810       return -1;
00811     if(!names_only) {
00812       /* try MLSD */
00813       cmd_resp = send_command("MLSD", path.c_str(), true, &sresp);
00814       if (cmd_resp == GLOBUS_FTP_PERMANENT_NEGATIVE_COMPLETION_REPLY) {
00815         logger.msg(INFO, "MLSD is not supported - trying NLST");
00816         free(sresp);
00817         /* run NLST */
00818         facts = false;
00819         cmd_resp = send_command("NLST", path.c_str(), true, &sresp);
00820       }
00821     } else {
00822       facts = false;
00823       cmd_resp = send_command("NLST", path.c_str(), true, &sresp);
00824     }
00825     if (cmd_resp == GLOBUS_FTP_POSITIVE_COMPLETION_REPLY) {
00826       /* completion is not expected here */
00827       pasv_set = false;
00828       logger.msg(INFO, "Immediate completion: %s", sresp);
00829       if (sresp)
00830         free(sresp);
00831       return -1;
00832     }
00833     if ((cmd_resp != GLOBUS_FTP_POSITIVE_PRELIMINARY_REPLY) &&
00834         (cmd_resp != GLOBUS_FTP_POSITIVE_INTERMEDIATE_REPLY)) {
00835       if (sresp) {
00836         logger.msg(INFO, "NLST/MLSD failed: %s", sresp);
00837         free(sresp);
00838       }
00839       else
00840         logger.msg(INFO, "NLST/MLSD failed");
00841       return -1;
00842     }
00843     free(sresp);
00844     return transfer_list();
00845   }
00846 
00847   int Lister::transfer_list(void) {
00848     globus_ftp_control_response_class_t cmd_resp;
00849     char* sresp = NULL;
00850     /* start transfer */
00851     for (;;) {
00852       /* waiting for response received */
00853       cmd_resp = send_command(NULL, NULL, true, &sresp);
00854       if (cmd_resp == GLOBUS_FTP_POSITIVE_COMPLETION_REPLY)
00855         break;
00856       if ((cmd_resp != GLOBUS_FTP_POSITIVE_PRELIMINARY_REPLY) &&
00857           (cmd_resp != GLOBUS_FTP_POSITIVE_INTERMEDIATE_REPLY)) {
00858         if (sresp) {
00859           logger.msg(INFO, "Data transfer aborted: %s", sresp);
00860           free(sresp);
00861         }
00862         else
00863           logger.msg(INFO, "Data transfer aborted");
00864         // Destroy data connections here ?????????
00865         pasv_set = false;
00866         return -1;
00867       }
00868       if (sresp)
00869         free(sresp);
00870     }
00871     if (sresp)
00872       free(sresp);
00873     /* waiting for data ended */
00874     if (wait_for_data_callback() != CALLBACK_DONE) {
00875       logger.msg(INFO, "Failed to transfer data");
00876       pasv_set = false;
00877       return -1;
00878     }
00879     pasv_set = false;
00880     /* success */
00881     return 0;
00882   }
00883 
00884 } // namespace Arc