"Fossies" - the Fresh Open Source Software Archive

Member "sitecopy-0.16.6/src/rcfile.c" (4 Feb 2006, 25083 Bytes) of archive /linux/www/sitecopy-0.16.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rcfile.c" see the Fossies "Dox" file reference documentation.

    1 /* 
    2    sitecopy, for managing remote web sites.
    3    Copyright (C) 1998-2006, Joe Orton <joe@manyfish.co.uk>
    4                                                                      
    5    This program is free software; you can redistribute it and/or modify
    6    it under the terms of the GNU General Public License as published by
    7    the Free Software Foundation; either version 2 of the License, or
    8    (at your option) any later version.
    9   
   10    This program is distributed in the hope that it will be useful,
   11    but WITHOUT ANY WARRANTY; without even the implied warranty of
   12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13    GNU General Public License for more details.
   14   
   15    You should have received a copy of the GNU General Public License
   16    along with this program; if not, write to the Free Software
   17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   18 
   19 */
   20 
   21 #include <config.h>
   22 
   23 #include <sys/types.h>
   24 
   25 #include <sys/stat.h>
   26 
   27 #include <ctype.h>
   28 #include <errno.h>
   29 #ifdef HAVE_STRING_H
   30 #include <string.h>
   31 #endif
   32 #ifdef HAVE_STRINGS_H
   33 #include <strings.h>
   34 #endif 
   35 #ifdef HAVE_STDLIB_H
   36 #include <stdlib.h>
   37 #endif /* HAVE_STDLIB_H */
   38 #ifdef HAVE_UNISTD_H
   39 #include <unistd.h>
   40 #endif /* HAVE_UNISTD_H */
   41 
   42 #include <ne_string.h>
   43 #include <ne_alloc.h>
   44 
   45 #include "common.h"
   46 #include "netrc.h"
   47 #include "rcfile.h"
   48 #include "sites.h"
   49 
   50 /** Global variables **/
   51 char *copypath;
   52 char *rcfile;
   53 char *netrcfile;
   54 char *home;
   55 int havenetrc;
   56 
   57 /* These are used for reporting errors back to the calling procedures. */
   58 int rcfile_linenum; 
   59 char *rcfile_err;
   60 
   61 /** Not quite so global variables **/
   62 
   63 /* These are appended to $HOME */
   64 #define RCNAME "/.sitecopyrc"
   65 #define COPYNAME "/.sitecopy/"
   66 #define NETRCNAME "/.netrc"
   67 
   68 /* Stores the list of entries in the ~/.netrc */
   69 netrc_entry *netrc_list;
   70 
   71 const char *rc_get_netrc_password(const char *server, const char *username);
   72 
   73 /* The driver definitions */
   74 #ifdef USE_FTP
   75 extern const struct proto_driver ftp_driver;
   76 #endif /* USE_FTP */
   77 #ifdef USE_DAV
   78 extern const struct proto_driver dav_driver;
   79 #endif /* USE_DAV */
   80 #ifdef USE_RSH
   81 extern const struct proto_driver rsh_driver;
   82 #endif /* USE_RSH */
   83 #ifdef USE_SFTP
   84 extern const struct proto_driver sftp_driver;
   85 #endif /* USE_SFTP */
   86 
   87 /* rcfile_read will read the rcfile and fill given sites list.
   88  * This returns 0 on success, RC_OPENFILE if the rcfile could not
   89  * be read, or RC_CORRUPT if the rcfile was corrupt.
   90  * If it is corrupt, rcfile_linenum and rcfile_line are set to the
   91  * the corrupt line.
   92  */
   93 #define LINESIZE 128
   94 int rcfile_read(struct site **sites) 
   95 {
   96     FILE *fp;
   97     int state, last_state=8, ret=0;
   98     int alpha, hash;
   99     char buf[LINESIZE];
  100     char *ch;
  101     char *ptr, key[LINESIZE], val[LINESIZE], val2[LINESIZE];
  102     /* Holders for the site info, and default site settings */
  103     struct site *this_site, *last_site, default_site = {0};
  104     
  105     if ((fp = fopen(rcfile, "r")) == NULL) {
  106     rcfile_err = strerror(errno);
  107     return RC_OPENFILE;
  108     } 
  109     
  110     default_site.perms = sitep_ignore;
  111     default_site.symlinks = sitesym_follow;
  112     default_site.protocol = siteproto_ftp;
  113     default_site.proto_string = ne_strdup("ftp");
  114 
  115     default_site.ftp_pasv_mode = true;
  116     default_site.ftp_use_cwd = false;
  117     
  118     last_site = this_site = NULL;
  119     rcfile_linenum = 0;
  120     rcfile_err = NULL;
  121 
  122     while ((ret==0) && (fgets(buf, sizeof(buf), fp) != NULL)) {
  123     rcfile_linenum++;
  124     /* Put the line without the LF into the error buffer */
  125     if (rcfile_err != NULL) free(rcfile_err);
  126     rcfile_err = ne_strdup(buf);
  127     ptr = strchr(rcfile_err, '\n');
  128     if (ptr != NULL) *ptr = '\0';
  129     state = 0;
  130     ptr = key;
  131     memset(key, 0, LINESIZE);
  132     memset(val, 0, LINESIZE);
  133     memset(val2, 0, LINESIZE);
  134     for (ch=buf; *ch!='\0'; ch++) {
  135         alpha = !isspace((unsigned)*ch); /* well, alphaish */
  136         hash = (*ch == '#');
  137         switch (state) {
  138         case 0: /* whitespace at beginning of line */
  139         if (hash) {
  140             state = 8;
  141         } else if (alpha) {
  142             *(ptr++) = *ch;
  143             state = 1;
  144         }
  145         break;
  146         case 1: /* key */
  147         if (hash) {
  148             state = 8;
  149         } else if (!alpha) {
  150             ptr = val;
  151             state = 2;
  152         } else {
  153             *(ptr++) = *ch;
  154         }
  155         break;
  156         case 2: /* whitespace after key */
  157         if (hash) {
  158             state = 8;
  159         } else if (*ch == '"') {
  160             state = 4; /* begin quoted value */
  161         } else if (alpha) {
  162             *(ptr++) = *ch;
  163             state = 3;
  164         } 
  165         break;
  166         case 3: /* unquoted value 1 */
  167         if (hash) {
  168             state = 8;
  169         } else if (!alpha) {
  170             ptr = val2;
  171             state = 5;
  172         } else {
  173             *(ptr++) = *ch;
  174         }
  175         break;
  176         case 4: /* quoted value 1 */
  177         if (*ch == '"') {
  178             ptr = val2;
  179             state = 5;
  180         } else if (*ch == '\\') {
  181             last_state = 4;
  182             state = 9;
  183         } else {
  184             *(ptr++) = *ch;
  185         }
  186         break;
  187         case 5: /* whitespace after value 1 */
  188         if (hash) {
  189             state = 8;
  190         } else if (*ch == '"') {
  191             state = 6; /* begin quoted value 2 */
  192         } else if (alpha) {
  193             *(ptr++) = *ch;
  194             state = 7; /* begin unquoted value 2 */
  195         } 
  196         break;
  197         case 6: /* quoted value 2 */
  198         if (*ch == '"') {
  199             state = 8;
  200         } else if (*ch == '\\') {
  201             last_state = 4;
  202             state = 9;
  203         } else {
  204             *(ptr++) = *ch;
  205         }
  206         break;
  207         case 7: /* unquoted value 2 */
  208         if (hash) {
  209             state = 8;
  210         } else if (!alpha) {
  211             state = 8;
  212         } else {
  213             *(ptr++) = *ch;
  214         }
  215         break;
  216         case 8: /* ignore till end of line */
  217         break;
  218         case 9: /* a literal (\-slashed) in a value */
  219         *(ptr++) = *ch;
  220         state = last_state;
  221         break;
  222         }
  223     }
  224     
  225     NE_DEBUG(DEBUG_RCFILE, "Key [%s] Value: [%s] Value2: [%s]\n", key, val, val2);
  226     
  227     if (strlen(key) == 0) {
  228         continue;
  229     }
  230     if (strlen(val) == 0) {
  231         /* A key with no value. */
  232         if (this_site == NULL) {
  233         if (strcmp(key, "default") == 0) {
  234             /* Setting up the default site */
  235             NE_DEBUG(DEBUG_RCFILE, "Default site entry:\n");
  236             this_site = &default_site;
  237         } else {
  238             /* Need to be in a site! */
  239             ret = RC_CORRUPT;
  240         }
  241         } else if (strcmp(key, "nodelete") == 0) {
  242         this_site->nodelete = true;
  243         } else if (strcmp(key, "checkmoved") == 0) {
  244         this_site->checkmoved = true;
  245         } else if (strcmp(key, "nooverwrite") == 0) {
  246         this_site->nooverwrite = true;
  247         } else if (strcmp(key, "lowercase") == 0) {
  248         this_site->lowercase = true;
  249         } else if (strcmp(key, "safe") == 0) {
  250         this_site->safemode = true;
  251         } else if (strcmp(key, "tempupload") == 0) {
  252         this_site->tempupload = true;
  253         } else {
  254         ret = RC_CORRUPT;
  255         }
  256     } else if (strlen(val2) == 0) {
  257         /* A key with a single value. */
  258         if (strcmp(key, "site") == 0) {
  259         /* Beginning of a new Site */
  260         if (this_site != &default_site)
  261             last_site = this_site;
  262         /* Allocate new item */
  263         this_site = ne_malloc(sizeof(struct site));
  264         /* Copy over the defaults */
  265         memcpy(this_site, &default_site, sizeof(struct site));
  266         /* Deep-copy the string lists */
  267         this_site->excludes = fnlist_deep_copy(default_site.excludes);
  268         this_site->ignores = fnlist_deep_copy(default_site.ignores);
  269         this_site->asciis = fnlist_deep_copy(default_site.asciis);
  270         this_site->prev = last_site;
  271         if (last_site != NULL) { /* next site */
  272             last_site->next = this_site;
  273         } else { /* First site */
  274             *sites = this_site;
  275         }       
  276         this_site->name = ne_strdup(val);
  277         this_site->files = NULL;
  278         this_site->proto_string = ne_strdup(default_site.proto_string);
  279         /* Now work out the info filename */
  280         this_site->infofile = ne_concat(copypath, val, NULL);
  281                 this_site->certfile = ne_concat(copypath, val, ".crt", NULL);
  282         } else if (this_site == NULL) {
  283         ret = RC_CORRUPT;
  284         } else if (strcmp(key, "username") == 0) {
  285         /* username */
  286         this_site->server.username = ne_strdup(val);
  287         } else if (strcmp(key, "server") == 0) {
  288         this_site->server.hostname = ne_strdup(val);
  289         } else if (strcmp(key, "port") == 0) {
  290         this_site->server.port = atoi(val);
  291         } else if (strcmp(key, "proxy-server") == 0) {
  292         this_site->proxy.hostname = ne_strdup(val);
  293         } else if (strcmp(key, "proxy-port") == 0) {
  294         this_site->proxy.port = atoi(val);
  295         } else if (strcmp(key, "proxy-password") == 0) {
  296         this_site->proxy.password = ne_strdup(val);
  297         } else if (strcmp(key, "proxy-username") == 0) {
  298         this_site->proxy.username = ne_strdup(val);
  299         } else if (strcmp(key, "password") == 0) {
  300         this_site->server.password = ne_strdup(val);
  301         } else if (strcmp(key, "url") == 0) {
  302             this_site->url = ne_strdup(val);
  303         } else if (strcmp(key, "remote") == 0) {
  304         /* Relative filenames must start with "~/" */
  305         if (val[0] == '~') {
  306             if (val[1] == '/') {
  307             this_site->remote_isrel = true;
  308             } else {
  309             ret = RC_CORRUPT;
  310             }
  311         } else {
  312             /* Dirname doesn't begin with "~/" */
  313             this_site->remote_isrel = false;
  314         }
  315         if (val[strlen(val)-1] != '/')
  316             strcat(val, "/");
  317         this_site->remote_root_user = ne_strdup(val);
  318         } else if (strcmp(key, "local") == 0) {
  319         /* Relative filenames must start with "~/" */
  320         if (val[0] == '~') {
  321             if (val[1] == '/') {
  322             this_site->local_isrel = true;
  323             } else {
  324             ret = RC_CORRUPT;
  325             }
  326         } else { 
  327             /* Dirname doesn't begin with a "~/" */
  328             this_site->local_isrel = false;
  329         }
  330         if (val[strlen(val)-1] != '/')
  331             strcat(val, "/");
  332         this_site->local_root_user = ne_strdup(val);
  333         } else if (strcmp(key, "permissions") == 0) {
  334         if (strcmp(val, "ignore") == 0) {
  335             this_site->perms = sitep_ignore;
  336                     this_site->dirperms = 0;
  337         } else if (strcmp(val, "exec") == 0) {
  338             this_site->perms = sitep_exec;
  339         } else if (strcmp(val, "all") == 0) {
  340             this_site->perms = sitep_all;
  341                 } else if (strcmp(val, "dir") == 0) {
  342                     this_site->dirperms = 1;
  343         } else {
  344             ret = RC_CORRUPT;
  345         }
  346         } else if (strcmp(key, "symlinks") == 0) {
  347         if (strcmp(val, "follow") == 0) {
  348             this_site->symlinks = sitesym_follow;
  349         } else if (strcmp(val, "maintain") == 0) {
  350             this_site->symlinks = sitesym_maintain;
  351         } else if (strcmp(val, "ignore") == 0) {
  352             this_site->symlinks = sitesym_ignore;
  353         } else {
  354             ret = RC_CORRUPT;
  355         }
  356         } else if (strcmp(key, "exclude") == 0) {
  357         struct fnlist *f = fnlist_prepend(&this_site->excludes);
  358         if (val[0] == '/') {
  359             f->pattern = ne_strdup(val+1);
  360             f->haspath = true;
  361         } else {
  362             f->pattern = ne_strdup(val);
  363             f->haspath = false;
  364         }
  365         } else if (strcmp(key, "ignore") == 0) {
  366         struct fnlist *f = fnlist_prepend(&this_site->ignores);
  367         if (val[0] == '/') {
  368             f->pattern = ne_strdup(val+1);
  369             f->haspath = true;
  370         } else {
  371             f->pattern = ne_strdup(val);
  372             f->haspath = false;
  373         }
  374         } else if (strcmp(key, "ascii") == 0) {
  375         struct fnlist *f = fnlist_prepend(&this_site->asciis);
  376         if (val[0] == '/') {
  377             f->pattern = ne_strdup(val+1);
  378             f->haspath = true;
  379         } else {
  380             f->pattern = ne_strdup(val);
  381             f->haspath = false;
  382         }
  383         } else if (strcmp(key, "protocol") == 0) {
  384         if (strcasecmp(val, "ftp") == 0) {
  385             this_site->protocol = siteproto_ftp;
  386         } else if (strcasecmp(val, "http") == 0 || 
  387                strcasecmp(val, "dav") == 0 ||
  388                strcasecmp(val, "webdav") == 0) {
  389             this_site->protocol = siteproto_dav;
  390         } else if (strcasecmp(val, "rsh") == 0) {
  391             this_site->protocol = siteproto_rsh;
  392         } else if (strcasecmp(val, "ssh") == 0) {
  393                     this_site->protocol = siteproto_rsh;
  394                     if (this_site->rsh_cmd == NULL) 
  395                         this_site->rsh_cmd = ne_strdup("ssh");
  396                     if (this_site->rcp_cmd == NULL) 
  397                         this_site->rcp_cmd = ne_strdup("scp");
  398         } else if (strcasecmp(val, "sftp") == 0) {
  399             this_site->protocol = siteproto_sftp;
  400                 } else {
  401             this_site->protocol = siteproto_unknown;
  402         }
  403         free(this_site->proto_string);
  404         this_site->proto_string = ne_strdup(val);
  405         } else if (strcmp(key, "ftp") == 0) {
  406         if (strcmp(val, "nopasv") == 0) {
  407             this_site->ftp_pasv_mode = false;
  408         } else if (strcmp(val, "showquit") == 0) {
  409             this_site->ftp_echo_quit = true;            
  410         } else if (strcmp(val, "usecwd") == 0) {
  411             this_site->ftp_use_cwd = true;          
  412         } else if (strcmp(val, "nousecwd") == 0) {
  413             this_site->ftp_use_cwd = false;         
  414         } else {
  415             ret = RC_CORRUPT;
  416         }
  417         } else if (strcmp(key, "http") == 0) {
  418         if (strcmp(val, "expect") == 0) {
  419             this_site->http_use_expect = true;
  420         } else if (strcmp(val, "limit") == 0) {
  421             this_site->http_limit = true;
  422         } else if (strcmp(val, "secure") == 0) {
  423             this_site->http_secure = true;
  424         } else if (strcmp(val, "tolerant") == 0) {
  425             this_site->http_tolerant = true;
  426         } else {            
  427             ret = RC_CORRUPT;
  428         }
  429             } else if (strcmp(key, "client-cert") == 0) {
  430                 this_site->client_cert = ne_strdup(val);
  431         } else if (strcmp(key, "rsh") == 0) {
  432         this_site->rsh_cmd = ne_strdup(val);
  433         } else if (strcmp(key, "rcp") == 0) {
  434         this_site->rcp_cmd = ne_strdup(val);
  435         } else if (strcmp(key, "state") == 0) {
  436         if (strcmp(val, "checksum") == 0) {
  437             this_site->state_method = state_checksum;
  438         } else if (strcmp(val, "timesize") == 0) {
  439             this_site->state_method = state_timesize;
  440         } else {
  441             ret = RC_CORRUPT;
  442         }
  443         } else if (strcmp(key, "checkmoved") == 0) {
  444         if (strcmp(val, "renames") == 0) {
  445             this_site->checkrenames = true;
  446             this_site->checkmoved = true;
  447         } else {
  448             ret = RC_CORRUPT;
  449         }
  450         } else if (strcmp(key, "charset") == 0) {
  451                 NE_DEBUG(DEBUG_RCFILE, "Ignored key %s\n", key);
  452             } else {
  453         /* Unknown key! */
  454         ret = RC_CORRUPT;
  455         }
  456     } else {
  457         {
  458         ret = RC_CORRUPT;
  459         }
  460     }
  461     }
  462 
  463     fclose(fp);
  464     return ret;
  465 }
  466 #undef LINESIZE
  467 
  468 const char *rc_get_netrc_password(const char *server, const char *username) {
  469     netrc_entry *found;
  470     found = search_netrc(netrc_list, server);
  471     if (found == NULL) {
  472     return NULL;
  473     }
  474     if (strcmp(found->account, username) == 0) {
  475     return found->password;
  476     } else {
  477     return NULL;
  478     }
  479 }
  480 
  481 /* Returns zero if site is properly defined, else non-zero */
  482 int rcfile_verify(struct site *any_site) 
  483 {
  484     struct stat localst;
  485     char *temp;
  486     int ret;
  487 
  488     /* Protocol-specific checks first, since if a new protocol driver is used,
  489      * any of the other checks may be irrelevant. */
  490     switch (any_site->protocol) {
  491     case siteproto_ftp:
  492 #ifdef USE_FTP
  493     any_site->driver = &ftp_driver;
  494     /* FTP checks */
  495     if (any_site->symlinks == sitesym_maintain) {
  496         return SITE_NOMAINTAIN;
  497     }
  498     break;
  499 #else /* !USE_FTP */
  500     return SITE_UNSUPPORTED;
  501 #endif /* USE_FTP */
  502     case siteproto_dav:
  503 #ifdef USE_DAV
  504     any_site->driver = &dav_driver;
  505     /* HTTP checks */
  506     if (any_site->remote_isrel) { 
  507         return SITE_NOREMOTEREL;
  508     }
  509     if (any_site->perms == sitep_all || any_site->dirperms) {
  510         return SITE_NOPERMS;
  511     }
  512     if (any_site->symlinks == sitesym_maintain) {
  513         return SITE_NOMAINTAIN;
  514     }
  515     break;
  516 #else /* !USE_DAV */
  517     return SITE_UNSUPPORTED;
  518 #endif /* USE_DAV */
  519     case siteproto_rsh:
  520 #ifdef USE_RSH
  521     any_site->driver = &rsh_driver;
  522     /* FIXME: rsh checks? */
  523     break;
  524 #else /* !USE_RSH */
  525     return SITE_UNSUPPORTED;
  526 #endif /* USE_RSH */
  527     case siteproto_sftp:
  528 #ifdef USE_SFTP
  529     any_site->driver = &sftp_driver;
  530     /* FIXME: sftp checks? */
  531     break;
  532 #else /* !USE_SFTP */
  533     return SITE_UNSUPPORTED;
  534 #endif /* USE_SFTP */
  535     case siteproto_unknown:
  536     return SITE_UNSUPPORTED;
  537     }
  538 
  539     /* Valid options check */
  540     if (any_site->checkrenames && (any_site->state_method != state_checksum)) {
  541     return SITE_NORENAMES;
  542     }
  543 
  544     /* Check they specified everything in the rcfile */
  545     if (any_site->server.hostname == NULL) {
  546     return SITE_NOSERVER;
  547     } 
  548 
  549     if (any_site->server.username != NULL && any_site->server.password == NULL) {
  550     if (havenetrc) {
  551         const char *pass;
  552         NE_DEBUG(DEBUG_RCFILE, "Checking netrc for password for %s@%s...",
  553            any_site->server.username, any_site->server.hostname);
  554         pass = rc_get_netrc_password(any_site->server.hostname, 
  555                       any_site->server.username);
  556         if (pass != NULL) {
  557         NE_DEBUG(DEBUG_RCFILE, "found!\n");
  558         any_site->server.password = (char *) pass;
  559         } else {
  560         NE_DEBUG(DEBUG_RCFILE, "none found.\n");
  561         }
  562     }
  563     }
  564     /* TODO: lookup proxy username/password in netrc too */
  565 
  566     if (any_site->remote_root_user == NULL) {
  567     return SITE_NOREMOTEDIR;
  568     } else if (any_site->local_root_user == NULL) {
  569     return SITE_NOLOCALDIR;
  570     }
  571     
  572     /* Need a home directory if we're using relative local root */
  573     if (home == NULL && any_site->local_root)
  574     return SITE_NOLOCALREL;
  575 
  576     /* Can't use safe mode and nooverwrite mode */
  577     if (any_site->safemode && any_site->nooverwrite)
  578     return SITE_NOSAFEOVER;
  579 
  580     if (any_site->safemode && any_site->tempupload)
  581     return SITE_NOSAFETEMPUP;
  582 
  583     if (any_site->remote_isrel) {
  584     any_site->remote_root = ne_strdup(any_site->remote_root_user + 2);
  585     } else {
  586     any_site->remote_root = ne_strdup(any_site->remote_root_user);
  587     }
  588     if (any_site->local_isrel) {
  589     /* We skip the first char ('~') of l_r_u */
  590     any_site->local_root = ne_concat(home, any_site->local_root_user + 1,
  591                      NULL);
  592     } else {
  593     any_site->local_root = any_site->local_root_user;
  594     }
  595 
  596     /* Now check the local directory actually exists.
  597      * To do this, stat `/the/local/root/.', which will fail if the
  598      * can't read the directory or if it's a file not a directory */
  599     temp = ne_concat(any_site->local_root, ".", NULL);
  600     ret = stat(temp, &localst);
  601     free(temp);
  602     if (ret != 0) {
  603     return SITE_ACCESSLOCALDIR;
  604     }
  605 
  606     if (any_site->client_cert && strncmp(any_site->client_cert, "~/", 2) == 0) {
  607         temp = ne_concat(home, any_site->client_cert + 1, NULL);
  608         ne_free(any_site->client_cert);
  609         any_site->client_cert = temp;
  610     }
  611 
  612     /* Assign default ports if they didn't bother to */
  613     if (any_site->server.port == 0) {
  614     NE_DEBUG(DEBUG_RCFILE, "Lookup up default port:\n");
  615     any_site->server.port = (*any_site->driver->get_server_port)(any_site);
  616     NE_DEBUG(DEBUG_RCFILE, "Using port: %d\n", any_site->server.port);
  617     }
  618 
  619     if (any_site->proxy.port == 0) {
  620     NE_DEBUG(DEBUG_RCFILE, "Lookup default proxy port...\n");
  621     any_site->proxy.port = (*any_site->driver->get_proxy_port)(any_site);
  622     NE_DEBUG(DEBUG_RCFILE, "Using port %d\n", any_site->proxy.port);
  623     }
  624 
  625     /* TODO: ditto for proxy server */
  626     return 0;
  627 }
  628 
  629 int init_netrc() {
  630     if (!havenetrc) return 0;
  631     netrc_list = parse_netrc(netrcfile);
  632     if (netrc_list == NULL) {
  633     /* Couldn't parse it */
  634     return 1;
  635     } else {
  636     /* Could parse it */
  637     return 0;
  638     }
  639 }
  640 
  641 /* Checks the perms of the rcfile and site storage directory. */
  642 int init_paths()
  643 {
  644     struct stat st;
  645     if (stat(rcfile, &st) < 0) {
  646     NE_DEBUG(DEBUG_RCFILE, "stat failed on %s: %s\n", 
  647            rcfile, strerror(errno));
  648     return RC_OPENFILE;
  649     }
  650 #if !defined (__EMX__) && !defined(__CYGWIN__)
  651     if (!S_ISREG(st.st_mode)) {
  652         return RC_OPENFILE;
  653     }
  654     if ((st.st_mode & ~(S_IFREG | S_IREAD | S_IWRITE)) > 0) {
  655     return RC_PERMS;
  656     }
  657 #endif
  658     if ((netrcfile == 0) || (stat(netrcfile, &st) < 0)) {
  659     havenetrc = false;
  660 #if !defined (__EMX__) && !defined(__CYGWIN__)
  661     } else if ((st.st_mode & ~(S_IFREG | S_IREAD | S_IWRITE)) > 0) {
  662     return RC_NETRCPERMS;
  663 #endif
  664     } else {
  665     havenetrc = true;
  666     }
  667     if (stat(copypath, &st) < 0) {
  668     NE_DEBUG(DEBUG_RCFILE, "stat failed on %s: %s\n", 
  669            copypath, strerror(errno));
  670     return RC_DIROPEN;
  671     }
  672 #if !defined (__EMX__) && !defined(__CYGWIN__)
  673     if (st.st_mode & (S_IRWXG | S_IRWXO)) {
  674     return RC_DIRPERMS;
  675     }
  676 #endif
  677     return 0;
  678 }
  679 
  680 int init_env() {
  681     /* Assign default filenames if they didn't give us any */
  682     home = getenv("HOME");
  683     if (home == NULL) {
  684     if ((rcfile == NULL) || (copypath == NULL)) {
  685         /* We need a $HOME or both rcfile and info dir path */
  686         return 1;
  687     } else {
  688         /* No $HOME, but we've got the rcfile and info dir path */
  689         return 0;
  690     }
  691     }
  692     if (rcfile == NULL) {
  693     rcfile = ne_concat(home, RCNAME, NULL);
  694     }
  695     if (copypath == NULL) {
  696     copypath = ne_concat(home, COPYNAME, NULL);
  697     }
  698     netrcfile = ne_concat(home, NETRCNAME, NULL);
  699     return 0;
  700 }
  701 
  702 /* rcfile_write() by Lee Mallabone, cleaned by JO.
  703  * Write the contents of list_of_sites to the specified 'filename'
  704  * in the standard sitecopy rc format.
  705  *
  706  * Any data already in 'filename' is over-written.
  707  */
  708 int rcfile_write (char *filename, struct site *list_of_sites) 
  709 {
  710     struct site *current;
  711     struct fnlist *item;
  712     FILE *fp;
  713     
  714     fp = fopen (filename, "w");
  715     if (fp == NULL) {
  716     printf ("There was a problem writing to the sitecopy configuration file.\n\nCheck permissions on %s.", filename);
  717     return RC_OPENFILE;
  718    }
  719 
  720     /* Set rcfile permissions properly */
  721 #if !defined (__EMX__) && !defined(__CYGWIN__)
  722     if (fchmod (fileno(fp), 00600) == -1) {
  723     return RC_PERMS;
  724     }
  725 #endif
  726     
  727     for (current=list_of_sites; current!=NULL; current=current->next) {
  728     /* Okay so this maybe isn't the most intuitive thing to look at.
  729      * With any luck though, the rcfile's it produces will be. :) */
  730     if (fprintf (fp, "site %s\n", current->name) == -1) {
  731         return RC_CORRUPT;
  732     }
  733     if (fprintf (fp, "  server %s\n", current->server.hostname) == -1) {
  734         return RC_CORRUPT;
  735     }
  736        
  737     if ((current->server.username != NULL) && 
  738         (strlen(current->server.username) > 0))
  739         if (fprintf(fp, "  username %s\n", 
  740             current->server.username) == -1) {
  741         return RC_CORRUPT;
  742         }
  743     
  744     if ((current->server.password != NULL) 
  745         && (strlen(current->server.password) > 0))
  746         if (fprintf(fp, "  password %s\n", 
  747             current->server.password) == -1) {
  748         return RC_CORRUPT;
  749         }
  750     
  751         if (fprintf(fp, "  remote %s\n  local %s\n",
  752             current->remote_root_user,
  753             current->local_root_user) == -1) {
  754         return RC_CORRUPT;
  755     }
  756     
  757     if (fprintf (fp, "  protocol %s\n", current->proto_string) == -1) {
  758         return RC_CORRUPT;
  759     }
  760     
  761     /* Makes sense to have protocol (ish) options after we specify
  762      * the protocol.  Warning, if the http declarations in site_t
  763      * are ever surrounded by an ifdef USE_DAV, then this will need
  764      * to be changed.  */
  765     
  766     /* Write out the boolean fields */
  767     
  768 #define RCWRITEBOOL(field,name) \
  769       if ((field) && (fprintf(fp, "  %s\n", name) == -1)) return RC_CORRUPT;
  770     
  771     RCWRITEBOOL(current->nodelete, "nodelete");
  772     if (current->checkmoved) {
  773         if (current->checkrenames) {
  774         if (fprintf(fp, "  checkmoved renames\n") == -1)
  775             return RC_CORRUPT;
  776         } else {
  777         if (fprintf(fp, "  checkmoved\n") == -1)
  778             return RC_CORRUPT;
  779         }
  780     }
  781     
  782     RCWRITEBOOL(current->nooverwrite, "nooverwrite");
  783     RCWRITEBOOL(current->safemode, "safe");
  784     RCWRITEBOOL(current->lowercase, "lowercase");
  785     RCWRITEBOOL(current->tempupload, "tempupload");
  786     
  787     RCWRITEBOOL(!current->ftp_pasv_mode, "ftp nopasv");
  788     RCWRITEBOOL(current->ftp_echo_quit, "ftp showquit");
  789     RCWRITEBOOL(current->ftp_use_cwd, "ftp usecwd");
  790     RCWRITEBOOL(current->http_limit, "http limit");
  791     RCWRITEBOOL(current->http_use_expect, "http expect");
  792     
  793 #undef RCWRITEBOOL
  794     
  795     if (current->server.port > 0) { /* Sanity check */
  796         if (fprintf (fp, "  port %d\n", current->server.port) == -1) {
  797         return RC_CORRUPT;
  798         }
  799     }
  800     
  801     /* Add the site's URL if one has been supplied. */
  802     if (current->url) {
  803         if (fprintf (fp, "  url %s\n", current->url) == -1) {
  804         return RC_CORRUPT;
  805         }
  806     }
  807       
  808     /* State method */
  809     switch (current->state_method) {
  810     case (state_timesize):
  811         if (fprintf (fp, "  state timesize\n") == -1) {
  812         return RC_CORRUPT;
  813         }   
  814         break;
  815     case (state_checksum):
  816         if (fprintf (fp, "  state checksum\n") == -1) {
  817         return RC_CORRUPT;
  818         }
  819         break;
  820     }
  821     
  822     /* Permissions now */
  823     switch (current->perms) {
  824     case (sitep_ignore): 
  825         if (fprintf (fp, "  permissions ignore\n") == -1) {
  826         return RC_CORRUPT;
  827         }
  828         break;
  829     case (sitep_exec):
  830         if (fprintf (fp, "  permissions exec\n") == -1) {
  831         return RC_CORRUPT;
  832         }
  833         break;
  834     case (sitep_all):
  835         if (fprintf (fp, "  permissions all\n") == -1) {
  836         return RC_CORRUPT;
  837         }
  838         break;
  839     }
  840     
  841         if (current->dirperms) {
  842             if (fprintf(fp, "  permissions dir\n") == -1) {
  843                 return RC_CORRUPT;
  844             }
  845         }
  846 
  847     /* Sym link mode */
  848     switch (current->symlinks) {
  849     case (sitesym_ignore): 
  850         if (fprintf (fp, "  symlinks ignore\n") == -1) {
  851         return RC_CORRUPT;
  852         }
  853         break;
  854     case (sitesym_follow):
  855         if (fprintf (fp, "  symlinks follow\n") == -1) {
  856         return RC_CORRUPT;
  857         }
  858         break;
  859     case (sitesym_maintain):
  860         if (fprintf (fp, "  symlinks maintain\n") == -1) {
  861         return RC_CORRUPT;
  862         }
  863         break;
  864     }
  865     
  866 #define DUMP_FNLIST(list, name)                       \
  867 do {\
  868 for (item = list; item != NULL; item = item->next)            \
  869     if (fprintf(fp, "  " name " \"%s%s\"\n", item->haspath?"/":"",    \
  870     item->pattern) == -1)                         \
  871     return RC_CORRUPT;                       \
  872 } while(0)
  873     
  874     DUMP_FNLIST(current->excludes, "exclude");
  875     DUMP_FNLIST(current->asciis, "ascii");
  876     DUMP_FNLIST(current->ignores, "ignore");
  877     
  878 #undef DUMP_FNLIST
  879     
  880     }
  881     if (fclose (fp) != 0)
  882     return RC_CORRUPT;
  883 
  884     return 0;
  885 }