home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / src / forms.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-03  |  10.8 KB  |  404 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: forms.c,v 5.3 1993/02/03 19:06:31 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.3 $   $State: Exp $
  6.  *
  7.  *            Copyright (c) 1988-1992 USENET Community Trust
  8.  *            Copyright (c) 1986,1987 Dave Taylor
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log: forms.c,v $
  17.  * Revision 5.3  1993/02/03  19:06:31  syd
  18.  * Remove extra strchr/strcat/strcpy et al declarations
  19.  * From: Syd
  20.  *
  21.  * Revision 5.2  1992/11/26  00:46:50  syd
  22.  * Fix how errno is used so err is inited and used instead
  23.  * as errno gets overwritten by print system call
  24.  * From: Syd
  25.  *
  26.  * Revision 5.1  1992/10/03  22:58:40  syd
  27.  * Initial checkin as of 2.4 Release at PL0
  28.  *
  29.  *
  30.  ******************************************************************************/
  31.  
  32. /** This set of files supports the 'forms' options (AT&T Mail Forms) to
  33.     the mail system.  The specs are drawn from a document from AT&T entitled
  34.     "Standard for Exchanging Forms on AT&T Mail", version 1.9.
  35.  
  36. **/
  37.  
  38. /** Some notes on the format of a FORM;
  39.  
  40.     First off, in AT&T Mail parlance, this program only supports SIMPLE
  41.     forms, currently.  This means that while each form must have three
  42.      sections;
  43.  
  44.         [options-section]
  45.         ***
  46.         [form-image]
  47.         ***
  48.         [rules-section]
  49.  
  50.     this program will ignore the first and third sections completely.  The
  51.     program will assume that the user merely enteres the form-image section,
  52.     and will append and prepend the triple asterisk sequences that *MUST*
  53.     be part of the message.  The messages are also expected to have a 
  54.     specific header - "Content-Type: mailform" - which will be added on all
  55.     outbound mail and checked on inbound...
  56. **/
  57.  
  58. #include "headers.h"
  59. #include "s_elm.h"
  60. #include <errno.h>
  61.  
  62. extern int errno;
  63.  
  64. char *error_description();
  65.  
  66. check_form_file(filename)
  67. char *filename;
  68. {
  69.     /** This routine returns the number of fields in the specified file,
  70.         or -1 if an error is encountered. **/
  71.  
  72.     FILE *form;
  73.     char buffer[SLEN];
  74.     register int field_count = 0;
  75.  
  76.     if ((form = fopen(filename, "r")) == NULL) {
  77.       error2(catgets(elm_msg_cat, ElmSet, ElmErrorOpeningCheckFields,
  78.           "Error %s trying to open %s to check fields!"),
  79.           error_description(errno), filename);
  80.       return(-1);
  81.     }
  82.     
  83.     while (mail_gets(buffer, SLEN, form)) {
  84.       field_count += occurances_of(COLON, buffer);
  85.     }
  86.  
  87.     fclose(form);
  88.  
  89.     return(field_count);
  90. }
  91.  
  92. format_form(filename)
  93. char *filename;
  94. {
  95.     /** This routine accepts a validated file that is the middle 
  96.         section of a form message and prepends and appends the appropriate 
  97.         instructions.  It's pretty simple. 
  98.         This returns the number of forms in the file, or -1 on errors
  99.     **/
  100.     
  101.     FILE *form, *newform;
  102.     char  newfname[SLEN], buffer[SLEN];
  103.     register int form_count = 0;
  104.     int  len_buf, err;
  105.  
  106.     dprint(4, (debugfile, "Formatting form file '%s'\n", filename));
  107.  
  108.     /** first off, let's open the files... **/
  109.  
  110.     if ((form = fopen(filename, "r")) == NULL) {
  111.       err = errno;
  112.       error(catgets(elm_msg_cat, ElmSet, ElmCantReadMessageToValidate,
  113.         "Can't read the message to validate the form!"));
  114.       dprint(1, (debugfile,
  115.               "** Error encountered opening file \"%s\" - %s (check_form) **\n",
  116.           filename, error_description(err)));
  117.       return(-1);
  118.     }
  119.  
  120.     sprintf(newfname, "%s%s%d", temp_dir, temp_form_file, getpid());
  121.  
  122.     if ((newform = fopen(newfname, "w")) == NULL) {
  123.       err = errno;
  124.       error(catgets(elm_msg_cat, ElmSet, ElmCouldntOpenNewformOutput,
  125.         "Couldn't open newform file for form output!"));
  126.       dprint(1, (debugfile, 
  127.               "** Error encountered opening file \"%s\" - %s (check_form) **\n",
  128.           newfname, error_description(err)));
  129.       return(-1);
  130.     }
  131.  
  132.     /** the required header... **/
  133.  
  134.     /* these are actually the defaults, but let's be sure, okay? */
  135.  
  136.     fprintf(newform, "WIDTH=78\nTYPE=SIMPLE\nOUTPUT=TEXT\n***\n");
  137.  
  138.     /** and let's have some fun transfering the stuff across... **/
  139.  
  140.     while (len_buf = mail_gets(buffer, SLEN, form)) {
  141.       fwrite(buffer, 1, len_buf, newform);
  142.       form_count += occurances_of(COLON, buffer);
  143.     }
  144.  
  145.     fprintf(newform, "***\n");    /* that closing bit! */
  146.  
  147.     fclose(form);
  148.     fclose(newform);
  149.  
  150.     if (form_count > 0) {
  151.       if (unlink(filename) != 0) {
  152.         error2(catgets(elm_msg_cat, ElmSet, ElmErrorUnlinkingFile,
  153.         "Error %s unlinking file %s."),
  154.         error_description(errno), filename);
  155.         return(-1);
  156.       }
  157.       if (link(newfname, filename)) {
  158.         error3(catgets(elm_msg_cat, ElmSet, ElmErrorLinkingFile,
  159.         "Error %s linking %s to %s."),
  160.             error_description(errno), newfname, filename);
  161.         return(-1);
  162.       }
  163.     }
  164.  
  165.     if (unlink(newfname)) {
  166.       error2(catgets(elm_msg_cat, ElmSet, ElmErrorUnlinkingFile,
  167.             "Error %s unlinking file %s."),
  168.         error_description(errno), newfname);
  169.       return(-1);    
  170.     }
  171.  
  172.     return(form_count);
  173. }
  174.  
  175. int
  176. mail_filled_in_form(address, subject)
  177. char *address, *subject;
  178. {
  179.     /** This is the interesting routine.  This one will read the
  180.         message and prompt the user, line by line, for each of
  181.         the fields...returns non-zero if it succeeds
  182.     **/
  183.  
  184.     FILE           *fd;
  185.     register int lines = 0, count, len_buf, max_lines;
  186.     char         buffer[SLEN];
  187.  
  188.     dprint(4, (debugfile, 
  189.         "replying to form with;\n\taddress=%s and\n\t subject=%s\n",
  190.          address, subject));
  191.  
  192.         if (fseek(mailfile, headers[current-1]->offset, 0) == -1) {
  193.       dprint(1, (debugfile,
  194.            "Error: seek %ld resulted in errno %s (%s)\n", 
  195.            headers[current-1]->offset, error_description(errno), 
  196.            "mail_filled_in_form"));
  197.       error2(catgets(elm_msg_cat, ElmSet, ElmSeekFailedFile,
  198.         "ELM [seek] couldn't read %d bytes into file (%s)."),
  199.              headers[current-1]->offset, error_description(errno));
  200.       return(0);
  201.         }
  202.  
  203.     /* now we can fly along and get to the message body... */
  204.  
  205.     max_lines = headers[current-1]->lines;
  206.     while (len_buf = mail_gets(buffer, SLEN, mailfile)) {
  207.       if (len_buf == 1)    /* <return> only */
  208.         break;
  209.       else if (lines >= max_lines) { 
  210.         error(catgets(elm_msg_cat, ElmSet, ElmNoFormInMessage,
  211.         "No form in this message!?"));
  212.         return(0);
  213.       }
  214.  
  215.       if (buffer[len_buf - 1] == '\n')
  216.         lines++;
  217.     }
  218.  
  219.     if (len_buf == 0) {
  220.       error(catgets(elm_msg_cat, ElmSet, ElmNoFormInMessage,
  221.           "No form in this message!?"));
  222.       return(0);
  223.     }
  224.  
  225.     dprint(6, (debugfile, "- past header of form message -\n"));
  226.     
  227.     /* at this point we're at the beginning of the body of the message */
  228.  
  229.     /* now we can skip to the FORM-IMAGE section by reading through a 
  230.        line with a triple asterisk... */
  231.  
  232.     while (len_buf = mail_gets(buffer, SLEN, mailfile)) {
  233.       if (strcmp(buffer, "***\n") == 0)
  234.         break;    /* we GOT it!  It's a miracle! */    
  235.  
  236.       if (buffer[len_buf - 1] == '\n')
  237.         lines++;
  238.  
  239.       if (lines >= max_lines) {
  240.         error(catgets(elm_msg_cat, ElmSet, ElmBadForm,
  241.         "Badly constructed form.  Can't reply!"));
  242.         return(0);
  243.       }
  244.     }
  245.  
  246.     if (len_buf == 0) {
  247.       error(catgets(elm_msg_cat, ElmSet, ElmBadForm,
  248.         "Badly constructed form.  Can't reply!"));
  249.       return(0);
  250.     }
  251.  
  252.     dprint(6, (debugfile, "- skipped the non-forms-image stuff -\n"));
  253.     
  254.     /* one last thing - let's open the tempfile for output... */
  255.     
  256.     sprintf(buffer, "%s%s%d", temp_dir, temp_form_file, getpid());
  257.  
  258.     dprint(2, (debugfile,"-- forms sending using file %s --\n", buffer));
  259.  
  260.     if ((fd = fopen(buffer,"w")) == NULL) {
  261.       error2(catgets(elm_msg_cat, ElmSet, ElmCantOpenAsOutputFile,
  262.         "Can't open \"%s\" as output file! (%s)."),
  263.         buffer, error_description(errno));
  264.       dprint(1, (debugfile,
  265.           "** Error %s encountered trying to open temp file %s;\n",
  266.           error_description(errno), buffer));
  267.       return(0);
  268.     }
  269.  
  270.     /* NOW we're ready to read the form image in and start prompting... */
  271.  
  272.     Raw(OFF);
  273.     ClearScreen();
  274.  
  275.     while (len_buf = mail_gets(buffer, SLEN, mailfile)) {
  276.       dprint(9, (debugfile, "- read %s", buffer));
  277.       if (strcmp(buffer, "***\n") == 0) /* end of form! */
  278.         break;
  279.  
  280.       if (buffer[len_buf - 1] == '\n')
  281.         lines++;
  282.      
  283.       if (lines > max_lines)
  284.         break; /* end of message */
  285.  
  286.       switch ((count = occurances_of(COLON, buffer))) {
  287.         case 0 : fwrite(buffer, 1, len_buf, stdout);    /* output line */
  288.              fwrite(buffer, 1, len_buf, fd);     
  289.              break;
  290.             case 1 : if (buffer[0] == COLON) {
  291.                    printf(catgets(elm_msg_cat, ElmSet, ElmEnterAsManyLines,
  292. "(Enter as many lines as needed, ending with a '.' by itself on a line)\n"));
  293.                        while (fgets(buffer, SLEN, stdin) != NULL) {
  294.                  no_ret(buffer);
  295.                      if (strcmp(buffer, ".") == 0)
  296.                        break;
  297.                      else 
  298.                fprintf(fd,"%s\n", buffer);
  299.                }
  300.                  }
  301.                  else 
  302.                prompt_for_entries(buffer, fd, count);
  303.                  break;
  304.             default: prompt_for_entries(buffer, fd, count);
  305.       }
  306.     }
  307.  
  308.     Raw(ON);
  309.     fclose(fd);
  310.  
  311.     /** let's just mail this off now... **/
  312.  
  313.     mail_form(address, subject);
  314.  
  315.     return(1);
  316. }
  317.  
  318. prompt_for_entries(buffer, fd, entries)
  319. char *buffer;
  320. FILE *fd;
  321. int  entries;
  322. {
  323.     /** deals with lines that have multiple colons on them.  It must first
  324.         figure out how many spaces to allocate for each field then prompts
  325.         the user, line by line, for the entries...
  326.     **/
  327.  
  328.     char mybuffer[SLEN], prompt[SLEN], spaces[SLEN];
  329.     register int  field_size, i, j, offset = 0, extra_tabs = 0;
  330.  
  331.     dprint(7, (debugfile, 
  332.         "prompt-for-multiple [%d] -entries \"%s\"\n", entries,
  333.         buffer));
  334.  
  335.     strcpy(prompt, catgets(elm_msg_cat, ElmSet, ElmFormNoPrompt,
  336.         "No Prompt Available:"));
  337.  
  338.     while (entries--) {
  339.       j=0; 
  340.       i = chloc((char *) buffer + offset, COLON) + 1;
  341.       while (j < i - 1) {
  342.         prompt[j] = buffer[j+offset];
  343.         j++;
  344.       }
  345.       prompt[j] = '\0';
  346.  
  347.       field_size = 0;
  348.  
  349.       while (whitespace(buffer[i+offset])) {
  350.         if (buffer[i+offset] == TAB) {
  351.           field_size += 8 - (i % 8);
  352.           extra_tabs += (8 - (i % 8)) - 1;
  353.         }
  354.         else
  355.           field_size += 1;
  356.         i++;
  357.       }
  358.  
  359.       offset += i;
  360.     
  361.       if (field_size == 0)     /* probably last prompt in line... */
  362.         field_size = 78 - (offset + extra_tabs);
  363.  
  364.       prompt_for_sized_entry(prompt, mybuffer, field_size);
  365.  
  366.       spaces[0] = ' ';    /* always at least ONE trailing space... */
  367.       spaces[1] = '\0';
  368.  
  369.       /*  field_size-1 for the space spaces[] starts with  */
  370.       for (j = strlen(mybuffer); j < field_size-1; j++)
  371.         strcat(spaces, " ");
  372.  
  373.       fprintf(fd, "%s: %s%s", prompt, mybuffer, spaces);
  374.       fflush(fd);
  375.     }
  376.  
  377.     fprintf(fd, "\n");
  378. }
  379.  
  380. prompt_for_sized_entry(prompt, buffer, field_size)
  381. char *prompt, *buffer;
  382. int   field_size;
  383. {
  384.     /* This routine prompts for an entry of the size specified. */
  385.  
  386.     register int i;
  387.  
  388.     dprint(7, (debugfile, "prompt-for-sized-entry \"%s\" %d chars\n", 
  389.         prompt, field_size));
  390.  
  391.     printf("%s: ", prompt);
  392.     
  393.     for (i=0;i<field_size; i++)
  394.       putchar('_');
  395.     for (i=0;i<field_size; i++)
  396.       putchar(BACKSPACE);
  397.     fflush(stdout);
  398.  
  399.     fgets(buffer, SLEN, stdin);
  400.     no_ret(buffer);
  401.  
  402.     if (strlen(buffer) > field_size) buffer[field_size-1] = '\0';
  403. }
  404.