home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / mm / mm-ccmd-0.91-20031017.tar.gz / mm-ccmd-0.91-20031017.tar / work / mm / print.c < prev    next >
C/C++ Source or Header  |  2002-09-18  |  12KB  |  434 lines

  1. /*
  2.  * Copyright (c) 1986, 2002 by The Trustees of Columbia University in
  3.  * the City of New York.  Permission is granted to any individual or
  4.  * institution to use, copy, or redistribute this software so long as it
  5.  * is not sold for profit, provided this copyright notice is retained.
  6.  */
  7.  
  8. #ifndef lint
  9. static char *rcsid = "$Header: /f/src2/encore.bin/cucca/mm/tarring-it-up/RCS/print.c,v 2.1 90/10/04 18:25:35 melissa Exp $";
  10. #endif
  11.  
  12. #include "mm.h"
  13. #include "parse.h"
  14. #include "cmds.h"
  15.  
  16. #define NULLSWIT 0
  17. #define HEADERS_ONLY 1
  18. #define SEPARATE_PAGES 2
  19. #define DOWNLOAD_FILE 3
  20.  
  21. /*
  22.  * cmd_list:
  23.  * list messages to file or pipe.
  24.  * a combination of the MM-20 LIST and FILE-LIST commands.
  25.  */
  26.  
  27. int
  28. cmd_list (n)
  29. int n;
  30. {
  31.     int sw = NULLSWIT;
  32.     static char *listdest = NULL;
  33.     char *parse_listfile();
  34.     FILE *od, *mm_popen(), *fopen();
  35.     int pipep;
  36.     int last_message;
  37.     message *m;
  38.     char *msgtxt, *fmt_message();
  39.     keylist only, dont;
  40.     int seq;
  41.  
  42.     if (listdest != NULL) {        /* catch the memory leak */
  43.     free (listdest);
  44.     listdest = NULL;
  45.     }
  46.  
  47.     if (!check_cf(O_RDONLY))        /* have to have a current file */
  48.     return;
  49.     noise ("to");
  50.     listdest = parse_listfile(&sw);    /* get destination file/pipe */
  51.     seq = parse_sequence("current",NULL,NULL); /* get a sequence */
  52.  
  53.     /*
  54.      * NOTE:
  55.      * If seq is TRUE (we parsed a sequence from the top level)
  56.      * then we want to check that there is something in the sequence,
  57.      * so we call sequence_start.
  58.      * If seq is FALSE we want to print the current message and DO NOT
  59.      * want to call sequence_start or sequence_next down in the while().
  60.      */
  61.     if (!seq || sequence_start(cf->sequence)) {    /* do we have a sequence? */
  62.     last_message = sequence_last (cf->sequence); /* remember last msg */
  63.  
  64.     if (listdest == NULL) {        /* /print */
  65.         pipep = true;
  66.         if (strlen(print_filter) == 0)
  67.         cmerr ("no print filter - use SET PRINT-FILTER to define one");
  68.         od = mm_popen (print_filter, "w");
  69.     }
  70.     else if (listdest[0] == '|' && listdest[1] == ' ') { /* pipe */
  71.         pipep = true;
  72.         od = mm_popen (listdest+2, "w"); /* open the pipe */
  73.     }
  74.     else {
  75.         pipep = false;
  76.         od = fopen (listdest, "w");    /* open the output file */
  77.     }
  78.  
  79.     if (od == NULL) {        /* do we have an output descriptor */
  80.         if (pipep)
  81.         cmxeprintf ("?could not start process %s\n", listdest+2);
  82.         else
  83.         perror (listdest);
  84.         free (listdest);        /* clean up */
  85.         listdest = NULL;
  86.         return false;
  87.     }
  88.  
  89.     /* title (filename and date of listing) */
  90.     fprintf (od, "-- Messages from file: %s --\n", cf->filename);
  91.     fprintf (od, "   %s\n\n", daytime(0));
  92.  
  93.     if ((sw == HEADERS_ONLY) || list_include_headers) {
  94.         do {            /* pass one for headers */
  95.         header_summary (cf->current, od); /* ta da! */
  96.         } while (seq && sequence_next (cf->sequence));
  97.     }
  98.  
  99.     if (sw != HEADERS_ONLY) {    /* message bodies too */
  100.         dont = (n == CMD_LITERAL) ? nil : dont_print_headers;
  101.         only = (n == CMD_LITERAL) ? nil : only_print_headers;
  102.         if (seq)
  103.             sequence_start (cf->sequence); /* same sequence */
  104.         fputc ('\n', od);        /* separate headers from messages */
  105.         fputc ('\f', od);        /* with a formfeed */
  106.         fputc ('\n', od);
  107.         do {            /* pass 2 for message body */
  108.         m = &cf->msgs[cf->current];
  109.         fprintf(od, "Message %d -- *********************\n",
  110.             cf->current);
  111.         if ((msgtxt = fmt_message(m, only, dont)) == NULL)
  112.             fputc ('\n', od);
  113.         else {
  114.             fwrite (msgtxt, sizeof(char), strlen(msgtxt), od);
  115.             fputc('\n', od);
  116.             free (msgtxt);
  117.         }
  118.         if (((sw == SEPARATE_PAGES) || list_on_separate_pages)
  119.             && (cf->current != last_message)) {
  120.             fputc ('\f', od);
  121.             fputc ('\n', od);
  122.         }
  123.         } while (seq && sequence_next (cf->sequence));
  124.     }
  125.     
  126.     if (pipep)            /* close up */
  127.         mm_pclose (od);
  128.     else
  129.         fclose (od);
  130.     if (mode == MM_TOP_LEVEL)    /* print that sequence so they */
  131.         seq_print (true);        /* know we did something */
  132.  
  133.     }
  134.  
  135.     if (listdest != NULL) {        /* clean up */
  136.     free (listdest);
  137.     listdest = NULL;
  138.     }
  139.     return true;            /* done! */
  140. }
  141.  
  142.  
  143. /*
  144.  * parse_listfile:
  145.  * parse for optional switches followed by a filename or '|' and command
  146.  * on return, the return value is either a filename or a command starting
  147.  * with "| ".
  148.  * Or, if it returns NULL, then the /print switch was parsed instead of
  149.  * a filename or command.
  150.  * sw may also be set.
  151.  * Note:
  152.  * caller is responsible of freeing the return value when done.
  153.  */
  154.  
  155. char *
  156. parse_listfile (sw)
  157. int *sw;                /* switch parsed if any */
  158. {
  159.     static keywrd swkeys[] = {
  160.     { "headers-only", 0, HEADERS_ONLY },
  161.     { "separate-pages", 0, SEPARATE_PAGES }
  162.     };
  163.     static keytab swtab = { sizeof(swkeys) / sizeof (keywrd), swkeys };
  164.     static fdb switches = { _CMSWI, 0, NULL, (pdat) &swtab, NULL, NULL, NULL };
  165.     static keywrd prkey[] = {
  166.     { "print", 0, 0 }
  167.     };
  168.     static keytab prtab = { sizeof(prkey) /sizeof (keywrd), prkey };
  169.     static fdb prfdb = { _CMSWI, 0, NULL, (pdat) &prtab, NULL, NULL, NULL };
  170.     static fdb filnam = { _CMFIL, CM_SDH|FIL_PO|FIL_VAL|FIL_NODIR, NULL, NULL, 
  171.                 "file to list to", NULL, NULL };
  172.     static fdb pipe = { _CMTOK, CM_SDH, NULL, (pdat) "|", 
  173.               "\"|\" followed by a quoted command line", 
  174.               NULL, NULL };
  175.     static fdb comm = { _CMQST, CM_SDH, NULL, NULL, "quoted command line",
  176.               NULL, NULL };
  177.     pval parseval;
  178.     fdb *used;
  179.     char *ret;
  180.  
  181.     *sw = NULLSWIT;
  182. #ifdef undef
  183.     pipe._cmdef = list_destination;    /* XXX add this var sometime */
  184. #endif /* undef */
  185.     parse (fdbchn(&switches, &prfdb, &pipe, &filnam, NULL), &parseval, &used);
  186.     if (used == &switches) {
  187.     *sw = parseval._pvint;
  188.     parse (fdbchn(&prfdb, &pipe, &filnam, NULL), &parseval, &used);
  189.     }
  190.  
  191.     if (used == &prfdb) {
  192.     return (NULL);
  193.     }
  194.     else if (used == &filnam) {
  195.     if (*parseval._pvfil[0] == '\0')
  196.         cmerr ("destination for output not specified");
  197.     ret = (char *) malloc (strlen(parseval._pvfil[0])+1);
  198.     strcpy (ret, parseval._pvfil[0]);
  199.     return (ret);
  200.     }
  201.     else {                /* if (used == &pipe)  */
  202.     parse (&comm, &parseval, &used);
  203.     ret = (char *) malloc (strlen(parseval._pvstr)+3);
  204.     sprintf (ret, "| %s", parseval._pvstr);
  205.     return (ret);
  206.     }
  207. }
  208.  
  209.  
  210. /*
  211.  * cmd_print:
  212.  */
  213.  
  214. int
  215. cmd_print (n)
  216. int n;
  217. {
  218.     static keywrd swkeys[] = {
  219.     { "separate-pages", 0, SEPARATE_PAGES }
  220.     };
  221.     static keytab swtab = { sizeof(swkeys) / sizeof (keywrd), swkeys };
  222.     static fdb switches = { _CMSWI, 0, NULL, (pdat) &swtab, NULL, NULL, NULL };
  223.     fdb *u;
  224.     FILE *pp, *mm_popen();
  225.     message *m;
  226.     char *msgtxt, *fmt_message();
  227.     keylist only, dont;
  228.     int seq;
  229.     int last_message;
  230.     int sw = NULLSWIT;
  231.  
  232.     if (!check_cf(O_RDONLY))        /* need a file of messages */
  233.     return;
  234.  
  235.     seq = parse_sequence("current", fdbchn(&switches,NULL), &u);
  236.     if (u != NULL) {
  237.     sw = pv._pvint;
  238.     seq = parse_sequence("current", NULL, NULL);
  239.     }
  240.  
  241.  
  242.     /*
  243.      * NOTE:  See NOTE in cmd_list
  244.      */
  245.     if (!seq || sequence_start(cf->sequence)) {    /* got a sequence? */
  246.     last_message = sequence_last (cf->sequence); /* remember last msg */
  247.  
  248.     if (strlen(print_filter) == 0)
  249.         cmerr ("no print filter - use SET PRINT-FILTER to define one");
  250.     if ((pp = mm_popen (print_filter, "w")) == NULL) {
  251.         cmxeprintf ("?could not start process %s\n", print_filter);
  252.         return false;
  253.     }
  254.     
  255.     dont = (n == CMD_LITERAL) ? nil : dont_print_headers;
  256.     only = (n == CMD_LITERAL) ? nil : only_print_headers;
  257.     do {
  258.         m = &cf->msgs[cf->current];
  259.         if ((msgtxt = fmt_message(m, only, dont)) == NULL)
  260.         fputc ('\n', pp);
  261.         else {
  262.         fwrite(msgtxt, sizeof(char), strlen(msgtxt), pp);
  263.         fputc('\n', pp);
  264.         free (msgtxt);
  265.         }
  266.         if (((sw == SEPARATE_PAGES) || list_on_separate_pages)
  267.         && (cf->current != last_message)) {
  268.         fputc ('\f', pp);
  269.         fputc ('\n', pp);
  270.         }
  271.     } while (seq && sequence_next (cf->sequence));
  272.     
  273.     mm_pclose (pp);
  274.     if (mode == MM_TOP_LEVEL)
  275.         seq_print (true);
  276.     }
  277.     return true;
  278. }
  279.  
  280. /* Code for downloading messages (fdc, Sep 2002) */
  281.  
  282. static brktab nambrk = {
  283. /* _CMFLD break table for foreign filename: */
  284. /* Allows letters, digits, hyphens (also +%_.!) */ 
  285.     {
  286. /*      0-7     8-15    16-23   24-31   32-39   40-47   48-55   56-63   */
  287.     0xff,   0xff,   0xff,   0xff,   0x80,   0x00,   0x00,   0x01,
  288.     0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x01
  289. /*      64-71   72-79   80-87   88-95   96-103  104-111 112-119 120-127 */
  290.     },
  291.     {
  292. #ifdef COMMENT
  293.     0xff, 0xff, 0xff, 0xff, 0xb2, 0xe8, 0x00, 0x3f,
  294.     0x80, 0x00, 0x00, 0x16, 0x80, 0x00, 0x00, 0x1f
  295. #else
  296.     0xff,   0xff,   0xff,   0xff,   0x80,   0x00,   0x00,   0x01,
  297.     0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x01
  298. #endif /* COMMENT */
  299.     }
  300. };
  301.  
  302. #define DNCMDBUF 511
  303.  
  304. int
  305. cmd_download (n)
  306. int n;
  307. {
  308.     static keywrd swkeys[] = {
  309.     { "filename:", 0, DOWNLOAD_FILE },
  310.     { "separate-pages", 0, SEPARATE_PAGES }
  311.     };
  312.     static keytab swtab = { sizeof(swkeys) / sizeof (keywrd), swkeys };
  313.     static fdb switches = { _CMSWI,0,NULL,(pdat)&swtab,NULL,NULL,NULL };
  314.     static fdb nametext = { _CMFLD,0,NULL,NULL,NULL,"mm_msg",&nambrk,NULL };
  315.     fdb *u, * u2;
  316.     pval parseval;
  317.     FILE *pp, *mm_popen();
  318.     message *m;
  319.     char *msgtxt, *fmt_message();
  320.     keylist only, dont;
  321.     int len, len2;
  322.     int seq;
  323.     int last_message;
  324.     int separate = 0;            /* Flag for /SEPARATE */
  325.     char dlname[DNCMDBUF+1];        /* User-provided filename */
  326.     char dlcmd[DNCMDBUF+1];        /* Constructed download command */
  327.  
  328.     if (!check_cf(O_RDONLY))        /* Need a file of messages */
  329.       return;
  330.  
  331.     dlname[0] = 0;            /* Stays empty if no /FILENAME: */
  332.     while (1) {                /* Parse switches or msg sequence */
  333.     seq = parse_sequence("current", fdbchn(&switches,NULL), &u);
  334.     if (!u)
  335.       break;
  336.     if (pv._pvint == DOWNLOAD_FILE) { /* If /FILENAME:, get arg */
  337.         parse(&nametext,&parseval,&u2);
  338.         strncpy(dlname,atmbuf,DNCMDBUF);
  339.         dlname[1023] = 0;
  340.     } else {
  341.         separate++;
  342.     }
  343.     }
  344.     if (!seq || sequence_start(cf->sequence)) {    /* got a sequence? */
  345.  
  346.     char * cp;
  347.     int count = 0;
  348.     int len3 = 0;
  349.  
  350.     last_message = sequence_last (cf->sequence); /* remember last msg */
  351.  
  352.     /* Get download filter and maybe plug filename into it */
  353.     /* Maybe more than once - but first make sure result is not too long */
  354.  
  355.     if ((len = strlen(download_filter)) == 0)
  356.       cmerr ("no download filter - use SET DOWNLOAD-FILTER to define one");
  357.     if (!dlname[0])
  358.       strncpy(dlname,"mm_msg",DNCMDBUF);
  359.     len2 = strlen(dlname);
  360.     len3 = len;
  361.     cp = dlname;
  362.     while ((cp = index(cp,'%'))) {
  363.         if (cp[1] == 's') {
  364.         count++;
  365.         len3 += (len2 - 2);
  366.         }
  367.         cp++;
  368.     }
  369.     if (len3 > DNCMDBUF-1 || count > 4)
  370.       cmerr ("download filter string too long");
  371.     sprintf(dlcmd,download_filter,dlname,dlname,dlname,dlname); /* SAFE */
  372.     dlname[1023] = 0;
  373.  
  374.     if ((pp = mm_popen (dlcmd, "w")) == NULL) {
  375.         cmxeprintf ("?could not start process: %s\n", download_filter);
  376.         return false;
  377.     }
  378.     dont = (n == CMD_LITERAL) ? nil : dont_print_headers;
  379.     only = (n == CMD_LITERAL) ? nil : only_print_headers;
  380.     do {
  381.         m = &cf->msgs[cf->current];
  382.         if ((msgtxt = fmt_message(m, only, dont)) == NULL)
  383.         fputc ('\n', pp);
  384.         else {
  385.         fwrite(msgtxt, sizeof(char), strlen(msgtxt), pp);
  386.         fputc('\n', pp);
  387.         free (msgtxt);
  388.         }
  389.         if ((separate || list_on_separate_pages)
  390.         && (cf->current != last_message)) {
  391.         fputc ('\f', pp);
  392.         fputc ('\n', pp);
  393.         }
  394.     } while (seq && sequence_next (cf->sequence));
  395.     
  396.     mm_pclose (pp);
  397.     if (mode == MM_TOP_LEVEL)
  398.       seq_print (true);
  399.     }
  400.     return true;
  401. }
  402.  
  403. /*
  404.  * cmd_literal:
  405.  * parse for downl/type/print/list (default type) and call appropriate command
  406.  */
  407.  
  408. cmd_literal(n)
  409. int n;
  410. {
  411.     static keywrd litkeys[] = {
  412.     { "download", 0, CMD_DOWNLOAD },
  413.     { "list",     0, CMD_LIST },
  414.     { "print",    0, CMD_PRINT },
  415.     { "type",     0, CMD_TYPE }
  416.     };
  417.     static keytab littab = { sizeof(litkeys) / sizeof (keywrd), litkeys };
  418.     static fdb litfdb = { _CMKEY, 0, NULL, (pdat) &littab, NULL,
  419.                   "type", NULL };
  420.     int seq;
  421.     fdb *u;
  422.  
  423.     if (!check_cf (O_RDONLY))        /* since we call parse_sequence */
  424.     return;
  425.     seq = parse_sequence ("current", fdbchn(&litfdb,NULL), &u);
  426.     if (u != NULL) {            /* parsed a command */
  427.     (void) (*mm_cmds[pv._pvkey]) (CMD_LITERAL);
  428.     }
  429.     else {                /* got a sequence */
  430.     check_mark();            /* default TYPE */
  431.     real_type (CMD_LITERAL, seq);
  432.     }
  433. }
  434.