home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume4 / unaxcess / part2 / msg.c < prev    next >
C/C++ Source or Header  |  1986-11-30  |  17KB  |  780 lines

  1. /*
  2.  * %W% %E% %U% ncoast!bsa %Z%
  3.  * %Z% Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved %Z%
  4.  */
  5.  
  6. #ifndef lint
  7. static char _SccsId[] = "%W% %E% %U% ncoast!bsa %Z%";
  8. static char _CopyRt[] = "%Z% Copyright (C) 1985 by Brandon S. Allbery %Z%";
  9. #endif  lint
  10.  
  11. #include "ua.h"
  12.  
  13. selmsg(s, fn)
  14.     char *s;
  15.     int (*fn)();
  16.     {
  17.     char line[256], *p;
  18.     short lomsg, himsg;
  19.     FILE *f;
  20.  
  21.     sprintf(line, "%s/%s/himsg", MSGBASE, conference);
  22.     if ((f = fopen(line, "r")) == NULL)
  23.     {
  24.     log("Error %d opening %s", errno, line);
  25.     if (strcmp(conference, "general") == 0)
  26.         {
  27.         panic("conf");
  28.         }
  29.     puts("I can't find the high message file.  Moving back to general...");
  30.     strcpy(conference, "general");
  31.     return 1;
  32.     }
  33.     fgets(line, 32, f);
  34.     fclose(f);
  35.     himsg = atoi(line);
  36.     for (p = s; *p != 0; p++)
  37.     if (*p == ' ')
  38.         {
  39.         if (strcmp(++p, "new") == 0)
  40.         {
  41.         domsg(conference, 0, himsg, fn);
  42.         return 1;
  43.         }
  44.         else if ((lomsg = atoi(p)) < 1 || lomsg > himsg)
  45.         break;
  46.         else
  47.         {
  48.         domsg(conference, lomsg, lomsg, fn);
  49.         return 1;
  50.         }
  51.         }
  52.     printf("<F>orward, <R>everse, <I>ndividual, or <N>ew: ");
  53.     gets(line);
  54.     log("Mode: %s", line);
  55.     switch (line[0])
  56.     {
  57.     case 'F':
  58.     case 'f':
  59.         lomsg = 1;
  60.         break;
  61.     case 'R':
  62.     case 'r':
  63.         lomsg = himsg;
  64.         himsg = 1;
  65.         break;
  66.     case 'I':
  67.     case 'i':
  68.         printf("Enter message number: ");
  69.         gets(line);
  70.         log("Message: %s", line);
  71.         if ((lomsg = atoi(line)) < 1 || lomsg > himsg)
  72.         {
  73.         puts("No such message.");
  74.         log("No such message.");
  75.         return 1;
  76.         }
  77.         domsg(conference, lomsg, lomsg, fn);
  78.         return 1;
  79.     case 'N':
  80.     case 'n':
  81.         lomsg = 0;
  82.         break;
  83.     case '\0':
  84.         return 1;
  85.     default:
  86.         puts("What?");
  87.         log("Illegal search mode.");
  88.         return 1;
  89.     }
  90.     if (lomsg != 0)
  91.     {
  92.     printf("Starting message (%d): ", lomsg);
  93.     gets(line);
  94.     log("Start: %s", line);
  95.     if (line[0] != 0)
  96.         if (atoi(line) < 1 || (lomsg > 1 && atoi(line) > lomsg))
  97.         {
  98.         puts("Bad message number.");
  99.         log("Bad message number.");
  100.         return 1;
  101.         }
  102.         else
  103.         lomsg = atoi(line);
  104.     printf("Ending message (%d): ", himsg);
  105.     gets(line);
  106.     log("End: %s", line);
  107.     if (line[0] != 0)
  108.         if (atoi(line) < 1 || (himsg > 1 && atoi(line) > himsg))
  109.         {
  110.         puts("Bad message number.");
  111.         log("Bad message number.");
  112.         return 1;
  113.         }
  114.         else
  115.         himsg = atoi(line);
  116.     }
  117.     domsg(conference, lomsg, himsg, fn);
  118.     return 1;
  119.     }
  120.  
  121. readmsg(s)
  122.     char *s;
  123.     {
  124.     return selmsg(s, doread);
  125.     }
  126.  
  127. scanmsg(s)
  128.     char *s;
  129.     {
  130.     return selmsg(s, doscan);
  131.     }
  132.  
  133. doread(msg, conf, mnum)
  134.     char *msg, *conf;
  135.     short mnum;
  136.     {
  137.     char line[256];
  138.  
  139.     printf("\nMessage %d of %s:\n", mnum, conf);
  140.     if (isprivate(msg))
  141.     {
  142.     puts("This message is private.");
  143.     return 1;
  144.     }
  145.     cat(msg);
  146.  
  147. DR_Loop:
  148.     printf("\nContinue, Stop, Unsubscribe, or Reply (C): ");
  149.     if (!isatty(0) || nopause)
  150.     {
  151.     line[0] = '\0';
  152.     putchar('\n');
  153.     }
  154.     else
  155.     gets(line);
  156.     log("C/S/U/R: %s", line);
  157.     switch (line[0])
  158.     {
  159.     case 'c':
  160.     case 'C':
  161.     case '\0':
  162.         return 1;
  163.         case 'U':
  164.         case 'u':
  165.             unsubscribe(conf);
  166.             return 0;
  167.     case 's':
  168.     case 'S':
  169.         return 0;
  170.     case 'r':
  171.     case 'R':
  172.         reply(msg, conf);
  173.         goto DR_Loop;
  174.     default:
  175.         puts("What?  Please enter one of C, S, U, or R.");
  176.         goto DR_Loop;
  177.     }
  178.     }
  179.  
  180. msgok(file)
  181.     char *file;
  182.     {
  183.     FILE *fp;
  184.  
  185.     if ((fp = fopen(file, "r")) == NULL)
  186.     return 0;
  187.     fclose(fp);
  188.     return 1;
  189.     }
  190.  
  191. doscan(msg, conf, mnum)
  192. char *msg, *conf;
  193. short mnum; {
  194.     char line[1024];
  195.     FILE *f;
  196.     short dflag, fflag, tflag, sflag;
  197.  
  198.     if ((f = fopen(msg, "r")) == NULL) {
  199.     puts("Cannot open file.");
  200.     log("Error %d opening %s", errno, msg);
  201.     return 1;
  202.     }
  203.     printf("\nMessage %d of %s: \n", mnum, conf);
  204.     dflag = fflag = tflag = sflag = 0;
  205.     if (isprivate(msg))
  206.     puts("Message is private.");
  207.     else {
  208.     while (fgets(line, 1024, f) != NULL) {
  209.         if (line[0] == '\n')
  210.         break;
  211.         if (!dflag && strncmp(line, "Date: ", 6) == 0) {
  212.         printf("%s", line);
  213.         dflag++;
  214.         continue;
  215.         }
  216.         if (!fflag && strncmp(line, "From: ", 6) == 0) {
  217.         printf("%s", line);
  218.         fflag++;
  219.         continue;
  220.         }
  221.         if (!tflag && strncmp(line, "To: ", 4) == 0) {
  222.         printf("%s", line);
  223.         tflag++;
  224.         continue;
  225.         }
  226.         if (!sflag && strncmp(line, "Subject: ", 9) == 0) {
  227.         printf("%s", line);
  228.         sflag++;
  229.         continue;
  230.         }
  231.         if (!sflag && strncmp(line, "Subject (Private): ", 19) == 0) {
  232.         printf("%s", line);
  233.         sflag++;
  234.         continue;
  235.         }
  236.     }
  237.         if (!tflag)
  238.         puts("To: All");
  239.     }
  240.     fclose(f);
  241.     puts("--------------------------------");
  242.     if (mnum % 3 == 0)    /* kludged, but there isn't an easy fix without */
  243.         if (!cont())    /* rewriting the I/O system. */
  244.             longjmp(cmdloop, 1);    /* also a kludge... */
  245.     return 1;
  246.     }
  247.  
  248. domsg(conf, lomsg, himsg, fn)
  249.     char *conf;
  250.     short lomsg, himsg;
  251.     int (*fn)();
  252.     {
  253.     short mcnt;
  254.     char tmps[256];
  255.     struct _himsg *ptr, *lastp;
  256.  
  257.     for (ptr = hicnts, lastp = NULL; ptr != NULL; lastp = ptr, ptr = ptr->hi_next)
  258.     if (strcmp(conf, ptr->hi_conf) == 0)
  259.         break;
  260.     if (ptr == NULL)
  261.     {
  262.     if ((ptr = (struct _himsg *) calloc((unsigned) 1, sizeof (struct _himsg))) == NULL)
  263.         {
  264.         log("Error %d allocating _himsg for %s", errno, conf);
  265.         panic("alloc");
  266.         }
  267.     ptr->hi_next = hicnts;
  268.         hicnts = ptr;
  269.         ptr->hi_uns = HI_SUBSCR;
  270.     strcpy(ptr->hi_conf, conf);
  271.     ptr->hi_num = 0;
  272.     }
  273.     if (lomsg == 0)            /* read new messages */
  274.     for (mcnt = ptr->hi_num + 1; mcnt <= himsg; mcnt++)
  275.         {
  276.         sprintf(tmps, "%s/%s/%d", MSGBASE, conf, mcnt);
  277.         if (msgok(tmps) <= 0)
  278.         continue;
  279.         if (!(*fn)(tmps, conf, mcnt))
  280.         break;
  281.         }
  282.     else if (lomsg <= himsg)        /* forward or individual read */
  283.     for (mcnt = lomsg; mcnt <= himsg; mcnt++)
  284.         {
  285.         sprintf(tmps, "%s/%s/%d", MSGBASE, conf, mcnt);
  286.         if (msgok(tmps) <= 0)
  287.         continue;
  288.         if (!(*fn)(tmps, conf, mcnt))
  289.         break;
  290.         }
  291.     else
  292.     for (mcnt = lomsg; mcnt >= himsg; mcnt--)
  293.         {
  294.         sprintf(tmps, "%s/%s/%d", MSGBASE, conf, mcnt);
  295.         if (msgok(tmps) <= 0)
  296.         continue;
  297.         if (!(*fn)(tmps, conf, mcnt))
  298.         break;
  299.         }
  300.     ptr->hi_num = himsg;
  301.     writehigh(hicnts);
  302.     }
  303.  
  304. readnew()
  305.     {
  306.     DIR *dp;
  307.     struct direct *dirp;
  308.     FILE *hp;
  309.     short himsg;
  310.     char line[256];
  311.  
  312.     if ((dp = opendir(MSGBASE)) == NULL)
  313.     {
  314.     log("Error %d reading dir %s/", errno, MSGBASE);
  315.     panic("msgdir");
  316.     }
  317.     while ((dirp = readdir(dp)) != NULL)
  318.     {
  319.     if (dirp->d_name[0] == '.')
  320.         continue;
  321.         if (isunsub(dirp->d_name))
  322.             continue;
  323.     printf("\nExamining conference %s...\n", dirp->d_name);
  324.     log("Reading %s.", dirp->d_name);
  325.     if (parms.ua_xrc && dirp->d_name[0] == 'x' && dirp->d_name[1] == '-')
  326.         {
  327.             if (user.u_access == A_GUEST) {
  328.                 log("Guest skipping Restricted conference.");
  329.                 continue;
  330.             }
  331.         printf("This conference is Restricted (X-RATED).  The material within may not be\nsuitable for, or acceptable to, some users.\n\nDo you wish to skip it (Y)? ");
  332.         if (!isatty(0) || nopause)
  333.         {
  334.         line[0] = '\0';
  335.         putchar('\n');
  336.         }
  337.         else
  338.         gets(line);
  339.         log("Restricted.  Skip? %s", line);
  340.         if (ToLower(line[0]) != 'n')
  341.         continue;
  342.         }
  343.     sprintf(line, "%s/%s/himsg", MSGBASE, dirp->d_name);
  344.     if ((hp = fopen(line, "r")) == NULL)
  345.         {
  346.         log("Error %d opening %s", errno, line);
  347.         puts("Can't open high message file.");
  348.         continue;
  349.         }
  350.     fgets(line, 32, hp);
  351.     fclose(hp);
  352.     himsg = atoi(line);
  353.     domsg(dirp->d_name, 0, himsg, doread);
  354.     
  355.     RN_Loop:
  356.     printf("\nNext conference, Unsubscribe, or Stop (N): ");
  357.     if (!isatty(0) || nopause)
  358.         {
  359.         putchar('\n');
  360.         line[0] = '\0';
  361.         }
  362.     else
  363.         gets(line);
  364.     log("Next/Unsub/Stop: %s", line);
  365.     switch (line[0])
  366.         {
  367.         case 'N':
  368.         case 'n':
  369.         case '\0':
  370.         break;
  371.         case 'U':
  372.         case 'u':
  373.             unsubscribe(dirp->d_name);
  374.             break;
  375.         case 'S':
  376.         case 's':
  377.         closedir(dp);
  378.         return 1;
  379.         default:
  380.         puts("Please enter one of N, U, or S.");
  381.         goto RN_Loop;
  382.         }
  383.     }
  384.     closedir(dp);
  385.     return 1;
  386.     }
  387.  
  388. enter(s)
  389.     char *s;
  390.     {
  391.     char to[256], subj[256], *p, line[256];
  392.     short pflag;
  393.  
  394.     if (user.u_access == A_GUEST && strcmp(conference, "guest") != 0)
  395.     {
  396.     log("Security violation:  GUEST entering messages.");
  397.     puts("You aren't allowed to enter messages in this conference.");
  398.     return 1;
  399.     }
  400.     for (p = s; *p != '\0'; p++)
  401.     if (*p == ' ')
  402.         {
  403.         strcpy(to, ++p);
  404.         break;
  405.         }
  406.     if (*p == '\0')
  407.     {
  408.     printf("Who is this message to (ALL)? ");
  409.     gets(line);
  410.     log("To: %s", line);
  411.     if (line[0] == '\0')
  412.         strcpy(line, "all");
  413.     for (p = line; *p != '\0'; p++)
  414.         *p = ToLower(*p);
  415.     strcpy(to, line);
  416.     }
  417.     printf("Subject: ");
  418.     gets(line);
  419.     strcpy(subj, line);
  420.     log("Subject: %s", line);
  421.     pflag = 0;
  422.     if (parms.ua_pm) {
  423.         printf("Is this message to be private (N)? ");
  424.         gets(line);
  425.         log("Private? %s", line);
  426.         if (ToLower(line[0]) == 'y')
  427.         pflag = 1;
  428.     }
  429.     mkmsg(to, subj, conference, pflag);
  430.     return 1;
  431.     }
  432.  
  433. reply(msg, conf)
  434.     char *msg, *conf;
  435.     {
  436.     char to[256], subj[256], line[1024], rconf[256];
  437.     short fflag, sflag, pflag;
  438.     FILE *f;
  439.  
  440.     if (user.u_access == A_GUEST && strcmp(conf, "guest") != 0)
  441.     {
  442.     log("Security violation:  GUEST entering messages");
  443.     puts("You aren't allowed to enter messages.");
  444.     return;
  445.     }
  446.     if ((f = fopen(msg, "r")) == NULL)
  447.     {
  448.     log("Error %d opening %s", errno, msg);
  449.     puts("Can't re-open message file.");
  450.     return;
  451.     }
  452.     fflag = sflag = 0;
  453.     strcpy(to, "All\n");
  454.     strcpy(subj, "Re: Orphaned Response\n");    /* now you know... */
  455.     while (fgets(line, 1024, f) != NULL)
  456.     {
  457.     if (line[0] == '\n')
  458.         break;
  459.     if (!fflag && strncmp(line, "From: ", 6) == 0)
  460.         {
  461.         strcpy(to, &line[6]);
  462.         fflag++;
  463.         continue;
  464.         }
  465.     if (!sflag && strncmp(line, "Subject: ", 9) == 0)
  466.         {
  467.         if (strncmp(&line[9], "Re: ", 4) == 0)
  468.         strcpy(subj, &line[9]);
  469.         else
  470.         strcpy(&subj[4], &line[9]);
  471.         sflag++;
  472.         continue;
  473.         }
  474.     if (!sflag && strncmp(line, "Subject (Private): ", 19) == 0)
  475.         {
  476.         if (strncmp(&line[19], "Re: ", 4) == 0)
  477.         strcpy(subj, &line[19]);
  478.         else
  479.         strcpy(&subj[4], &line[19]);
  480.         sflag++;
  481.         continue;
  482.         }
  483.     }
  484.     fclose(f);
  485.     to[strlen(to) - 1] = '\0';            /* get rid of trailing nl */
  486.     subj[strlen(subj) - 1] = '\0';
  487.     printf("What conference do you wish this reply to be in (%s): ", conf);
  488.     gets(line);
  489.     if (line[0] != '\0' && verify(line))
  490.     {
  491.     strcpy(rconf, line);
  492.     conf = rconf;
  493.     }
  494.     pflag = 0;
  495.     if (parms.ua_pm) {
  496.         printf("Is this message to be private (N)? ");
  497.         gets(line);
  498.         log("Private? %s", line);
  499.         if (ToLower(line[0]) == 'y')
  500.         pflag = 1;
  501.     }
  502.     mkmsg(to, subj, conf, pflag);
  503.     }
  504.  
  505. mkmsg(to, subj, conf, ispriv)
  506.     char *to, *subj, *conf;
  507.     {
  508.     static char lockfile[] = "msgbase.lock";
  509.     char *tempfile = mktemp("/tmp/UAmXXXXXX");
  510.     FILE *mfp, *sfp;
  511.     char line[1024], *p;
  512.     long clock;
  513.     short mcnt;
  514.     struct tm *ltbuf;
  515.     struct user ubuf;
  516.  
  517.     if (parms.ua_roc && conf[0] == 'r' && conf[1] == '-')
  518.     {
  519.     conf = "general";            /* responses get redirected */
  520.     puts("Read-only conference; message will be added to \"general\".");
  521.     }
  522.     if (ispriv && !getuser(to, &ubuf))
  523.     {
  524.     printf("Can't send private message to \"%s\"; he's unregistered.\n", to);
  525.     log("Attempted private message to unregistered user.");
  526.     return 0;
  527.     }
  528.     if ((mfp = fopen(tempfile, "w")) == NULL)
  529.     {
  530.     log("Error %d opening %s", errno, tempfile);
  531.     panic("tmp");
  532.     }
  533.     for (p = to; *p != '\0'; p++)
  534.     *p = ToUpper(*p);
  535.     fprintf(mfp, "To: %s\nSubject%s: %s\n\n", to, (ispriv? " (Private)": ""), subj);
  536.     fclose(mfp);
  537.     input(tempfile);
  538.     for (;;)
  539.     {
  540.     printf("\nEdit command (L, C, E, S, or A): ");
  541.     gets(line);
  542.     log("Edit command: %s", line);
  543.     switch (line[0])
  544.         {
  545.         case 'l':
  546.         case 'L':
  547.         cat(tempfile);
  548.         break;
  549.         case 'c':
  550.         case 'C':
  551.         input(tempfile);
  552.         break;
  553.         case 'e':
  554.         case 'E':
  555.         if (user.u_access == A_SYSTEM || user.u_access == A_WITNESS)
  556.             xedit(tempfile);
  557.         else
  558.             edit(tempfile);
  559.         break;
  560.         case 'a':
  561.         case 'A':
  562.         printf("Do you really want to abort this edit (N)? ");
  563.         gets(line);
  564.         log("Abort? %s", line);
  565.         if (ToLower(line[0]) == 'y')
  566.             {
  567.             unlink(tempfile);
  568.             return 0;
  569.             }
  570.         break;
  571.         case '?':
  572.         puts("Editor commands:\nL - List message\nC - Continue message entry\nE - Edit message\nS - Save message\nA - Abort message");
  573.         break;
  574.         case '\0':
  575.         break;
  576.         case 's':
  577.         case 'S':
  578.         puts("Saving message...");
  579.         mklock(lockfile);
  580.         sprintf(line, "%s/%s/himsg", MSGBASE, conf);
  581.         if ((sfp = fopen(line, "r")) == NULL)
  582.             {
  583.             log("Error %d opening %s", errno, line);
  584.             rmlock(lockfile);
  585.             unlink(tempfile);
  586.             panic("himsg");
  587.             }
  588.         fgets(line, 32, sfp);
  589.         fclose(sfp);
  590.         mcnt = atoi(line) + 1;
  591.         sprintf(line, "%s/%s/%d", MSGBASE, conf, mcnt);
  592.         if ((sfp = fopen(line, "w")) == NULL)
  593.             {
  594.             log("Error %d opening %s", errno, line);
  595.             unlink(tempfile);
  596.             rmlock(lockfile);
  597.             panic("msg");
  598.             }
  599.         fprintf(sfp, "Date: %s\nFrom: ", longdate());
  600.         for (p = user.u_name; *p != '\0'; p++)
  601.             putc(ToUpper(*p), sfp);
  602.         putc('\n', sfp);
  603.         if ((mfp = fopen(tempfile, "r")) == NULL)
  604.             {
  605.             fclose(sfp);
  606.             log("Error %d opening %s", errno, tempfile);
  607.             unlink(tempfile);
  608.             unlink(line);
  609.             rmlock(lockfile);
  610.             panic("tmp");
  611.             }
  612.         while (fgets(line, 1024, mfp) != NULL)
  613.             fputs(line, sfp);
  614.         fclose(sfp);
  615.         fclose(mfp);
  616.         unlink(tempfile);
  617.         sprintf(line, "%s/%s/himsg", MSGBASE, conf);
  618.         if ((sfp = fopen(line, "w")) == NULL)
  619.             {
  620.             log("Error %d opening %s", errno, line);
  621.             panic("himsg");
  622.             }
  623.         fprintf(sfp, "%d\n", mcnt);
  624.         fclose(sfp);
  625.         rmlock(lockfile);
  626.         return 1;
  627.         default:
  628.         puts("Please enter L, C, E, S, or A; or ? for help.");
  629.         }
  630.     }
  631.     }
  632.  
  633. input(file)
  634.     char *file;
  635.     {
  636.     FILE *fp;
  637.     char line[256], *p;
  638.  
  639.     if ((fp = fopen(file, "a")) == NULL)
  640.     {
  641.     log("Error %d opening %s", errno, file);
  642.     unlink(file);
  643.     panic("tmp");
  644.     }
  645.     puts("\nEnter your text now.  End it with a slash on a line by itself.\n");
  646.     log("Entering text...");
  647.     for (;;)
  648.     {
  649.     printf("] ");
  650.     if (gets(line) == NULL)
  651.         {
  652.         log("Illegal character: EOF");
  653.         clearerr(stdin);            /* 4.2 brain damage fix */
  654.         continue;
  655.         }
  656.     if (strcmp(line, "/") == 0)
  657.         break;
  658.     for (p = line; *p != '\0'; p++)
  659.         if (iscntrl(*p) && *p != '\t')
  660.         {
  661.         log("Illegal character: ^%c", uncntrl(*p));
  662.         putc('^', fp);
  663.         putc(uncntrl(*p), fp);
  664.         }
  665.         else
  666.         putc(*p, fp);
  667.     putc('\n', fp);
  668.     }
  669.     fclose(fp);
  670.     }
  671.  
  672. edit(file)
  673.     char *file;
  674.     {
  675.     char line[256], rline[256], *edtemp = mktemp("/tmp/UaEdXXXXXX");
  676.     short lcnt, lnum;
  677.     FILE *ip, *fp;
  678.  
  679.     for (;;)
  680.     {
  681.     printf("\nLine number to edit (<ENTER> to exit): ");
  682.     gets(line);
  683.     log("Line #: %s", line);
  684.     if (line[0] == '\0')
  685.         return;
  686.     lnum = atoi(line);
  687.     if (lnum < 1)
  688.         continue;
  689.     if ((fp = fopen(file, "r")) == NULL)
  690.         {
  691.         log("Error %d opening %s", errno, file);
  692.         panic("tmp");
  693.         }
  694.     if ((ip = fopen(edtemp, "w")) == NULL)
  695.         {
  696.         log("Error %d opening %s", errno, edtemp);
  697.         puts("Can't open the temporary file.");
  698.         fclose(fp);
  699.         return;
  700.         }
  701.     for (lcnt = 1; lcnt < lnum; lcnt++)
  702.         {
  703.         fgets(line, 256, fp);
  704.         fputs(line, ip);
  705.         }
  706.     fgets(line, 256, fp);
  707.     if (feof(fp))
  708.         {
  709.         puts("Not that many lines in the message.");
  710.         fclose(fp);
  711.         fclose(ip);
  712.         unlink(edtemp);
  713.         continue;
  714.         }
  715.     printf("\nLine %d currently reads:\n\n> %s\nRe-enter the line, or hit <ENTER> to leave it unchanged:\n\n] ", lnum, line);
  716.     gets(rline);
  717.     log("Replacement: %s", rline);
  718.     if (rline[0] == '\0')
  719.         fputs(line, ip);
  720.     else
  721.         fprintf(ip, "%s\n", rline);
  722.     while (fgets(line, 256, fp) != NULL)
  723.         fputs(line, ip);
  724.     fclose(ip);
  725.     fclose(fp);
  726.     unlink(file);
  727.     if (copylink(edtemp, file) < 0)
  728.         {
  729.         log("Error %d copylinking %s to %s", errno, edtemp, file);
  730.         panic("copylink");
  731.         }
  732.     unlink(edtemp);
  733.     }
  734.     }
  735.     
  736. doqscan(msg, conf, mnum)
  737.     char *msg, *conf;
  738.     short mnum;
  739.     {
  740.     char line[1024];
  741.     FILE *f;
  742.  
  743.     if ((f = fopen(msg, "r")) == NULL)
  744.     {
  745.     puts("Cannot open file.");
  746.     log("Error %d opening %s", errno, msg);
  747.     return 1;
  748.     }
  749.     printf("%5d. ", mnum);
  750.     if (isprivate(msg))
  751.     puts("Private message.");
  752.     else
  753.     while (fgets(line, 1024, f) != NULL)
  754.         {
  755.         if (line[0] == '\n')
  756.         break;
  757.         if (strncmp(line, "Subject: ", 9) == 0)
  758.         {
  759.         printf("%s", &line[9]);
  760.         break;
  761.         }
  762.         if (strncmp(line, "Subject (Private): ", 19) == 0)
  763.         {
  764.         printf("%s", &line[8]);        /* include privacy tag */
  765.         break;
  766.         }
  767.         }
  768.     fclose(f);
  769.     if (mnum % 16 == 0)    /* kludge, see comment in doscan() */
  770.         if (!cont())
  771.             longjmp(cmdloop, 1);
  772.     return 1;
  773.     }
  774.  
  775. qscan(s)
  776.     char *s;
  777.     {
  778.     return selmsg(s, doqscan);
  779.     }
  780.