home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / AP / TERMNET / NCFTP183 / CMDS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-20  |  45.2 KB  |  2,218 lines

  1. /* cmds.c */
  2.  
  3. /*  $RCSfile: cmds.c,v $
  4.  *  $Revision: 14020.14 $
  5.  *  $Date: 93/07/09 11:31:53 $
  6.  */
  7.  
  8. #include "sys.h"
  9.  
  10. #include <sys/wait.h>
  11.  
  12. #include <sys/stat.h>
  13. #include <arpa/ftp.h>
  14. #include <setjmp.h>
  15. #include <signal.h>
  16. #include <errno.h>
  17. #include <netdb.h>
  18. #include <netinet/in.h>
  19. #include <arpa/inet.h>
  20. #include <ctype.h>
  21.  
  22. #ifdef SYSLOG
  23. #    include <syslog.h>
  24. #endif
  25.  
  26. #include "util.h"
  27. #include "cmds.h"
  28. #include "main.h"
  29. #include "ftp.h"
  30. #include "ftprc.h"
  31. #include "getpass.h"
  32. #include "glob.h"
  33. #include "open.h"
  34. #include "set.h"
  35. #include "defaults.h"
  36. #include "copyright.h"
  37.  
  38. /* cmds.c globals */
  39. #ifdef PASSIVEMODE
  40. int                    passivemode = 1;
  41. #endif
  42. int                    curtype;            /* file transfer type */
  43. char                *typeabbrs = "abiet";
  44. str32                curtypename;        /* name of file transfer type */
  45. int                    verbose;             /* verbosity level of output */
  46. int                    mprompt;            /* interactively prompt on m* cmds */
  47. int                    debug;                /* debugging level */
  48. int                    options;            /* used during socket creation */
  49. int                    macnum;                /* number of defined macros */
  50. int                    paging = 0;
  51. int                    creating = 0;
  52. struct macel        macros[MAXMACROS];
  53. char                *macbuf;            /* holds ALL macros */
  54. int                    doingInitMacro = 0;    /* TRUE if executing "init" macro. */
  55. jmp_buf                jabort;
  56. char                *mname;                /* name of current m* command */
  57. int                    activemcmd;            /* flag: if != 0, then active multi command */
  58. int                    warnNoLSFlagsWithWildcards = 0;
  59.                                         /* Tells whether the user has been
  60.                                          * warned about not being able to use
  61.                                          * flags with ls when using wildcards.
  62.                                          */
  63. longstring            cwd;                /* current remote directory */
  64. longstring            lcwd;                /* current local directory */
  65. Hostname            lasthostname;        /* name of last host w/ lookup(). */
  66. int                    logged_in = 0;        /* TRUE if connected and user/pw OK. */
  67. int                    is_ls = 0;            /* are we doing an ls?  if so, then
  68.                                            read input into a line buffer
  69.                                            for re-use. */
  70. extern int                    buffer_only;
  71. struct lslist               *lshead = NULL;    /* hold last output from host */
  72. struct lslist               *lstail = NULL;
  73.  
  74. /* cmds.c externs */
  75. extern char                    *globerr, *home, *reply_string;
  76. extern int                    margc, connected, ansi_escapes;
  77. extern int                    code, connected;
  78. extern int                    toatty, fromatty;
  79. extern int                    data, progress_meter, remote_is_unix;
  80. extern int                    parsing_rc, keep_recent;
  81. extern char                    *altarg, *line, *margv[];
  82. extern char                    *globchars;
  83. extern Hostname                hostname;
  84. extern RemoteSiteInfo        gRmtInfo;
  85. extern string                progname, pager, anon_password;
  86. extern string                prompt, version, indataline;
  87. extern longstring            logfname;
  88. extern long                    logsize;
  89. extern size_t                xferbufsize;
  90. extern struct servent        serv;
  91. extern struct cmd            cmdtab[];
  92. extern struct userinfo        uinfo;
  93. extern FILE                    *cin, *cout, *logf;
  94. extern int                    Optind;
  95. extern char                    *Optarg;
  96. extern int                    Optind;
  97. extern char                    *Optarg;
  98.  
  99. #ifdef STRICT_PROTOS
  100. extern int gethostname(char *, int), getdomainname(char *, int);
  101. #endif
  102.  
  103.  
  104. struct types types[] = {
  105.     { "ascii",  "A",    TYPE_A, 0 },
  106.     { "binary", "I",    TYPE_I, 0 },
  107.     { "image",  "I",    TYPE_I, 0 },
  108.     { "ebcdic", "E",    TYPE_E, 0 },
  109.     { "tenex",  "L",    TYPE_L, "8" },
  110.     { 0 }
  111. };
  112.  
  113.  
  114.  
  115. long GetDateSizeFromLSLine(char *fName, unsigned long *mod_time)
  116. {
  117.     char *cp, *np;
  118.     string lsline;
  119.     long size = SIZE_UNKNOWN;
  120.     int n, v;
  121.     struct lslist *savedh, *savedt;
  122.     static int depth = 0;
  123.  
  124.     depth++;    /* Try to prevent infinite recursion. */
  125.     *mod_time = MDTM_UNKNOWN;
  126.     v = verbose; verbose = V_QUIET;
  127.     is_ls = 1;
  128.     buffer_only = 1;
  129.     savedh = lshead;
  130.     savedt = lstail;
  131.     lshead = NULL;
  132.     (void) recvrequest("LIST", "-", fName, "w");
  133.     is_ls = 0;
  134.     buffer_only = 0;
  135.     verbose = v;
  136.     if (lshead == NULL) {
  137.         PurgeLineBuffer();
  138.         lshead = savedh;
  139.         lstail = savedt;
  140.         goto aa;
  141.     }
  142.     (void) Strncpy(lsline, lshead->string);
  143.     PurgeLineBuffer();
  144.     lshead = savedh;
  145.     lstail = savedt;
  146.  
  147.     if (code >= 400 && code < 500)
  148.         goto aa;
  149.  
  150.     /* See if this line looks like a unix-style ls line. 
  151.      * If so, we can grab the date and size from it.
  152.      */    
  153.     if (strpbrk(lsline, "-dlsbcp") == lsline) {
  154.         /* See if it looks like a typical '-rwxrwxrwx' line. */
  155.         cp = lsline + 1;
  156.         if (*cp != 'r' && *cp != '-')
  157.             goto aa;
  158.         ++cp;
  159.         if (*cp != 'w' && *cp != '-')
  160.             goto aa;
  161.         cp += 2;
  162.         if (*cp != 'r' && *cp != '-')
  163.             goto aa;
  164.  
  165.          /* skip mode, links, owner (and possibly group) */
  166.          for (n = 0; n < 4; n++) {
  167.              np = cp;
  168.              while (*cp != '\0' && !isspace(*cp))
  169.                  cp++;
  170.              while (*cp != '\0' &&  isspace(*cp))
  171.                  cp++;
  172.          }
  173.          if (!isdigit(*cp))
  174.              cp = np;    /* back up (no group) */
  175.          (void) sscanf(cp, "%ld%n", &size, &n);
  176.  
  177.          *mod_time = UnLSDate(cp + n + 1);
  178.  
  179.         if (size < 100) {
  180.             /* May be the size of a link to the file, instead of the file. */
  181.             if ((cp = strstr(lsline, " -> ")) != NULL) {
  182.                 /* Yes, it was a link. */
  183.                 size = (depth>4) ? SIZE_UNKNOWN :
  184.                     GetDateAndSize(cp + 4, mod_time);
  185.                 /* Try the file. */
  186.             }
  187.         }
  188.     }    
  189. aa:
  190.     --depth;
  191.     return (size);
  192. }    /* GetDateSizeFromLSLine */
  193.  
  194.  
  195.  
  196.  
  197. /* The caller wanted to know the modification date and size of the remote
  198.  * file given to us.  We try to get this information by using the SIZE
  199.  * and MDTM ftp commands, and if that didn't work we try sending the site
  200.  * a "ls -l <fName>" and try to get that information from the line it
  201.  * sends us back.  It is possible that we won't be able to determine
  202.  * either of these, though.
  203.  */
  204. long GetDateAndSize(char *fName, unsigned long *mod_time)
  205. {
  206.     unsigned long mdtm, ls_mdtm;
  207.     long size, ls_size;
  208.     int have_mdtm, have_size;
  209.     string cmd;
  210.  
  211.     size = SIZE_UNKNOWN;
  212.     mdtm = MDTM_UNKNOWN;
  213.     if (fName != NULL) {
  214.         have_mdtm = have_size = 0;
  215.         if (gRmtInfo.hasSIZE) {
  216.             (void) Strncpy(cmd, "SIZE ");
  217.             (void) Strncat(cmd, fName);
  218.             if (quiet_command(cmd) == 2) {
  219.                 if (sscanf(reply_string, "%*d %ld", &size) == 1)
  220.                     have_size = 1;
  221.             } else if (strncmp(reply_string, "550", (size_t)3) != 0)
  222.                 gRmtInfo.hasSIZE = 0;
  223.         }
  224.  
  225. #ifndef NO_MKTIME
  226.         /* We'll need mktime() to un-mangle this. */
  227.         if (gRmtInfo.hasMDTM) {
  228.             (void) Strncpy(cmd, "MDTM ");
  229.             (void) Strncat(cmd, fName);
  230.             if (quiet_command(cmd) == 2) {
  231.                 /* Result should look like "213 19930602204445\n" */
  232.                 mdtm = UnMDTMDate(reply_string);
  233.                 if (mdtm != MDTM_UNKNOWN)
  234.                     have_mdtm = 1;
  235.             } else if (strncmp(reply_string, "550", (size_t)3) != 0)
  236.                 gRmtInfo.hasMDTM = 0;
  237.         }
  238. #endif /* NO_MKTIME */
  239.  
  240.         if (!have_mdtm || !have_size)
  241.             ls_size = GetDateSizeFromLSLine(fName, &ls_mdtm);
  242.  
  243.         /* Try to use the information from the real SIZE/MDTM commands if
  244.          * we could, since some maverick ftp server may be using a non-standard
  245.          * ls command, and we could parse it wrong.
  246.          */
  247.         
  248.         if (!have_mdtm)
  249.             mdtm = ls_mdtm;
  250.         if (!have_size)
  251.             size = ls_size;
  252.  
  253.         dbprintf("Used SIZE: %s;  Used MDTM: %s\n",
  254.             have_size ? "yes" : "no",
  255.             have_mdtm ? "yes" : "no"
  256.         );
  257.  
  258.         if (debug > 0) {
  259.             if (size != SIZE_UNKNOWN)
  260.                 dbprintf("Size: %ld\n", size);
  261.             if (mdtm != MDTM_UNKNOWN)
  262.                 dbprintf("Mdtm: %s\n", ctime((time_t *) &mdtm));
  263.         }
  264.     }
  265.     *mod_time = mdtm;
  266.     return size;
  267. }    /* GetDateAndSize */
  268.  
  269.  
  270.  
  271.  
  272.  
  273. int _settype(char *typename)
  274. {
  275.     register struct types    *p;
  276.     int                        comret, c;
  277.     string                    cmd;
  278.     char                    *cp;
  279.  
  280.     c = isupper(*typename) ? tolower(*typename) : (*typename);
  281.     if ((cp = index(typeabbrs, c)) != NULL)
  282.         p = &types[(int) (cp - typeabbrs)];
  283.     else {
  284.         (void) printf("%s: unknown type\n", typename);
  285.         return USAGE;
  286.     }
  287.     if (c == 't')
  288.         (void) strcpy(cmd, "TYPE L 8");
  289.     else    
  290.         (void) sprintf(cmd, "TYPE %s", p->t_mode);
  291.     comret = command(cmd);
  292.     if (comret == COMPLETE) {
  293.         (void) Strncpy(curtypename, p->t_name);
  294.         curtype = p->t_type;
  295.     }
  296.     return NOERR;
  297. }    /* _settype */
  298.  
  299.  
  300.  
  301.  
  302. int SetTypeByNumber(int i)
  303. {
  304.     char tstr[4], *tp = tstr, c;
  305.  
  306.     tp[1] = c = 0;
  307.     switch (i) {
  308.         case TYPE_A: c = 'a'; break;
  309.         case TYPE_I: c = 'b'; break;
  310.         case TYPE_E: c = 'e'; break;
  311.         case TYPE_L: c = 't';
  312.     }
  313.     *tp = c;
  314.     return (c == 0 ? -1 : _settype(tp));
  315. }    /* SetTypeByNumber */
  316.  
  317.  
  318.  
  319.  
  320. /*
  321.  * Set transfer type.
  322.  */
  323. int settype(int argc, char **argv)
  324. {
  325.     int result = NOERR;
  326.  
  327.     if (argc > 2) {
  328.         result = USAGE;
  329.     } else {
  330.         if (argc < 2)
  331.             goto xx;
  332.         result = _settype(argv[1]);
  333.         if (IS_VVERBOSE)
  334. xx:            (void) printf("Using %s mode to transfer files.\n", curtypename);
  335.     }
  336.     return result;
  337. }    /* settype */
  338.  
  339.  
  340.  
  341.  
  342. /*ARGSUSED*/
  343. int setbinary(int argc, char **argv) {    return (_settype("binary")); }
  344. /*ARGSUSED*/
  345. int setascii(int argc, char **argv) {    return (_settype("ascii")); }
  346.  
  347.  
  348.  
  349. /*
  350.  * Send a single file.
  351.  */
  352. int put(int argc, char **argv)
  353. {
  354.     char *cmd;
  355.  
  356.     if (argc == 2) {
  357.         argc++;
  358.         argv[2] = argv[1];
  359.     }
  360.     if (argc < 2)
  361.         argv = re_makeargv("(local-file) ", &argc);
  362.     if (argc < 2) {
  363. usage:
  364.         return USAGE;
  365.     }
  366.     if (argc < 3)
  367.         argv = re_makeargv("(remote-file) ", &argc);
  368.     if (argc < 3) 
  369.         goto usage;
  370.     cmd = (argv[0][0] == 'a') ? "APPE" : "STOR";
  371.     (void) sendrequest(cmd, argv[1], argv[2]);
  372.     return NOERR;
  373. }    /* put */
  374.  
  375.  
  376.  
  377.  
  378. /*
  379.  * Send multiple files.
  380.  */
  381. int mput(int argc, char **argv)
  382. {
  383.     register int i;
  384.     Sig_t oldintr;
  385.     char *tp;
  386.  
  387.     if (argc < 2)
  388.         argv = re_makeargv("(local-files) ", &argc);
  389.     if (argc < 2) {
  390.         return USAGE;
  391.     }
  392.     mname = argv[0];
  393.     activemcmd = 1;
  394.     oldintr = Signal(SIGINT, mabort);
  395.     (void) setjmp(jabort);
  396.     for (i = 1; i < argc; i++) {
  397.         register char **cpp, **gargs;
  398.         char *icopy;
  399.         
  400.         /* Make a copy of the argument, because glob() will just copy
  401.          * the pointer you give it to the glob-arg vector, and blkfree()
  402.          * will want to free each element of the glob-arg vector
  403.          * later.
  404.          */
  405.         if ((icopy = NewString(argv[i])) == NULL)
  406.             break;
  407.         gargs = glob(icopy);
  408.         if (globerr != NULL) {
  409.             (void) printf("%s\n", globerr);
  410.             if (gargs) {
  411.                 blkfree(gargs);
  412.                 Free(gargs);
  413.             }
  414.             continue;
  415.         }
  416.         for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
  417.             if (activemcmd && confirm(argv[0], *cpp)) {
  418.                 tp = *cpp;
  419.                 (void) sendrequest("STOR", *cpp, tp);
  420.                 if (!activemcmd && fromatty) {
  421.                     if (confirm("Continue with","mput")) {
  422.                         activemcmd++;
  423.                     }
  424.                 }
  425.             }
  426.         }
  427.         if (gargs != NULL) {
  428.             blkfree(gargs);
  429.             Free(gargs);
  430.         }
  431.     }
  432.     (void) Signal(SIGINT, oldintr);
  433.     activemcmd = 0;
  434.     return NOERR;
  435. }    /* mput */
  436.  
  437.  
  438.  
  439.  
  440. int rem_glob_one(char *pattern)
  441. {
  442.     int            oldverbose, result = 0;
  443.     char        *cp;
  444.     string        str, tname;
  445.     FILE        *ftemp;
  446.  
  447.     /* Check for wildcard characters. */
  448.     if (*pattern == '|' || strpbrk(pattern, globchars) == NULL)
  449.         return 0;
  450.  
  451.     (void) tmp_name(tname);
  452.     oldverbose = verbose;
  453.     verbose = V_QUIET;
  454.     (void) recvrequest ("NLST", tname, pattern, "w");
  455.     verbose = oldverbose;
  456.     ftemp = fopen(tname, "r");
  457.     (void) chmod(tname, 0600);
  458.     if (ftemp == NULL || FGets(str, ftemp) == NULL) {
  459.         if (NOT_VQUIET)
  460.             (void) printf("%s: no match.\n", pattern);
  461.         result = -1;
  462.         goto done;
  463.     }
  464.     if ((cp = index(str, '\n')) != NULL)
  465.         *cp = '\0';
  466.     (void) strcpy(pattern, str);
  467.     cp = FGets(str, ftemp);
  468.     /* It is an error if the pattern matched more than one file. */
  469.     if (cp != NULL) {
  470.         if (NOT_VQUIET)
  471.             (void) printf("?Ambiguous remote file name.\n");
  472.         result = -2;
  473.     }
  474. done:
  475.     if (ftemp != NULL)
  476.         (void) fclose(ftemp);
  477.     (void) unlink(tname);
  478.     return (result);
  479. }    /* rem_glob_one */
  480.  
  481.  
  482.  
  483.  
  484. /*
  485.  * Receive (and maybe page) one file.
  486.  */
  487. int get(int argc, char **argv)
  488. {
  489.     string local_file;
  490.     char remote_file[256];
  491.     char *cp;
  492.     int oldtype = curtype, try_zcat;
  493.     size_t len;
  494.  
  495.     /* paging mode is set if the command name is 'page' or 'more.' */
  496.     paging = (**argv != 'g');
  497.  
  498.     if (argc < 2)
  499.         argv = re_makeargv("(remote-file) ", &argc);
  500.  
  501.     if (argc < 2) {
  502.         return USAGE;
  503.     }
  504.     cp = Strncpy(remote_file, argv[1]);
  505.     argv[1] = cp;
  506.     if (rem_glob_one(argv[1]) < 0)
  507.         return CMDERR;
  508.  
  509.     if (paging) {
  510.         try_zcat = 0;
  511.         len = strlen(remote_file);
  512.  
  513.         if (len > (size_t) 2) {
  514.              if (remote_file[len-2] == '.') {
  515.                 /* Check for .Z files. */
  516.                 if (remote_file[len-1] == 'Z')
  517.                     try_zcat = 1;
  518. #ifdef GZCAT
  519.                 /* Check for .z (gzip) files. */
  520.                 if (remote_file[len-1] == 'z')
  521.                     try_zcat = 1;
  522. #endif    /* GZCAT */
  523.             }
  524.         }
  525.  
  526. #ifdef GZCAT
  527.         if (len > (size_t) 3) {
  528.             /* Check for ".gz" (gzip) files. */
  529.             if (strcmp(remote_file + len - 3, ".gz") == 0)
  530.                 try_zcat = 1;
  531.         }
  532. #endif    /* GZCAT */
  533.  
  534.         /* Run compressed remote files through zcat, then the pager.
  535.          * If GZCAT was defined, we also try paging gzipped files.
  536.          * Note that ZCAT is defined to be GZCAT if you defined
  537.          * GZCAT.
  538.          */
  539.         
  540.          if (try_zcat) {
  541.             (void) _settype("b");
  542.             (void) sprintf(local_file, "|%s ", ZCAT);
  543.             argv[2] = Strncat(local_file, pager);
  544.         } else {
  545.             /* Try to use text mode for paging, so newlines get converted. */
  546.             (void) _settype("a");
  547.             argv[2] = pager;
  548.         }
  549.     } else {
  550.         /* normal get */
  551.         if (argc == 2) {
  552.             (void) Strncpy(local_file, argv[1]);
  553.             argv[2] = local_file;
  554.         } else {
  555.             if (argc < 3)
  556.                 argv = re_makeargv("(local-file) ", &argc);
  557.             if (argc < 3) 
  558.                 return USAGE;
  559.             (void) LocalDotPath(argv[2]);
  560.         }
  561.     }
  562.     (void) recvrequest("RETR", argv[2], argv[1], "w");
  563.     if (paging) {
  564.         (void) SetTypeByNumber(oldtype);    /* Restore it to what it was. */
  565.         paging = 0;
  566.     }
  567.     return NOERR;
  568. }    /* get */
  569.  
  570.  
  571.  
  572. /*ARGSUSED*/
  573. void mabort SIG_PARAMS
  574. {
  575.     (void) printf("\n");
  576.     (void) fflush(stdout);
  577.     if (activemcmd && fromatty) {
  578.         if (confirm("Continue with", mname)) {
  579.             longjmp(jabort,0);
  580.         }
  581.     }
  582.     activemcmd = 0;
  583.     longjmp(jabort,0);
  584. }    /* mabort */
  585.  
  586.  
  587.  
  588.  
  589. /*
  590.  * Get multiple files.
  591.  */
  592. int mget(int argc, char **argv)
  593. {
  594.     char *cp;
  595.     longstring local;
  596.     Sig_t oldintr;
  597.  
  598.     if (argc < 2)
  599.         argv = re_makeargv("(remote-files) ", &argc);
  600.     if (argc < 2) {
  601.         return USAGE;
  602.     }
  603.     mname = argv[0];
  604.     activemcmd = 1;
  605.     oldintr = Signal(SIGINT, mabort);
  606.     (void) setjmp(jabort);
  607.     while ((cp = remglob(argv)) != NULL) {
  608.         if (*cp == '\0') {
  609.             activemcmd = 0;
  610.             continue;
  611.         }
  612.         if (activemcmd && confirm(argv[0], cp)) {
  613.             (void) Strncpy(local, cp);
  614.             (void) recvrequest("RETR", local, cp, "w");
  615.             if (!activemcmd && fromatty) {
  616.                 if (confirm("Continue with","mget")) {
  617.                     activemcmd++;
  618.                 }
  619.             }
  620.         }
  621.     }
  622.     (void) Signal(SIGINT,oldintr);
  623.     activemcmd = 0;
  624.     return NOERR;
  625. }    /* mget */
  626.  
  627.  
  628.  
  629.  
  630. char *remglob(char *argv[])
  631. {
  632.     static FILE            *ftemp = NULL;
  633.     int                    oldverbose, i;
  634.     char                *cp, *mode;
  635.     static string        tmpname, str;
  636.     int                    result, errs;
  637.  
  638.     if (!activemcmd) {
  639. xx:
  640.         if (ftemp) {
  641.             (void) fclose(ftemp);
  642.             ftemp = NULL;
  643.             (void) unlink(tmpname);
  644.         }
  645.         return(NULL);
  646.     }
  647.     if (ftemp == NULL) {
  648.         (void) tmp_name(tmpname);
  649.         oldverbose = verbose, verbose = V_QUIET;
  650.         errs = 0;
  651.         for (mode = "w", i=1; argv[i] != NULL; i++, mode = "a") {
  652.             result = recvrequest ("NLST", tmpname, argv[i], mode);
  653.             if (i == 1)
  654.                 (void) chmod(tmpname, 0600);
  655.             if (result < 0) {
  656.                 fprintf(stderr, "%s: %s.\n",
  657.                     argv[i],
  658.                     (strpbrk(argv[i], globchars) != NULL) ? "No match" :
  659.                         "No such file"
  660.                 );
  661.                 errs++;
  662.             }
  663.         }
  664.               verbose = oldverbose;
  665.         if (errs == (i - 1)) {
  666.             /* Every pattern was in error, so we can't try anything. */
  667.             (void) unlink(tmpname);        /* Shouldn't be there anyway. */
  668.             return NULL;
  669.         }
  670.         ftemp = fopen(tmpname, "r");
  671.         if (ftemp == NULL) {
  672.             PERROR("remglob", tmpname);
  673.             return (NULL);
  674.         }
  675.     }
  676.     if (FGets(str, ftemp) == NULL) 
  677.         goto xx;
  678.     if ((cp = index(str, '\n')) != NULL)
  679.         *cp = '\0';
  680.     return (str);
  681. }    /* remglob */
  682.  
  683.  
  684. /*
  685.  * Turn on/off printing of server echo's, messages, and statistics.
  686.  */
  687. int setverbose(int argc, char **argv)
  688. {
  689.     if (argc > 1)
  690.         set_verbose(argv[1], 0);
  691.     else set_verbose(argv[1], -1);
  692.     return NOERR;
  693. }    /* setverbose */
  694.  
  695.  
  696.  
  697. /*
  698.  * Toggle interactive prompting
  699.  * during mget, mput, and mdelete.
  700.  */
  701. int setprompt(int argc, char **argv)
  702. {
  703.     if (argc > 1)
  704.         mprompt = StrToBool(argv[1]);
  705.     else mprompt = !mprompt;
  706.     if (IS_VVERBOSE)
  707.         (void) printf("Interactive prompting for m* commmands %s.\n", onoff(mprompt));
  708.     return NOERR;
  709. }    /* setprompt */
  710.  
  711.  
  712.  
  713.  
  714. void fix_options(void)
  715. {
  716.     if (debug)
  717.         options |= SO_DEBUG;
  718.     else
  719.     options &= ~SO_DEBUG;
  720. }   /* fix_options */
  721.  
  722.  
  723. /*
  724.  * Set debugging mode on/off and/or
  725.  * set level of debugging.
  726.  */
  727. int setdebug(int argc, char **argv)
  728. {
  729.     int val;
  730.  
  731.     if (argc > 1) {
  732.         val = StrToBool(argv[1]);
  733.         if (val < 0) {
  734.             (void) printf("%s: bad debugging value.\n", argv[1]);
  735.             return USAGE;
  736.         }
  737.     } else
  738.         val = !debug;
  739.     debug = val;
  740.     fix_options();
  741.     if (IS_VVERBOSE)
  742.         (void) printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
  743.     return NOERR;
  744. }    /* debug */
  745.  
  746.  
  747.  
  748. /*
  749.  * Set current working directory
  750.  * on remote machine.
  751.  */
  752. int cd(int argc, char **argv)
  753. {
  754.     if (argc < 2)
  755.         argv = re_makeargv("(remote-directory) ", &argc);
  756.     if (argc < 2) {
  757.         return USAGE;
  758.     }
  759.     (void) _cd(argv[1]);
  760.     return NOERR;
  761. }    /* cd */
  762.  
  763.  
  764.  
  765.  
  766. int implicit_cd(char *dir)
  767. {
  768.     int i, j = 0;
  769.     
  770.     if (connected) {
  771.         i = verbose;
  772.         /* Special verbosity level that ignores errors and prints other stuff,
  773.          * so you will get just the unknown command message and not an error
  774.          * message from cd.
  775.          */
  776.         verbose = V_IMPLICITCD;
  777.         j = _cd(dir);
  778.         verbose = i;
  779.     }
  780.     return j;
  781. }    /* implicit_cd */
  782.  
  783.  
  784.  
  785.  
  786. int _cd(char *dir)
  787. {
  788.     register char *cp;
  789.     int result = 0;
  790.     string str;
  791.  
  792.     if (dir == NULL)
  793.         goto getrwd;
  794.     /* Won't work because glob really is a ls, so 'cd pu*' will match
  795.      * pub/README, pub/file2, etc.
  796.      *    if (result = rem_glob_one(dir) < 0)
  797.      *    return result;
  798.      */
  799.     if (strncmp(dir, "CDUP", (size_t) 4) == 0)
  800.         (void) Strncpy(str, dir);
  801.     else
  802.         (void) sprintf(str, "CWD %s", dir);
  803.     if (command(str) != 5) {
  804. getrwd:
  805.         (void) quiet_command("PWD");
  806.         cp = rindex(reply_string, '\"');
  807.         if (cp != NULL) {
  808.             result = 1;
  809.             *cp = '\0';
  810.             cp = index(reply_string, '\"');
  811.             if (cp != NULL)
  812.                 (void) Strncpy(cwd, ++cp);
  813.         }
  814.     }
  815.     dbprintf("Current remote directory is \"%s\"\n", cwd);
  816.     return (result);
  817. }    /* _cd */
  818.  
  819.  
  820.  
  821.  
  822. /*
  823.  * Set current working directory
  824.  * on local machine.
  825.  */
  826. int lcd(int argc, char **argv)
  827. {
  828.     longstring ldir;
  829.  
  830.     if (argc < 2)
  831.         argc++, argv[1] = home;
  832.     if (argc != 2) {
  833.         return USAGE;
  834.     }
  835.     (void) Strncpy(ldir, argv[1]);
  836.     if (chdir(LocalDotPath(ldir)) < 0) {
  837.         PERROR("lcd", ldir);
  838.         return CMDERR;
  839.     }
  840.     (void) get_cwd(lcwd, (int) sizeof(lcwd));
  841.     if (NOT_VQUIET) 
  842.         (void) printf("Local directory now %s\n", lcwd);
  843.     return NOERR;
  844. }    /* lcd */
  845.  
  846.  
  847.  
  848.  
  849. /*
  850.  * Delete a single file.
  851.  */
  852. int do_delete(int argc, char **argv)
  853. {
  854.     string str;
  855.  
  856.     if (argc < 2)
  857.         argv = re_makeargv("(remote file to delete) ", &argc);
  858.     if (argc < 2) {
  859.         return USAGE;
  860.     }
  861.     if (rem_glob_one(argv[1]) == 0) {
  862.         (void) sprintf(str, "DELE %s", argv[1]);
  863.         (void) command(str);
  864.     }
  865.     return NOERR;
  866. }    /* do_delete */
  867.  
  868.  
  869.  
  870.  
  871. /*
  872.  * Delete multiple files.
  873.  */
  874. int mdelete(int argc, char **argv)
  875. {
  876.     char *cp;
  877.     Sig_t oldintr;
  878.     string str;
  879.  
  880.     if (argc < 2)
  881.         argv = re_makeargv("(remote-files) ", &argc);
  882.     if (argc < 2) {
  883.         return USAGE;
  884.     }
  885.     mname = argv[0];
  886.     activemcmd = 1;
  887.     oldintr = Signal(SIGINT, mabort);
  888.     (void) setjmp(jabort);
  889.     while ((cp = remglob(argv)) != NULL) {
  890.         if (*cp == '\0') {
  891.             activemcmd = 0;
  892.             continue;
  893.         }
  894.         if (activemcmd && confirm(argv[0], cp)) {
  895.             (void) sprintf(str, "DELE %s", cp);
  896.             (void) command(str);
  897.             if (!activemcmd && fromatty) {
  898.                 if (confirm("Continue with", "mdelete")) {
  899.                     activemcmd++;
  900.                 }
  901.             }
  902.         }
  903.     }
  904.     (void) Signal(SIGINT, oldintr);
  905.     activemcmd = 0;
  906.     return NOERR;
  907. }    /* mdelete */
  908.  
  909.  
  910.  
  911.  
  912. /*
  913.  * Rename a remote file.
  914.  */
  915. int renamefile(int argc, char **argv)
  916. {
  917.     string str;
  918.  
  919.     if (argc < 2)
  920.         argv = re_makeargv("(from-name) ", &argc);
  921.     if (argc < 2) {
  922. usage:
  923.         return USAGE;
  924.     }
  925.     if (argc < 3)
  926.         argv = re_makeargv("(to-name) ", &argc);
  927.     if (argc < 3)
  928.         goto usage;
  929.     if (rem_glob_one(argv[1]) < 0)
  930.         return CMDERR;
  931.     (void) sprintf(str, "RNFR %s", argv[1]);
  932.     if (command(str) == CONTINUE) {
  933.         (void) sprintf(str, "RNTO %s", argv[2]);
  934.         (void) command(str);
  935.     }
  936.     return NOERR;
  937. }    /* renamefile */
  938.  
  939.  
  940.  
  941. /*
  942.  * Get a directory listing
  943.  * of remote files.
  944.  */
  945. int ls(int argc, char **argv)
  946. {
  947.     char        *whichcmd, *cp;
  948.     str32        lsflags;
  949.     string        remote, local, str;
  950.     int            listmode, pagemode, i;
  951.  
  952.     PurgeLineBuffer();
  953.     pagemode = 0;
  954.     switch (**argv) {
  955.         case 'p':                            /* pls, pdir, pnlist */
  956.             pagemode = 1;
  957.             listmode = argv[0][1] == 'd';
  958.             break;
  959.         case 'd':                            /* dir */
  960.             listmode = 1;
  961.             break;
  962.         default:                            /* ls, nlist */
  963.             listmode = 0;
  964.     }
  965.     whichcmd = listmode ? "LIST" : "NLST";
  966.  
  967.     (void) strncpy(local, (pagemode ? pager : "-"), sizeof(local));
  968.     remote[0] = lsflags[0] = 0;
  969.     
  970.     /* Possible scenarios:
  971.      *  1.    ls
  972.      *  2.    ls -flags
  973.      *  3.    ls directory
  974.      *  4.  ls -flags >outfile
  975.      *  5.  ls directory >outfile
  976.      *  6.  ls -flags directory
  977.      *  7.  ls -flags directory >outfile
  978.      *
  979.      * Note that using a wildcard will choke with flags.  I.e., don't do
  980.      * "ls -CF *.tar," but instead do "ls *.tar."
  981.      */
  982.  
  983.     for (i=1; i<argc; i++) {
  984.         switch (argv[i][0]) {
  985.             case '-': 
  986.                 /*
  987.                  * If you give more than one set of flags, concat the each
  988.                  * additional set to the first one (without the dash).
  989.                  */
  990.                 (void) strncat(lsflags, (argv[i] + (lsflags[0] == '-')), sizeof(lsflags));
  991.                 break;
  992.             case '|':
  993.                 (void) Strncpy(local, argv[i]);
  994.                 LocalDotPath(local + 1);
  995.                 break;
  996.             case '>':
  997.                 /* We don't want the '>'. */
  998.                 (void) Strncpy(local, argv[i] + 1);
  999.                 LocalDotPath(local);
  1000.                 break;
  1001.             default:  
  1002.                 cp = argv[i];
  1003.                 /*
  1004.                  * In case you want to get a remote file called '--README--'
  1005.                  * or '>README,' you can use '\--README--' and '\>README.'
  1006.                  */
  1007.                 if ((cp[1] != 0) && (*cp == '\\'))
  1008.                     ++cp;
  1009.                 if (remote[0] != 0) {
  1010.                     (void) Strncat(remote, " ");
  1011.                     (void) Strncat(remote, cp);
  1012.                 } else {
  1013.                     (void) Strncpy(remote, cp);
  1014.                 }
  1015.         }    /* end switch */    
  1016.     }        /* end loop */
  1017.  
  1018.     /*
  1019.      *    If we are given an ls with some flags, make sure we use 
  1020.      *    columnized output (-C) unless one column output (-1) is
  1021.      *    specified.
  1022.      */
  1023.     if (!listmode) {
  1024.         if (lsflags[0] != 0) {
  1025.             (void) Strncpy(str, lsflags);
  1026.             for (cp = str + 1; *cp; cp++)
  1027.                 if (*cp == '1')
  1028.                     goto aa;
  1029.             (void) sprintf(lsflags, "-FC%s", str + 1);
  1030.         } else {
  1031.             if (remote_is_unix)
  1032.                 (void) strcpy(lsflags, "-FC");
  1033.         }
  1034.         /* As noted above, we can't use -flags if the user gave a
  1035.          * wildcard expr.
  1036.          */
  1037.         if (remote_is_unix && (strpbrk(remote, globchars) != NULL)) {
  1038.             lsflags[0] = 0;
  1039.             /* Warn the user what's going on. */
  1040.             if ((warnNoLSFlagsWithWildcards == 0) && NOT_VQUIET) {
  1041.                 (void) fprintf(stderr, "Warning: ls flags disabled with wildcard expressions.\n");
  1042.                 warnNoLSFlagsWithWildcards++;
  1043.             }
  1044.         }
  1045.     }
  1046.  
  1047. aa:
  1048.     is_ls = 1; /* tells getreply() to start saving input to a buffer. */
  1049.     (void) Strncpy(str, remote);
  1050.     if (lsflags[0] && remote[0])
  1051.         (void) sprintf(remote, "%s%c%s", lsflags, LS_FLAGS_AND_FILE, str);
  1052.     else
  1053.         (void) strncpy(remote, lsflags[0] ? lsflags : str, sizeof(remote));
  1054.     (void) recvrequest(whichcmd, local, (remote[0] == 0 ? NULL : remote), "w");
  1055.     is_ls=0;
  1056.     return NOERR;
  1057. }    /* ls */
  1058.  
  1059.  
  1060.  
  1061. /*
  1062.  * Do a shell escape
  1063.  */
  1064. /*ARGSUSED*/
  1065. int shell(int argc, char **argv)
  1066. {
  1067.     int                pid;
  1068.     Sig_t            old1, old2;
  1069.     char            *theShell, *namep;
  1070. #ifndef U_WAIT
  1071.     int                Status;
  1072. #else
  1073.     union wait        Status;
  1074. #endif
  1075.     string            str;
  1076.  
  1077.     old1 = signal (SIGINT, SIG_IGN);
  1078.     old2 = signal (SIGQUIT, SIG_IGN);
  1079.     /* This will prevent <defunct> zombie processes. */
  1080.     /* (void) signal(SIGCHLD, SIG_IGN); */
  1081.  
  1082.     if ((pid = fork()) == 0) {
  1083.         for (pid = 3; pid < 20; pid++)
  1084.             (void) close(pid);
  1085.         (void) Signal(SIGINT, SIG_DFL);
  1086.         (void) Signal(SIGQUIT, SIG_DFL);
  1087.         if ((theShell = getenv("SHELL")) == NULL)
  1088.             theShell = uinfo.shell;
  1089.         if (theShell == NULL)
  1090.             theShell = "/bin/sh";
  1091.         namep = rindex(theShell, '/');
  1092.         if (namep == NULL)
  1093.             namep = theShell;
  1094.         (void) strcpy(str, "-");
  1095.         (void) strcat(str, ++namep);
  1096.         if (strcmp(namep, "sh") != 0)
  1097.             str[0] = '+';
  1098.         dbprintf ("%s\n", theShell);
  1099. #if defined(BSD) || defined(_POSIX_SOURCE)
  1100.         setreuid(-1,getuid());
  1101.         setregid(-1,getgid());
  1102. #endif
  1103.         if (argc > 1)
  1104.             (void) execl(theShell, str, "-c", altarg, (char *)0);
  1105.         else
  1106.             (void) execl(theShell, str, (char *)0);
  1107.         PERROR("shell", theShell);
  1108.         exit(1);
  1109.         }
  1110.     if (pid > 0)
  1111.         while (wait((void *) &Status) != pid)
  1112.             ;
  1113.     (void) Signal(SIGINT, old1);
  1114.     (void) Signal(SIGQUIT, old2);
  1115.     if (pid == -1) {
  1116.         PERROR("shell", "Try again later");
  1117.     }
  1118.     return NOERR;
  1119. }    /* shell */
  1120.  
  1121.  
  1122.  
  1123.  
  1124. /*
  1125.  * Send new user information (re-login)
  1126.  */
  1127. int do_user(int argc, char **argv)
  1128. {
  1129.     char            acct[80];
  1130.     int                n, aflag = 0;
  1131.     string            str;
  1132.  
  1133.     if (argc < 2)
  1134.         argv = re_makeargv("(username) ", &argc);
  1135.     if (argc > 4) {
  1136.         return USAGE;
  1137.     }
  1138.     (void) sprintf(str, "USER %s", argv[1]);
  1139.     n = command(str);
  1140.     if (n == CONTINUE) {
  1141.         if (argc < 3 )
  1142.             argv[2] = Getpass("Password: "), argc++;
  1143.         (void) sprintf(str, "PASS %s", argv[2]);
  1144.         n = command(str);
  1145.     }
  1146.     if (n == CONTINUE) {
  1147.         if (argc < 4) {
  1148.             (void) printf("Account: "); (void) fflush(stdout);
  1149.             (void) FGets(acct, stdin);
  1150.             acct[strlen(acct) - 1] = '\0';
  1151.             argv[3] = acct; argc++;
  1152.         }
  1153.         (void) sprintf(str, "ACCT %s", argv[3]);
  1154.         n = command(str);
  1155.         aflag++;
  1156.     }
  1157.     if (n != COMPLETE) {
  1158.         (void) fprintf(stdout, "Login failed.\n");
  1159.         logged_in = 0;
  1160.         return (0);
  1161.     }
  1162.     if (!aflag && argc == 4) {
  1163.         (void) sprintf(str, "ACCT %s", argv[3]);
  1164.         (void) command(str);
  1165.     }
  1166.     logged_in = 1;
  1167.     CheckRemoteSystemType(0);
  1168.     return NOERR;
  1169. }    /* do_user */
  1170.  
  1171.  
  1172.  
  1173.  
  1174. /*
  1175.  * Print working directory.
  1176.  */
  1177. /*ARGSUSED*/
  1178. int pwd(int argc, char **argv)
  1179. {
  1180.     (void) verbose_command("PWD");
  1181.     return NOERR;
  1182. }    /* pwd */
  1183.  
  1184.  
  1185.  
  1186.  
  1187. /*
  1188.  * Make a directory.
  1189.  */
  1190. int makedir(int argc, char **argv)
  1191. {
  1192.     string str;
  1193.  
  1194.     if (argc < 2)
  1195.         argv = re_makeargv("(directory-name) ", &argc);
  1196.     if (argc < 2) {
  1197.         return USAGE;
  1198.     }
  1199.     (void) sprintf(str, "MKD %s", argv[1]);
  1200.     (void) command(str);
  1201.     return NOERR;
  1202. }    /* makedir */
  1203.  
  1204.  
  1205.  
  1206.  
  1207. /*
  1208.  * Remove a directory.
  1209.  */
  1210. int removedir(int argc, char **argv)
  1211. {
  1212.     string str;
  1213.     if (argc < 2)
  1214.         argv = re_makeargv("(directory-name) ", &argc);
  1215.     if (argc < 2) {
  1216.         return USAGE;
  1217.     }
  1218.     if (rem_glob_one(argv[1]) == 0) {
  1219.         (void) sprintf(str, "RMD %s", argv[1]);
  1220.         (void) command(str);
  1221.     }
  1222.     return NOERR;
  1223. }    /* removedir */
  1224.  
  1225.  
  1226.  
  1227.  
  1228. /*
  1229.  * Send a line, verbatim, to the remote machine.
  1230.  */
  1231. int quote(int argc, char **argv)
  1232. {
  1233.     int i, tmpverbose;
  1234.     string str;
  1235.  
  1236.     if (argc < 2)
  1237.         argv = re_makeargv("(command line to send) ", &argc);
  1238.     if (argc < 2) {
  1239.         return USAGE;
  1240.     }
  1241.     str[0] = 0;
  1242.     if (*argv[0] == 's')    /* Command was 'site' instead of 'quote.' */
  1243.         (void) Strncpy(str, "site ");
  1244.     (void) Strncat(str, argv[1]);
  1245.     for (i = 2; i < argc; i++) {
  1246.         (void) Strncat(str, " ");
  1247.         (void) Strncat(str, argv[i]);
  1248.     }
  1249.     tmpverbose = verbose;
  1250.     verbose = V_VERBOSE;
  1251.     if (command(str) == PRELIM) {
  1252.         while (getreply(0) == PRELIM);
  1253.     }
  1254.     verbose = tmpverbose;
  1255.     return NOERR;
  1256. }    /* quote */
  1257.  
  1258.  
  1259.  
  1260.  
  1261. /*
  1262.  * Ask the other side for help.
  1263.  */
  1264. int rmthelp(int argc, char **argv)
  1265. {
  1266.     string str;
  1267.  
  1268.     if (argc == 1) (void) verbose_command("HELP");
  1269.     else {
  1270.         (void) sprintf(str, "HELP %s", argv[1]);
  1271.         (void) verbose_command(str);
  1272.     }
  1273.     return NOERR;
  1274. }    /* rmthelp */
  1275.  
  1276.  
  1277.  
  1278.  
  1279. /*
  1280.  * Terminate session and exit.
  1281.  */
  1282. /*ARGSUSED*/
  1283. int quit(int argc, char **argv)
  1284. {
  1285.     close_up_shop();
  1286.     trim_log();
  1287.     exit(0);
  1288. }    /* quit */
  1289.  
  1290.  
  1291.  
  1292. void close_streams(int wantShutDown)
  1293. {
  1294.     if (cout != NULL) {
  1295.         if (wantShutDown)
  1296.             (void) shutdown(fileno(cout), 1+1);
  1297.         (void) fclose(cout);
  1298.         cout = NULL;
  1299.     }
  1300.     if (cin != NULL) {
  1301.         if (wantShutDown)
  1302.             (void) shutdown(fileno(cin), 1+1);
  1303.         (void) fclose(cin);
  1304.         cin = NULL;
  1305.     }
  1306. }    /* close_streams */
  1307.  
  1308.  
  1309.  
  1310.  
  1311. /*
  1312.  * Terminate session, but don't exit.
  1313.  */
  1314. /*ARGSUSED*/
  1315. int disconnect(int argc, char **argv)
  1316. {
  1317. #ifdef SYSLOG
  1318.     syslog (LOG_INFO, "%s disconnected from %s.", uinfo.username, hostname);
  1319. #endif
  1320.  
  1321.     (void) command("QUIT");
  1322.     close_streams(0);
  1323.     if (logged_in)
  1324.         UpdateRecentSitesList(hostname, cwd);
  1325.     hostname[0] = cwd[0] = 0;
  1326.     logged_in = connected = 0;
  1327.     data = -1;
  1328.     macnum = 0;
  1329.     return NOERR;
  1330. }    /* disconnect */
  1331.  
  1332.  
  1333.  
  1334. void
  1335. close_up_shop(void)
  1336. {
  1337.     static int only_once = 0;
  1338.     if (only_once++ > 0)
  1339.         return;
  1340.     if (connected)
  1341.         (void) disconnect(0, NULL);
  1342.     WriteRecentSitesFile();
  1343.     if (logf != NULL) {
  1344.         (void) fclose(logf);
  1345.         logf = NULL;
  1346.     }
  1347. }    /* close_up_shop */
  1348.  
  1349.  
  1350.  
  1351.  
  1352. /*
  1353.  * Glob a local file name specification with
  1354.  * the expectation of a single return value.
  1355.  * Can't control multiple values being expanded
  1356.  * from the expression, we return only the first.
  1357.  */
  1358. int globulize(char **cpp)
  1359. {
  1360.     char **globbed;
  1361.  
  1362.     (void) LocalPath(*cpp);
  1363.     globbed = glob(*cpp);
  1364.     if (globerr != NULL) {
  1365.         (void) printf("%s: %s\n", *cpp, globerr);
  1366.         if (globbed) {
  1367.             blkfree(globbed);
  1368.             Free(globbed);
  1369.         }
  1370.         return (0);
  1371.     }
  1372.     if (globbed) {
  1373.         *cpp = *globbed++;
  1374.         /* don't waste too much memory */
  1375.         if (*globbed) {
  1376.             blkfree(globbed);
  1377.             Free(globbed);
  1378.         }
  1379.     }
  1380.     return (1);
  1381. }    /* globulize */
  1382.  
  1383.  
  1384.  
  1385. /* change directory to perent directory */
  1386. /*ARGSUSED*/
  1387. int cdup(int argc, char **argv)
  1388. {
  1389.     (void) _cd("CDUP");
  1390.     return NOERR;
  1391. }    /* cdup */
  1392.  
  1393.  
  1394. /* show remote system type */
  1395. /*ARGSUSED*/
  1396. int syst(int argc, char **argv)
  1397. {
  1398.     (void) verbose_command("SYST");
  1399.     return NOERR;
  1400. }    /* syst */
  1401.  
  1402.  
  1403.  
  1404.  
  1405. int make_macro(char *name, FILE *fp)
  1406. {
  1407.     char            *tmp;
  1408.     char            *cp;
  1409.     string            str;
  1410.     size_t            len;
  1411.     int                i;
  1412.  
  1413.     if (macnum == MAXMACROS) {
  1414.         (void) fprintf(stderr, "Limit of %d macros have already been defined.\n", MAXMACROS);
  1415.         return -1;
  1416.     }
  1417.  
  1418.     /* Make sure macros have unique names.  If 'init' was attempted to be
  1419.      * redefined, just return, since it was probably cmdOpen() in a redial
  1420.      * mode which tried to define it again.
  1421.      */
  1422.     for (i = 0; i<macnum; i++) {
  1423.         if (strncmp(name, macros[i].mac_name, (size_t)8) == 0) {
  1424.             if (parsing_rc) {
  1425.                 /* Just shut up and read in the macro, but don't save it,
  1426.                  * because we already have it.
  1427.                  */
  1428.                 while ((cp = FGets(str, fp)) != NULL) {
  1429.                     /* See if we have a 'blank' line: just whitespace. */
  1430.                     while (*cp && isspace(*cp)) ++cp;
  1431.                     if (!*cp)
  1432.                         break;
  1433.                 }
  1434.             } else
  1435.                 (void) fprintf(stderr,
  1436.                     "There is already a macro named '%s.'\n", name);
  1437.             return -1;
  1438.         }
  1439.     }
  1440.     (void) strncpy(macros[macnum].mac_name, name, (size_t)8);
  1441.     if (macnum == 0)
  1442.         macros[macnum].mac_start = macbuf;
  1443.     else
  1444.         macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
  1445.     tmp = macros[macnum].mac_start;
  1446.     while (1) {
  1447.         cp = FGets(str, fp);
  1448.         if (cp == NULL) {
  1449.             /*
  1450.              * If we had started a macro, we will say it is
  1451.              * okay to skip the blank line delimiter if we
  1452.              * are at the EOF.
  1453.              */
  1454.             if (tmp > macros[macnum].mac_start)
  1455.                 goto endmac;
  1456.             (void) fprintf(stderr, "No text supplied for macro \"%s.\"\n", name);
  1457.         }
  1458.         /* see if we have a 'blank' line: just whitespace. */
  1459.         while (*cp && isspace(*cp)) ++cp;
  1460.         if (*cp == '\0') {
  1461.             /* Blank line; end this macro. */
  1462. endmac:
  1463.             macros[macnum++].mac_end = tmp;
  1464.             return 0;
  1465.         }
  1466.         /* Add the text of this line to the macro. */
  1467.         len = strlen(cp) + 1;    /* we need the \0 too. */
  1468.         if (tmp + len >= macbuf + MACBUFLEN) {
  1469.             (void) fprintf(stderr, "Macro \"%s\" not defined -- %d byte buffer exceeded.\n", name, MACBUFLEN);
  1470.             return -1;
  1471.         }
  1472.         (void) strcpy(tmp, cp);
  1473.         tmp += len;
  1474.     }
  1475. }    /* make_macro */
  1476.  
  1477.  
  1478.  
  1479.  
  1480. int macdef(int argc, char **argv)
  1481. {
  1482.     if (argc < 2)
  1483.         argv = re_makeargv("(macro name) ", &argc);
  1484.     if (argc != 2) {
  1485.         (void) domacro(0, NULL);
  1486.         return USAGE;
  1487.     }
  1488.     (void) printf("Enter macro line by line, terminating it with a blank line\n");
  1489.     (void) make_macro(argv[1], stdin);
  1490.     return NOERR;
  1491. }    /* macdef */
  1492.  
  1493.  
  1494.  
  1495.  
  1496. int domacro(int argc, char **argv)
  1497. {
  1498.     register int            i, j;
  1499.     register char            *cp1, *cp2;
  1500.     int                        count = 2, loopflg = 0;
  1501.     string                    str;
  1502.     struct cmd                *c;
  1503.  
  1504.     if (argc < 2) {
  1505.         /* print macros. */
  1506.         if (macnum == 0)
  1507.             (void) printf("No macros defined.\n");
  1508.         else {
  1509.             (void) printf("Current macro definitions:\n");
  1510.             for (i = 0; i < macnum; ++i) {
  1511.                 (void) printf("%s:\n", macros[i].mac_name);
  1512.                 cp1 = macros[i].mac_start;
  1513.                 cp2 = macros[i].mac_end;
  1514.                 while (cp1 < cp2) {
  1515.                     (void) printf("   > ");
  1516.                     while (cp1 < cp2 && *cp1)
  1517.                         putchar(*cp1++);
  1518.                     ++cp1;
  1519.                 }
  1520.             }
  1521.         }
  1522.         if (argc == 0) return (NOERR);    /* called from macdef(), above. */
  1523.         argv = re_makeargv("(macro to run) ", &argc);
  1524.     }            
  1525.     if (argc < 2) {
  1526.         return USAGE;
  1527.     }
  1528.     for (i = 0; i < macnum; ++i) {
  1529.         if (!strncmp(argv[1], macros[i].mac_name, (size_t) 9)) {
  1530.             break;
  1531.         }
  1532.     }
  1533.     if (i == macnum) {
  1534.         (void) printf("'%s' macro not found.\n", argv[1]);
  1535.         return USAGE;
  1536.     }
  1537.     doingInitMacro = (strcmp(macros[i].mac_name, "init") == 0);
  1538.     (void) Strncpy(str, line);
  1539. TOP:
  1540.     cp1 = macros[i].mac_start;
  1541.     while (cp1 != macros[i].mac_end) {
  1542.         while (isspace(*cp1)) {
  1543.             cp1++;
  1544.         }
  1545.         cp2 = line;
  1546.         while (*cp1 != '\0') {
  1547.               switch(*cp1) {
  1548.                    case '\\':
  1549.                  *cp2++ = *++cp1;
  1550.                  break;
  1551.                 case '$':
  1552.                  if (isdigit(*(cp1+1))) {
  1553.                     j = 0;
  1554.                     while (isdigit(*++cp1)) {
  1555.                       j = 10*j +  *cp1 - '0';
  1556.                     }
  1557.                     cp1--;
  1558.                     if (argc - 2 >= j) {
  1559.                     (void) strcpy(cp2, argv[j+1]);
  1560.                     cp2 += strlen(argv[j+1]);
  1561.                     }
  1562.                     break;
  1563.                  }
  1564.                  if (*(cp1+1) == 'i') {
  1565.                     loopflg = 1;
  1566.                     cp1++;
  1567.                     if (count < argc) {
  1568.                        (void) strcpy(cp2, argv[count]);
  1569.                        cp2 += strlen(argv[count]);
  1570.                     }
  1571.                     break;
  1572.                 }
  1573.                 /* intentional drop through */
  1574.                 default:
  1575.                 *cp2++ = *cp1;
  1576.                 break;
  1577.               }
  1578.               if (*cp1 != '\0') {
  1579.                     cp1++;
  1580.               }
  1581.         }
  1582.         *cp2 = '\0';
  1583.         makeargv();
  1584.         c = getcmd(margv[0]);
  1585.         if ((c == (struct cmd *) -1) && !parsing_rc) {
  1586.             (void) printf("?Ambiguous command\n");
  1587.         } else if (c == NULL && !parsing_rc) {
  1588.             (void) printf("?Invalid command\n");
  1589.         } else if (c->c_conn && !connected) {
  1590.             (void) printf("Not connected.\n");
  1591.         } else {
  1592.             if (IS_VVERBOSE)
  1593.                 (void) printf("%s\n",line);
  1594.             if ((*c->c_handler)(margc, margv) == USAGE)
  1595.                 cmd_usage(c);
  1596.             (void) strcpy(line, str);
  1597.             makeargv();
  1598.             argc = margc;
  1599.             argv = margv;
  1600.         }
  1601.         if (cp1 != macros[i].mac_end) {
  1602.             cp1++;
  1603.         }
  1604.     }
  1605.     if (loopflg && ++count < argc) {
  1606.         goto TOP;
  1607.     }
  1608.     doingInitMacro = 0;
  1609.     return NOERR;
  1610. }    /* domacro */
  1611.  
  1612.  
  1613.  
  1614. /*
  1615.  * get size of file on remote machine
  1616.  */
  1617. int sizecmd(int argc, char **argv)
  1618. {
  1619.     string str;
  1620.  
  1621.     if (argc < 2)
  1622.         argv = re_makeargv("(remote-file) ", &argc);
  1623.     if (argc < 2) {
  1624.         return USAGE;
  1625.     }
  1626.     if (rem_glob_one(argv[1]) == 0) {
  1627.         (void) sprintf(str, "SIZE %s", argv[1]);
  1628.         (void) verbose_command(str);
  1629.     }
  1630.     return NOERR;
  1631. }    /* sizecmd */
  1632.  
  1633.  
  1634.  
  1635.  
  1636. /*
  1637.  * get last modification time of file on remote machine
  1638.  */
  1639. int modtime(int argc, char **argv)
  1640. {
  1641.     int overbose;
  1642.     string str;
  1643.  
  1644.     if (argc < 2)
  1645.         argv = re_makeargv("(remote-file) ", &argc);
  1646.     if (argc < 2) {
  1647.         return USAGE;
  1648.     }
  1649.     if (rem_glob_one(argv[1]) == 0) {
  1650.         overbose = verbose;
  1651.         if (debug == 0)
  1652.             verbose = V_QUIET;
  1653.         (void) sprintf(str, "MDTM %s", argv[1]);
  1654.         if (command(str) == COMPLETE) {
  1655.             int yy, mo, day, hour, min, sec;
  1656.             (void) sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d",
  1657.                 &yy, &mo, &day, &hour, &min, &sec);
  1658.             /* might want to print this in local time */
  1659.             (void) printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
  1660.                 mo, day, yy, hour, min, sec);
  1661.         } else
  1662.             (void) fputs(reply_string, stdout);
  1663.         verbose = overbose;
  1664.     }
  1665.     return NOERR;
  1666. }    /* modtime */
  1667.  
  1668.  
  1669.  
  1670. int lookup(int argc, char **argv)
  1671. {
  1672.     int i, j, by_name, result = NOERR;
  1673.     struct hostent *host;        /* structure returned by gethostbyaddr() */
  1674.     extern int h_errno;
  1675. #ifdef BAD_INETADDR
  1676.     struct in_addr addr;        /* address in host order */
  1677. # define ADDR    addr.s_addr
  1678. #else
  1679.     unsigned long addr;            /* address in host order */
  1680. # define ADDR    addr
  1681. #endif
  1682.  
  1683.     if (argc < 2)
  1684.         argv = re_makeargv("(sitename) ", &argc);
  1685.     if (argc < 2) {
  1686.         return USAGE;
  1687.     }
  1688.  
  1689.      lasthostname[0] = 0;
  1690.     for (i=1; i<argc; i++) {
  1691.         /* does the argument look like an address? */
  1692.         if (4 == sscanf (argv[i], "%d.%d.%d.%d", &j, &j, &j, &j)) {
  1693.             /* ip */
  1694.               addr = inet_addr (argv[i]);
  1695.               if (ADDR == 0xffffffff) {
  1696.                  (void) fprintf(stderr, "## could not convert \"%s\" into a valid IP address.\n", argv[i]);
  1697.                  continue;
  1698.              }
  1699.             host = gethostbyaddr ((char *) &ADDR, 4, AF_INET);
  1700.             by_name = 0;
  1701.         } else {
  1702.             /* name */
  1703.             host = gethostbyname (argv[i]);
  1704.             by_name = 1;
  1705.         }
  1706.         if (host == NULL) {
  1707.             if (NOT_VQUIET) {
  1708.                 /* gethostxxx error */                
  1709.                 if (h_errno == HOST_NOT_FOUND) {
  1710.                      (void) printf("%s: lookup error (%d).\n",
  1711.                          argv[i], h_errno);
  1712.                      result = h_errno;
  1713.                  } else {
  1714.                      (void) printf("%s \"%s\"\n",
  1715.                          (by_name==0 ? "unknown address" : "unknown host"),
  1716.                          argv[i]);
  1717.                      result = 
  1718.                          h_errno != 0 ? h_errno :
  1719.                          -1;
  1720.                 }
  1721.             }
  1722.          } else {
  1723.              if (*host->h_name)
  1724.                  (void) Strncpy(lasthostname, host->h_name);
  1725.             for (j=0; host->h_aliases[j] != NULL; j++) {
  1726.                 if (strlen(host->h_aliases[j]) >
  1727.                     strlen(host->h_name) &&
  1728.                     strstr(host->h_aliases[j],host->h_name) != NULL)
  1729.                         (void) Strncpy(lasthostname,host->h_aliases[j]);
  1730.             }
  1731.             if (NOT_VQUIET) {
  1732.                 (void) printf("%-32s  ", *host->h_name ? host->h_name : "???");
  1733.                 if (*host->h_addr_list) {
  1734.                     unsigned long horder;
  1735.     
  1736.                     horder = ntohl (*(unsigned long *) *(char **)host->h_addr_list);
  1737.                     (void) printf ("%lu.%lu.%lu.%lu\n",
  1738.                         (horder >> 24),
  1739.                         (horder >> 16) & 0xff,
  1740.                         (horder >> 8) & 0xff,
  1741.                         horder & 0xff);
  1742.                 }
  1743.                 else (void) printf("???\n");
  1744.             }
  1745.         }
  1746.     }    /* loop thru all sites */
  1747.     return result;
  1748. }    /* lookup */
  1749.  
  1750.  
  1751.  
  1752.  
  1753. int getlocalhostname(char *host, size_t size)
  1754. {
  1755.     int oldv, r;
  1756.     char *argv[2];
  1757.     char domain[64];
  1758.  
  1759. #ifdef HOSTNAME
  1760.     (void) strncpy(host, HOSTNAME, size);
  1761.     return NOERR;
  1762. #else
  1763.     host[0] = '\0';
  1764.     if ((r = gethostname(host, size)) == 0) {
  1765.         if (host[0] == '\0') {
  1766.             (void) fprintf(stderr,
  1767. "Could not determine the hostname. Re-compile with HOSTNAME defined\n\
  1768. to be the full name of your hostname.\n");
  1769.             exit(1);
  1770.         }
  1771.         oldv = verbose;
  1772.         verbose = V_QUIET;
  1773.         argv[0] = "lookup";
  1774.         (void) sprintf(line, "lookup %s", host);
  1775.         (void) makeargv();
  1776.         if (lookup(margc, margv) == 0 && lasthostname[0]) {
  1777.             (void) _Strncpy(host, lasthostname, size);
  1778.             domain[0] = '\0';
  1779. #ifdef HAS_DOMAINNAME
  1780.             /* getdomainname() returns just the domain name, without a
  1781.              * preceding period.  For example, on "cse.unl.edu", it would
  1782.              * return "unl.edu".
  1783.              *
  1784.              * SunOS note: getdomainname will return an empty string if
  1785.              * this machine isn't on NIS.
  1786.              */
  1787.             (void) getdomainname(domain, sizeof(domain) - 1);
  1788. #endif
  1789. #ifdef DOMAIN_NAME
  1790.             (void) Strncpy(domain, DOMAIN_NAME);
  1791. #endif
  1792.             if (index(host, '.') == NULL) {
  1793.                 /* If the hostname has periods we'll assume that the
  1794.                  * it includes the domain name already.  Some gethostname()s
  1795.                  * return the whole host name, others just the machine name.
  1796.                  * If we have just the machine name and we successfully
  1797.                  * found out the domain name (from above), we'll append
  1798.                  * the domain to the machine to get a full hostname.
  1799.                  */
  1800.                 if (domain[0]) {
  1801.                     (void) _Strncat(host, ".", size);
  1802.                     (void) _Strncat(host, domain, size);
  1803.                 } else {
  1804.                     fprintf(stderr,
  1805. "WARNING: could not determine full host name (have: '%s').\n\
  1806. The program should be re-compiled with DOMAIN_NAME defined to be the\n\
  1807. domain name, i.e. -DDOMAIN_NAME=\\\"unl.edu\\\"\n\n",
  1808.                         host);
  1809.                 }
  1810.             }
  1811.         }
  1812.         verbose = oldv;
  1813.     }
  1814.     return r;
  1815. #endif
  1816. }    /* getlocalhostname */
  1817.  
  1818.  
  1819.  
  1820.  
  1821. /*
  1822.  * show status on remote machine
  1823.  */
  1824. int rmtstatus(int argc, char **argv)
  1825. {
  1826.     string str;
  1827.  
  1828.     if (argc > 1) {
  1829.         (void) sprintf(str, "STAT %s" , argv[1]);
  1830.         (void) verbose_command(str);
  1831.     } else (void) verbose_command("STAT");
  1832.     return NOERR;
  1833. }    /* rmtstatus */
  1834.  
  1835.  
  1836.  
  1837.  
  1838. /*
  1839.  * create an empty file on remote machine.
  1840.  */
  1841. int create(int argc, char **argv)
  1842. {
  1843.     string            str;
  1844.     FILE            *ftemp;
  1845.  
  1846.     if (argc < 2)
  1847.         argv = re_makeargv("(remote-file) ", &argc);
  1848.     if (argc < 2) {
  1849.         return USAGE;
  1850.     }
  1851.     (void) tmp_name(str);
  1852.     ftemp = fopen(str, "w");
  1853.     /* (void) fputc('x', ftemp); */
  1854.     (void) fclose(ftemp);
  1855.     creating = 1;
  1856.     (void) sendrequest("STOR", str, argv[1]);
  1857.     creating = 0;
  1858.     (void) unlink(str);
  1859.     return NOERR;
  1860. }    /* create */
  1861.  
  1862.  
  1863.  
  1864.  
  1865. /* show version info */
  1866. /*ARGSUSED*/
  1867. int show_version(int argc, char **argv)
  1868. {
  1869.     char    *DStrs[80];
  1870.     int        nDStrs = 0, i, j;
  1871.  
  1872.     (void) printf("%-30s %s\n", "NcFTP Version:", version);
  1873.     (void) printf("%-30s %s\n", "Author:",
  1874.         "Mike Gleason, NCEMRSoft (mgleason@cse.unl.edu).");
  1875.  
  1876. /* Now entering CPP hell... */
  1877. #ifdef __DATE__
  1878.     (void) printf("%-30s %s\n", "Compile Date:", __DATE__);
  1879. #endif
  1880.     (void) printf("%-30s %s (%s)\n", "Operating System:",
  1881. #ifdef System
  1882.     System,
  1883. #else
  1884. #    ifdef unix
  1885.     "UNIX",
  1886. #    else
  1887.     "??",
  1888. #    endif
  1889. #endif
  1890. #ifdef SYSV
  1891.         "SYSV");
  1892. #else
  1893. #    ifdef BSD
  1894.             "BSD");
  1895. #    else
  1896.             "neither BSD nor SYSV?");
  1897. #    endif
  1898. #endif
  1899.  
  1900.     /* Show which CPP symbols were used in compilation. */
  1901. #ifdef __GNUC__
  1902.     DStrs[nDStrs++] = "__GNUC__";
  1903. #endif
  1904. #ifdef RINDEX
  1905.     DStrs[nDStrs++] = "RINDEX";
  1906. #endif
  1907. #ifdef CURSES
  1908.     DStrs[nDStrs++] = "CURSES";
  1909. #endif
  1910. #ifdef NO_CURSES_H
  1911.     DStrs[nDStrs++] = "NO_CURSES_H";
  1912. #endif
  1913. #ifdef HERROR
  1914.     DStrs[nDStrs++] = "HERROR";
  1915. #endif
  1916. #ifdef U_WAIT
  1917.     DStrs[nDStrs++] = "U_WAIT";
  1918. #endif
  1919. #if defined(NO_CONST) || defined(const)
  1920.     DStrs[nDStrs++] = "NO_CONST";
  1921. #endif
  1922. #ifdef NO_FORMATTING
  1923.     DStrs[nDStrs++] = "NO_FORMATTING";
  1924. #endif
  1925. #ifdef DONT_TIMESTAMP
  1926.     DStrs[nDStrs++] = "DONT_TIMESTAMP";
  1927. #endif
  1928. #ifdef GETPASS
  1929.     DStrs[nDStrs++] = "GETPASS";
  1930. #endif
  1931. #ifdef HAS_GETCWD
  1932.     DStrs[nDStrs++] = "HAS_GETCWD";
  1933. #endif
  1934. #ifdef GETCWDSIZET
  1935.     DStrs[nDStrs++] = "GETCWDSIZET";
  1936. #endif
  1937. #ifdef HAS_DOMAINNAME
  1938.     DStrs[nDStrs++] = "HAS_DOMAINNAME";
  1939. #endif
  1940. #ifdef DOMAIN_NAME
  1941.     DStrs[nDStrs++] = "DOMAIN_NAME";
  1942. #endif
  1943. #ifdef Solaris
  1944.     DStrs[nDStrs++] = "Solaris";
  1945. #endif
  1946. #ifdef USE_GETPWUID
  1947.     DStrs[nDStrs++] = "USE_GETPWUID";
  1948. #endif
  1949. #ifdef HOSTNAME
  1950.     DStrs[nDStrs++] = "HOSTNAME";
  1951. #endif
  1952. #ifdef SYSDIRH
  1953.     DStrs[nDStrs++] = "SYSDIRH";
  1954. #endif
  1955. #ifdef SYSSELECTH
  1956.     DStrs[nDStrs++] = "SYSSELECTH";
  1957. #endif
  1958. #ifdef TERMH
  1959.     DStrs[nDStrs++] = "TERMH";
  1960. #endif
  1961. #ifdef NO_UNISTDH 
  1962.     DStrs[nDStrs++] = "NO_UNISTDH";
  1963. #endif
  1964. #ifdef NO_STDLIBH
  1965.     DStrs[nDStrs++] = "NO_STDLIBH";
  1966. #endif
  1967. #ifdef SYSLOG 
  1968.     DStrs[nDStrs++] = "SYSLOG";
  1969. #endif
  1970. #ifdef BAD_INETADDR
  1971.     DStrs[nDStrs++] = "BAD_INETADDR";
  1972. #endif
  1973. #ifdef SGTTYB
  1974.     DStrs[nDStrs++] = "SGTTYB";
  1975. #endif
  1976. #ifdef TERMIOS
  1977.     DStrs[nDStrs++] = "TERMIOS";
  1978. #endif
  1979. #ifdef STRICT_PROTOS
  1980.     DStrs[nDStrs++] = "STRICT_PROTOS";
  1981. #endif
  1982. #ifdef dFTP_PORT
  1983.     DStrs[nDStrs++] = "dFTP_PORT";
  1984. #endif
  1985. #ifdef BROKEN_MEMCPY
  1986.     DStrs[nDStrs++] = "BROKEN_MEMCPY";
  1987. #endif
  1988. #ifdef READLINE
  1989.     DStrs[nDStrs++] = "READLINE";
  1990. #endif
  1991. #ifdef GETLINE 
  1992.     DStrs[nDStrs++] = "GETLINE";
  1993. #endif
  1994. #ifdef _POSIX_SOURCE
  1995.     DStrs[nDStrs++] = "_POSIX_SOURCE";
  1996. #endif
  1997. #ifdef _XOPEN_SOURCE
  1998.     DStrs[nDStrs++] = "_XOPEN_SOURCE";
  1999. #endif
  2000. #ifdef NO_TIPS
  2001.     DStrs[nDStrs++] = "NO_TIPS";
  2002. #endif
  2003. #ifdef GZCAT
  2004.     DStrs[nDStrs++] = "GZCAT";
  2005. #endif
  2006. #ifdef LINGER
  2007.     DStrs[nDStrs++] = "LINGER";
  2008. #endif
  2009. #ifdef TRY_NOREPLY
  2010.     DStrs[nDStrs++] = "TRY_NOREPLY";
  2011. #endif
  2012. #ifdef NO_UTIMEH 
  2013.     DStrs[nDStrs++] = "NO_UTIMEH";
  2014. #endif
  2015. #ifdef DB_ERRS
  2016.     DStrs[nDStrs++] = "DB_ERRS";
  2017. #endif
  2018. #ifdef NO_VARARGS 
  2019.     DStrs[nDStrs++] = "NO_VARARGS";
  2020. #endif
  2021. #ifdef NO_STDARGH
  2022.     DStrs[nDStrs++] = "NO_STDARGH";
  2023. #endif
  2024. #ifdef NO_MKTIME
  2025.     DStrs[nDStrs++] = "NO_MKTIME";
  2026. #endif
  2027. #ifdef NO_STRSTR
  2028.     DStrs[nDStrs++] = "NO_STRSTR";
  2029. #endif
  2030. #ifdef NO_STRFTIME
  2031.     DStrs[nDStrs++] = "NO_STRFTIME";
  2032. #endif
  2033. #ifdef NO_RENAME
  2034.     DStrs[nDStrs++] = "NO_RENAME";
  2035. #endif
  2036. #ifdef TRY_ABOR
  2037.     DStrs[nDStrs++] = "TRY_ABOR";
  2038. #endif
  2039. #ifdef GATEWAY
  2040.     DStrs[nDStrs++] = "GATEWAY";
  2041. #endif
  2042. #ifdef SOCKS
  2043.     DStrs[nDStrs++] = "SOCKS";
  2044. #endif
  2045. #ifdef TERM_FTP
  2046.     DStrs[nDStrs++] = "TERM_FTP";
  2047. #endif
  2048. #ifdef NET_ERRNO_H
  2049.     DStrs[nDStrs++] = "NET_ERRNO_H";
  2050. #endif
  2051. #ifdef PASSIVEMODE
  2052.     DStrs[nDStrs++] = "PASSIVEMODE";
  2053. #endif
  2054.  
  2055.  
  2056. /* DONE with #ifdefs for now! */
  2057.  
  2058.     (void) printf ("\nCompile Options:\n");
  2059.     for (i=j=0; i<nDStrs; i++) {
  2060.         if (j == 0)
  2061.             (void) printf("    ");
  2062.         (void) printf("%-15s", DStrs[i]);
  2063.         if (++j == 4) {
  2064.             j = 0;
  2065.             (void) putchar('\n');
  2066.         }
  2067.     }
  2068.     if (j != 0)
  2069.         (void) putchar('\n');
  2070.  
  2071. #ifdef MK
  2072.     (void) printf("\nMK: %s\n", MK);
  2073. #endif /* MK */
  2074.  
  2075.     (void) printf("\nDefaults:\n");
  2076.     (void) printf("\
  2077.     Xfer Buf Size: %8d   Debug: %d   MPrompt: %d   Verbosity: %d\n\
  2078.     Prompt: %s   Pager: %s  ZCat: %s\n\
  2079.     Logname: %s   Logging: %d   Type: %s   Cmd Len: %d\n\
  2080.     Recv Line Len: %d   #Macros: %d   Macbuf: %d  Auto-Binary: %d\n\
  2081.     Recent File: %s   Recent On: %d   nRecents: %d\n\
  2082.     Redial Delay: %d  Anon Open: %d  New Mail Message: \"%s\"\n",
  2083.         MAX_XFER_BUFSIZE, dDEBUG, dMPROMPT, dVERBOSE,
  2084.         dPROMPT, dPAGER, ZCAT,
  2085.         dLOGNAME, dLOGGING, dTYPESTR, CMDLINELEN,
  2086.         RECEIVEDLINELEN, MAXMACROS, MACBUFLEN, dAUTOBINARY,
  2087.         dRECENTF, dRECENT_ON, dMAXRECENTS,
  2088.         dREDIALDELAY, dANONOPEN, NEWMAILMESSAGE
  2089.     );
  2090. #ifdef GATEWAY
  2091.     (void) printf("\
  2092.     Gateway Login: %s\n", dGATEWAY_LOGIN);
  2093. #endif
  2094.     return NOERR;
  2095. }    /* show_version */
  2096.  
  2097.  
  2098.  
  2099. void PurgeLineBuffer(void)
  2100. {
  2101.     register struct lslist *a, *b;
  2102.          
  2103.     for (a = lshead; a != NULL; ) {
  2104.         b = a->next;
  2105.         if (a->string)
  2106.             free(a->string);    /* free string */
  2107.         Free(a);         /* free node */
  2108.         a = b;
  2109.     }
  2110.     lshead = lstail = NULL;
  2111. }    /* PurgeLineBuffer */
  2112.  
  2113.  
  2114.  
  2115.  
  2116. /*ARGSUSED*/
  2117. int ShowLineBuffer(int argc, char **argv)
  2118. {
  2119.     register struct lslist *a = lshead;
  2120.     int pagemode;
  2121.     FILE *fp;
  2122.     Sig_t oldintp;
  2123.  
  2124.     if (a == NULL)
  2125.         return CMDERR;
  2126.     pagemode= (**argv) == 'p' && pager[0] == '|';
  2127.     if (pagemode) {
  2128.         fp = popen(pager + 1, "w");
  2129.         if (!fp) {
  2130.             PERROR("ShowLineBuffer", pager + 1);
  2131.             return CMDERR;
  2132.         }
  2133.     } else
  2134.         fp = stdout;
  2135.     oldintp = Signal(SIGPIPE, SIG_IGN);
  2136.     while (a) {
  2137.         if (a->string)
  2138.             (void) fprintf(fp, "%s\n", a->string);
  2139.         a = a->next;
  2140.     }
  2141.     if (pagemode)
  2142.         (void) pclose(fp);
  2143.     if (oldintp)
  2144.         (void) Signal(SIGPIPE, oldintp);
  2145.     return NOERR;
  2146. }    /* ShowLineBuffer */
  2147.  
  2148.  
  2149.  
  2150.  
  2151. #if LIBMALLOC != LIBC_MALLOC
  2152. /*ARGSUSED*/
  2153. int MallocStatusCmd(int argc, char **argv)
  2154. {
  2155. #if (LIBMALLOC == FAST_MALLOC)
  2156.     struct mallinfo mi;
  2157.  
  2158.     mi = mallinfo();
  2159.     printf("\
  2160. total space in arena:               %d\n\
  2161. number of ordinary blocks:          %d\n\
  2162. number of small blocks:             %d\n\
  2163. number of holding blocks:           %d\n\
  2164. space in holding block headers:     %d\n\
  2165. space in small blocks in use:       %d\n\
  2166. space in free small blocks:         %d\n\
  2167. space in ordinary blocks in use:    %d\n\
  2168. space in free ordinary blocks:      %d\n\
  2169. cost of enabling keep option:       %d\n",
  2170.         mi.arena,
  2171.         mi.ordblks,
  2172.         mi.smblks,
  2173.         mi.hblks,
  2174.         mi.hblkhd,
  2175.         mi.usmblks,
  2176.         mi.fsmblks,
  2177.         mi.uordblks,
  2178.         mi.fordblks,
  2179.         mi.keepcost
  2180.     );
  2181. #else
  2182. #if (LIBMALLOC == DEBUG_MALLOC)
  2183.     printf("malloc_chain_check: %d\n\n", malloc_chain_check(0));
  2184.     if (argc > 1)
  2185.         malloc_dump(1);
  2186.     printf("malloc_inuse: %lu\n", malloc_inuse(NULL));
  2187. #else
  2188.     printf("Nothing to report.\n");
  2189. #endif    /* (LIBMALLOC == DEBUG_MALLOC) */
  2190. #endif    /* (LIBMALLOC == FAST_MALLOC) */
  2191.  
  2192.     return (0);
  2193. }    /* MallocStatusCmd */
  2194. #endif    /* LIBMALLOC */
  2195.  
  2196.  
  2197.  
  2198.  
  2199. /*ARGSUSED*/
  2200. int unimpl(int argc, char **argv)
  2201. {
  2202.     if (!parsing_rc)
  2203.         (void) printf("%s: command not supported. (and probably won't ever be).\n", argv[0]);
  2204.     return (NOERR);
  2205. }    /* unimpl */
  2206.  
  2207. #ifdef PASSIVEMODE
  2208. int setpassive(int argc, char **argv)
  2209. {
  2210.     passivemode = !passivemode;
  2211.     printf( "Passive mode %s.\n", (passivemode ? "ON" : "OFF") );
  2212.     return NOERR;
  2213. }
  2214. #endif
  2215.  
  2216.  
  2217. /* eof cmds.c */
  2218.