source: trunk/athena/bin/discuss/mclient/dsmail.c @ 22864

Revision 22864, 17.6 KB checked in by andersk, 16 years ago (diff)
Fix obsolete names for Kerberos library functions, which no longer worked on Mac OS X. Patch from broder.
Line 
1 /*
2 *
3 *      Copyright (C) 1988, 1989 by the Massachusetts Institute of Technology
4 *      Developed by the MIT Student Information Processing Board (SIPB).
5 *      For copying information, see the file mit-copyright.h in this release.
6 *
7 */
8/*
9 *
10 * dsmail.c - Modifies/parses mail to discuss
11 *
12 *        $Id: dsmail.c,v 1.11 2006-03-10 07:11:39 ghudson Exp $
13 *
14 */
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <ctype.h>
20#include <sys/types.h>
21#include <sys/file.h>
22#include <sysexits.h>
23#include <regex.h>
24#include <sys/fcntl.h>
25
26
27#include <discuss/discuss.h>
28#include <rpc.h>
29#include "config.h"
30
31#define DEFAULT_SUBJECT "No subject found in mail header"
32#define BUFFLEN 400
33#define LISTLEN 40
34
35/* Ultrix sux */
36#ifndef EX_CONFIG
37#define EX_CONFIG EX_SOFTWARE
38#endif
39
40#ifndef lint
41static char rcsid[] =
42    "$Id: dsmail.c,v 1.11 2006-03-10 07:11:39 ghudson Exp $";
43#endif
44
45extern char *optarg;                /* External variables for getopt */
46extern int optind;
47
48char *deflist[] = {
49        "^to$","^from$","^cc$","^[^d].*-to$",".*-from$","^date$",
50        "^message-id$", "^mime-version$", "^content-.*$", NULL
51};
52               
53char *subjlist[] = {
54        "^subject$",NULL
55};
56
57char *inreplyto[] = {
58        "^in-reply-to$",NULL
59};
60
61char *fromlist[] = {
62        "^from$",NULL
63};     
64
65char *progname;
66char *save[LISTLEN],*reject[LISTLEN];
67char *usr_mtg = "";
68int dodefs, allfields, debug, have_host, subject_match=0;
69char *optarg;
70int optind;
71extern tfile unix_tfile();
72int reply_to;
73
74void PRS();
75void lower();
76void trim();
77void SendToMeeting();
78int parse_reply_to();
79int have_trn_num();
80int subject_compare();
81
82main(argc,argv)
83        int argc;
84        char *argv[];
85{
86     FILE *f;
87     char line[BUFFLEN+1],*colonp,*ep;
88     char *subject=NULL,*reply_to_str=NULL;
89     int i,ok_prev=0,iscont = 0, have_signature = 0, len, d;
90     char filename[60], signature[35], field_name[100];
91     
92     initialize_dsc_error_table();
93
94     PRS(argc,argv);                            /* Parse args */
95
96     line[BUFFLEN]='\0';
97
98     if (debug)
99          f=stdout;
100     else {
101          (void) mktemp(strcpy(filename, "/tmp/DSXXXXXX"));
102          if ((d = open(filename, O_CREAT|O_EXCL|O_RDWR, 0600)) == -1)
103            {
104              fprintf (stderr, "250-Can't create temporary file ");
105              fflush (stderr);
106              perror(filename);
107              return EX_TEMPFAIL;
108            }
109          if ((f = fdopen(d, "w+")) == NULL)
110            {
111              perror("250-Can't fdopen temporary file");
112              return EX_TEMPFAIL;
113            }
114     }
115
116     if (debug) printf("start of text->");
117     
118     if (fgets(line,BUFFLEN,stdin)==NULL)
119          exit(EX_NOINPUT);
120
121     while (*line != '\n') {                    /* Do headers */
122          if (!iscont) {
123               char *cp;
124
125               ep = line + strlen(line);
126               colonp = strchr(line, ':');
127               if (colonp == NULL)
128                    colonp = ep;
129               len = colonp - line;
130               if (len > sizeof(field_name))
131                    len = sizeof(field_name)-1;
132               strncpy(field_name, line, len);
133               field_name[len] = '\0';
134               lower(field_name);
135
136               if (list_compare(field_name,subjlist)) { /* Subject */
137                    cp = colonp;
138                    if (*cp == ':')
139                         cp++;
140                    while (isspace(*cp))
141                         cp++;
142
143                    /* ignore second subject line */
144                    if (subject==NULL) {
145                         subject=malloc(ep-cp+1);
146                         if (!subject)
147                             exit (EX_TEMPFAIL);                               
148                         (void) strcpy(subject,cp);
149
150                         /* Trim subject */
151                         trim(subject);
152                    }   
153               } else if (list_compare(field_name, inreplyto)) {
154                    /* ignore second subject line */
155                    cp = colonp;
156                    if (*cp == ':')
157                         cp++;
158
159                    if (reply_to_str==NULL) {
160                         reply_to_str=malloc(ep-cp+1);
161                         if (!reply_to_str)
162                             exit (EX_TEMPFAIL);                               
163                         (void) strcpy(reply_to_str,cp);
164                    }   
165               }
166               else if (list_compare(field_name,fromlist)) {
167                    cp = colonp;
168                    if (*cp == ':') {
169                         cp++;
170                         extract_full_name(cp, signature, sizeof(signature));
171                         have_signature = TRUE;
172                         if (debug)
173                              printf ("got sig: %s\n",
174                                      signature);
175                    }
176               }
177          } else {
178               if (list_compare(field_name, inreplyto) && reply_to_str != NULL) {
179                    /* Concat reply-to */
180                    reply_to_str = realloc(reply_to_str,strlen(reply_to_str) + strlen(line) + 1);
181                    if (!reply_to_str)
182                        exit (EX_TEMPFAIL);                             
183                    strcpy(reply_to_str+strlen(reply_to_str),line);
184               }
185          }
186
187          if ((ok_prev && iscont) || (!iscont && CheckField(field_name))) {
188               ok_prev=1;
189               fprintf(f,"%s",line);
190          } else
191               ok_prev=0;
192
193          iscont = line[strlen(line)-1] != '\n';
194          if (fgets(line,BUFFLEN,stdin)==NULL)
195               goto bye;
196          if (!iscont)
197               iscont = (line[0] == ' ' || line[0] == '\t');
198     }
199     fprintf (f, "\n");
200
201     /* Copy over body of message */
202     while (fgets(line,BUFFLEN,stdin)!=NULL) {
203          fprintf(f,"%s",line);
204     }
205     if (fflush(f) == EOF) {
206          fprintf (stderr, "250-Can't write to ");
207          fflush (stderr);
208          perror (debug ? "standard output" : filename);
209          exit (EX_TEMPFAIL);
210     }
211     
212     SendToMeeting(f,(subject==NULL) ? DEFAULT_SUBJECT : subject,
213                   reply_to_str,
214                   (have_signature) ? signature : NULL);
215 bye:
216     if (!debug)
217          (void) unlink(filename);
218     exit (EX_OK);
219     
220}
221
222void SendToMeeting(f, subject, reply_to_str, signature)
223char *subject;
224char *reply_to_str;
225char *signature;     
226FILE *f;
227{
228     int len,have_mtg_info;
229     static char module[100] = "discuss@";
230     char *mtg_name,*cp,*short_name;
231     int fatal_err, result, smtp_code, exit_code, reply_to_trn;
232     tfile transaction;
233     mtg_info minfo;
234     trn_info tinfo;
235     int trn_no, i;
236     
237     gethostname(&module[8], sizeof(module)-8);
238     init_rpc();
239     set_module(module, &fatal_err, &result);
240
241     switch (result) {
242     case 0:
243          break;
244     case RPC_NS_TIMEOUT:
245          smtp_code = 250;
246          exit_code = EX_TEMPFAIL;
247          break;
248     default:
249          smtp_code = 554;
250          exit_code = EX_CONFIG;
251          break;
252     }
253     if (result) {
254          fprintf(stderr, "%03d-Can't connect to discuss server: %s\n",
255                  smtp_code, error_message(result));
256          exit (exit_code);
257     }
258     
259     rewind(f); lseek(fileno(f), 0, L_SET);
260     transaction = unix_tfile(fileno(f));
261
262     cp = strchr(subject, '\n');
263     if (cp)
264          *cp = '\0';
265
266     /* Parse reply_to_string */
267     have_mtg_info = FALSE;
268     reply_to_trn = 0;
269     if (reply_to_str != NULL && have_trn_num(reply_to_str)) {
270          short_name = usr_mtg + strlen(usr_mtg);
271          while (short_name > usr_mtg && *short_name != '/')
272               short_name--;
273
274          if (*short_name == '/')
275               short_name++;
276
277          reply_to_trn = parse_reply_to(reply_to_str, short_name);
278          if (reply_to_trn == 0) {
279               /* Get mtg info, to check out long name */
280               get_mtg_info(usr_mtg, &minfo, &result);
281               if (result == 0) {
282                    have_mtg_info = TRUE;
283                    reply_to_trn = parse_reply_to(reply_to_str, minfo.long_name);
284               } else
285                    reply_to_trn = parse_reply_to(reply_to_str, NULL);
286          }
287     }
288
289     if (reply_to_trn == 0 && subject_match && strcmp(subject, DEFAULT_SUBJECT) && *subject != '\0') {
290          if (!have_mtg_info) {
291               /* Get mtg info, to check out long name */
292               get_mtg_info(usr_mtg, &minfo, &result);
293               if (result == 0)
294                    have_mtg_info = TRUE;
295          }
296          if (have_mtg_info) {
297               /* Walk through meeting, doing subject comparisons */
298               for (i = 0; i < subject_match; i++) {
299                    if (minfo.last-i < minfo.first)
300                         break;
301
302                    get_trn_info(usr_mtg, minfo.last-i, &tinfo, &result);
303                    if (result == 0) {
304                         if (subject_compare(tinfo.subject, subject)) {
305                              reply_to_trn = minfo.last-i;
306                              dsc_destroy_trn_info(&tinfo);
307                              break;
308                         }
309                         dsc_destroy_trn_info(&tinfo);
310                    }
311               }
312          }
313     }
314
315     if (debug) {
316          printf("subject is ``%s''\nreply to %d in %s\n",
317                 subject, reply_to_trn, usr_mtg);
318     }
319
320     if (signature == NULL || *signature == '\0') {
321          add_trn(usr_mtg, transaction, subject, reply_to_trn, &trn_no, &result);
322     } else {
323          if (get_server_version() < SERVER_2) {
324               add_trn(usr_mtg, transaction, subject, reply_to_trn, &trn_no, &result);
325          } else {
326               add_trn2(usr_mtg, transaction, subject, signature, reply_to_trn, &trn_no, &result);
327          }
328     }
329
330     /* If error, try it as a non-reply */
331     if ((result == NO_SUCH_TRN || result == DELETED_TRN || result == NO_ACCESS)  && reply_to_trn != 0) {
332          tdestroy(transaction);
333          rewind(f); lseek(fileno(f), 0, L_SET);
334          transaction = unix_tfile(fileno(f));
335          if (signature == NULL || *signature == '\0' || get_server_version() < SERVER_2) {
336               add_trn(usr_mtg, transaction, subject, 0, &trn_no, &result);
337          } else {
338               add_trn2(usr_mtg, transaction, subject, signature, 0, &trn_no, &result);
339          }
340     }
341     
342     switch (result) {
343     case 0:
344          break;
345     default:
346          smtp_code = 550;
347          exit_code = EX_CANTCREAT;
348     }
349     if (result) {
350          fprintf (stderr, "%03d-Can't enter transaction", smtp_code);
351          if (reply_to)
352               fprintf (stderr, " as reply to %d", reply_to);
353          fprintf (stderr, "\n%03d- into meeting %s: %s\n",
354                   smtp_code, usr_mtg, error_message (result));
355          exit(exit_code);
356     }
357     (void) fclose(f);
358}
359
360void
361lower(s)
362char *s;
363{
364     while (*s) {
365          if (isupper(*s))
366               *s = tolower(*s);
367          s++;
368     }
369}
370
371void
372trim(s)
373char *s;
374{
375     char *cp;
376
377     cp = &s[strlen(s)]-1;
378     while (cp >= s && isspace(*cp)) {
379          *cp-- = '\0';
380     }
381}
382
383int CheckField(key)
384        char *key;
385{
386        int keepfield;
387
388        keepfield=allfields;
389        if (!keepfield && dodefs && list_compare(key,deflist))
390                keepfield=1;
391        if (!keepfield && list_compare(key,save))
392                keepfield=1;
393        if (keepfield && list_compare(key,reject))
394                keepfield=0;
395        return(keepfield);
396}
397
398/* Parse command line arguments */
399void PRS(argc,argv)
400        int argc;
401        char **argv;
402{
403        int c,rp,sp;
404       
405        progname=argv[0];
406        sp=rp=0;
407        optind=1;               /* Initialize for getopt */
408        while ((c = getopt(argc,argv,"AZDs:da:r:h")) != EOF)
409                switch(c) {
410                case 'd':
411                        dodefs=!dodefs;
412                        break;
413
414                case 's':
415                        subject_match = atoi(optarg);
416                        break;
417
418                case 'D':
419                        debug=!debug;
420                        break;
421
422                case 'A':
423                        allfields=!allfields;
424                        break;
425
426                case 'a':
427                        lower(optarg);
428                        save[sp++]=optarg;
429                        if (sp>=LISTLEN) {
430                                fprintf(stderr,"500-Too many accept fields\n");
431                                exit (EX_USAGE);
432                        }
433                        break;
434
435                case 'h':
436                        have_host = 1;
437                        break;
438
439                case 'r':
440                        lower(optarg);
441                        reject[rp++]=optarg;
442                        if (sp>=LISTLEN) {
443                                fprintf(stderr,"500-Too many reject fields\n");
444                                exit (EX_USAGE);
445                        }
446                }   
447        if (optind>=argc)
448                goto lusage;
449        usr_mtg=argv[optind];
450        if (have_host) {
451                usr_mtg = strchr (usr_mtg, ':');
452                if (!usr_mtg)
453                        goto lusage;
454                usr_mtg++;
455        }
456        save[sp]=NULL;          /* Insert terminators */
457        reject[rp]=NULL;
458        return;
459 lusage:
460        printf("500-Usage: %s [-dADZ] [-s subject-match-count] [-a field] [-r field] meeting-path-name\n",
461               progname);
462        exit (EX_USAGE);
463}
464
465int list_compare(s,list)
466        char *s,**list;
467{
468        char buf[BUFSIZ];
469        regex_t reg;
470        int status;
471
472        while (*list!=NULL) {
473                status = regcomp(&reg, *list, REG_NOSUB);
474                if (status != 0) {
475                        regerror(status, &reg, buf, sizeof(buf));
476                        fprintf(stderr,"554-%s - %s: %s\n",
477                                progname, *list, buf);
478                }
479                if (regexec(&reg, s, 0, NULL, 0) == 0) {
480                        regfree(&reg);
481                        return 1;
482                }
483                regfree(&reg);
484                list++;
485        }
486        return(0);
487}
488
489strip_addr(addr, dest, dest_size)
490char *addr,*dest;
491int dest_size;
492{
493     char *dest_end,*dp,*sp,*quote_start;
494     int paren_level,found_angle;
495
496     dest_end = &dest[dest_size-1];
497     dp = dest;
498     sp = addr;
499     paren_level = 0;
500
501eat_white:
502     while (isspace(*sp) && *sp != '\n')
503          sp++;
504
505     if (*sp == '(')
506          goto eat_comment;
507
508     if (*sp == '"')
509          goto eat_string;
510
511     if (*sp == '<') {
512          dp = dest;
513          sp++;
514          found_angle = TRUE;
515          goto eat_white;
516     }
517
518     if (*sp == '>' && found_angle) {
519          *sp++;
520          goto eat_white;
521     }
522
523     if (*sp == '\0' || *sp == '\n') {
524          *dp++ = '\0';
525          goto post_proc;
526     }
527
528     *dp++ = *sp++;
529     if (dp == dest_end) {
530          *dp++ = '\0';
531          goto post_proc;
532     }
533
534     goto eat_white;
535
536eat_comment:
537     paren_level++;
538     sp++;
539
540cont_comment:
541     while (*sp != ')' && *sp != '(' && *sp) {
542          sp++;
543     }
544
545     if (*sp == '\0') {
546          *dp = '\0';
547          goto post_proc;
548     }
549
550     if (*sp == '(')
551          goto eat_comment;
552
553     sp++;              /* ) */
554     paren_level--;
555     if (paren_level <= 0)
556          goto eat_white;
557
558     goto cont_comment;
559
560eat_string:
561     quote_start = sp;
562     sp++;
563
564     while(*sp != '"' && *sp)
565          sp++;
566
567     if (!*sp) {
568          *dp = '\0';
569          goto post_proc;
570     }
571
572     if (*++sp == '@') {                /* "foo"@bar */
573          sp = quote_start;
574          *dp++ = *sp++;
575          while (dp < dest_end && *sp != '"')
576               *dp++ = *sp++;
577
578          if (dp == dest_end) {
579               *dp = '\0';
580               goto post_proc;
581          }
582          *dp++ = *sp++;
583          if (dp == dest_end) {
584               *dp++ = '\0';
585               goto post_proc;
586          }
587     }
588     goto eat_white;
589
590     /* No post processing */
591post_proc:
592     return;
593}
594
595/*
596 *
597 *   Routine to extract a full name from an address.  If no full name
598 *   can be found, then we simply return the stripped address.
599 *
600 */
601extract_full_name(addr, dest, dest_size)
602char *addr,*dest;
603int dest_size;
604{
605     char *dest_end,*dp,*sp,*bracket,*close_paren;
606     int paren_level,non_white;
607
608     dest_end = &dest[dest_size-1];
609     dp = dest;
610     sp = addr;
611
612     /* Find angle bracket (if possible) */
613     while (*sp && *sp != '<' && *sp != '\n')
614          sp++;
615
616     bracket = NULL;
617     if (*sp == '<')
618          bracket = sp;
619
620     non_white = 0;
621     if (bracket != NULL) {
622          for (sp = addr; sp < bracket; sp++) {
623               if (!isspace(*sp) && *sp != '"')
624                    non_white++;
625          }
626     }
627
628     if (non_white > 1) {               /* We have a name */
629          sp = addr;
630          while (isspace(*sp) || *sp == '"')    /* Skip leading spaces */
631               sp++;
632
633          while (isspace(*(bracket-1)) || *(bracket-1) == '"')  /* Skip trailing spaces */
634               bracket--;
635
636          /* Copy it over */
637          while (sp < bracket && dp < dest_end)
638               *dp++ = *sp++;
639
640          *dp++ = '\0';
641          return;
642     }
643
644     /* Now, let's see if we have name in a comment (look back from the
645        end for a parenthesis. */
646     for (sp = addr; *sp && *sp != '\n'; sp++)
647          ;
648
649     sp--;
650     while (sp > addr && isspace(*sp))
651          sp--;
652
653     if (*sp == ')') {                  /* Name in comment */
654          close_paren = sp;
655          paren_level = 1;
656          sp--;
657
658          for (;sp > addr; sp--) {
659               if (*sp == ')')
660                    paren_level++;
661               else if (*sp == '(') {
662                    paren_level--;
663                    if (paren_level == 0)
664                         break;
665               }
666          }
667
668          if (*sp == '(') {             /* Copy it over */
669               sp++;
670
671               while(isspace(*sp))
672                    sp++;
673
674               while (sp < close_paren && dp < dest_end)
675                    *dp++ = *sp++;
676
677               *dp = '\0';
678               return;
679          }
680     }
681
682     strip_addr(addr, dest, dest_size);
683     return;
684}         
685
686/*
687 *
688 *   parse_reply_to() - Parse an in-reply-to message for a given message.
689 *
690 */
691int
692parse_reply_to(str, mtg_name)
693char *str;
694char *mtg_name;
695{
696     char *bracketp,*end_bracketp,*startp,*cp;
697     int trn_num,mtg_name_len;
698
699     startp = str;
700     while (1) {
701          bracketp = strchr(startp, '[');
702          if (bracketp == NULL)
703               return(0);
704
705          end_bracketp = strchr(bracketp, ']');
706          if (end_bracketp == NULL || end_bracketp - bracketp > 10)
707               return(0);
708
709          trn_num = 0;
710          cp = bracketp+1;
711          while (isdigit(*cp)) {
712               trn_num = trn_num*10 + *cp++ - '0';
713          }
714         
715          if (*cp == '\\')                              /* Skip quoting char */
716               cp++;
717         
718          if (*cp != ']')
719               trn_num = 0;
720         
721          if (trn_num == 0)
722               return(0);
723         
724          cp++;
725          while (isspace(*cp) || *cp == '"')
726               cp++;
727         
728          if (mtg_name == NULL)                         /* Match anything */
729               return(trn_num);
730
731          /* Look for "in" */
732          if (*cp != 'i' && *cp != 'I')
733               return(trn_num);
734         
735          cp++;
736          if (*cp != 'n' && *cp != 'N')
737               return(trn_num);
738
739          cp++;
740          while (isspace(*cp) || *cp == '"')
741               cp++;
742
743          /* Check for meeting name.  If it doesn't match, we don't have
744             a transaction number */
745          mtg_name_len = strlen(mtg_name);
746          if (mtg_name == NULL || strlen(cp) < mtg_name_len) {
747               startp = cp;
748               continue;
749          }
750
751          /* Check if match, and ends fine (random punctuation or space) */
752          if (!strncasecmp(cp, mtg_name, mtg_name_len) &&
753              !isalnum(*(cp+mtg_name_len)) && *(cp+mtg_name_len) != '_' &&
754              *(cp+mtg_name_len) != '-')
755               return(trn_num);
756
757          startp = cp;
758     }
759}
760
761int
762have_trn_num(str)
763char *str;
764{
765     char *bracketp,*end_bracketp,*cp;
766     int trn_num;
767
768     bracketp = strchr(str, '[');
769     if (bracketp == NULL)
770          return(FALSE);
771
772     end_bracketp = strchr(bracketp, ']');
773     if (end_bracketp == NULL || end_bracketp - bracketp > 10)
774          return;
775
776     trn_num = 0;
777     cp = bracketp+1;
778     while (isdigit(*cp)) {
779          trn_num = trn_num*10 + *cp++ - '0';
780     }
781
782     if (*cp == '\\')                           /* Skip quoting char */
783          cp++;
784
785     if (*cp != ']')
786          trn_num = 0;
787
788     if (trn_num == 0)
789          return(FALSE);
790
791     return(TRUE);
792}
793
794/*
795 *
796 *   Compare subjects, ignoring 're: *' at the beginning and trailing
797 *      white space
798 *
799 */
800int
801subject_compare(subj1, subj2)
802char *subj1, *subj2;
803{
804     char *cp;
805     int min_len, len1, len2;
806
807     while (*subj1) {
808          while (isspace(*subj1))
809               subj1++;
810
811          cp = subj1;
812
813          if (*cp != 'r' && *cp != 'R')
814               break;
815
816          cp++;
817          if (*cp != 'e' && *cp != 'E')
818               break;
819          cp++;
820
821          if (*cp != ':')
822               break;
823
824          subj1 = cp+1;
825     }
826
827     while (*subj2) {
828          while (isspace(*subj2))
829               subj2++;
830
831          cp = subj2;
832
833          if (*cp != 'r' && *cp != 'R')
834               break;
835
836          cp++;
837          if (*cp != 'e' && *cp != 'E')
838               break;
839          cp++;
840
841          if (*cp != ':')
842               break;
843
844          subj2 = cp+1;
845     }
846
847     /* Compare subjects, ignoring trailing white-space */
848     len1 = strlen(subj1);
849     len2 = strlen(subj2);
850     if (len1 < len2)
851          min_len = len1;
852     else
853          min_len = len2;
854
855     if (min_len <= 0)
856          return(0);
857
858     if (strncasecmp(subj1, subj2, min_len))
859          return(0);
860
861     if (len1 == len2)
862          return(1);
863
864     if (len1 < len2)
865          cp = &subj2[len1];
866     else
867          cp = &subj1[len2];
868
869     /* If rest if white-space, we match */
870     while (*cp) {
871          if (*cp != ' ')
872               return(0);
873          cp++;
874     }
875     return(1);
876}
Note: See TracBrowser for help on using the repository browser.