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

Revision 10910, 20.9 KB checked in by ghudson, 27 years ago (diff)
Oops, REG_BASIC isn't universal. (It's 0 where it is defined, so just punt it.)
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 *        $Source: /afs/dev.mit.edu/source/repository/athena/bin/discuss/mclient/dsmail.c,v $
13 *
14 *        $Log: not supported by cvs2svn $
15 *        Revision 1.5  1997/12/17 00:13:06  ghudson
16 *        Use POSIX regexps.
17 *
18 *        Revision 1.4  1995/11/30 19:37:40  miki
19 *        In Solaris2.4 sysexits.h migrated to /usr/include
20 *
21 * Revision 1.3  1995/07/31  21:43:53  cfields
22 * Get sysexits.h from ucbinclude if SOLARIS, not SYSV.
23 * Don't need the EX_CONFIG def in that ifdef; it happens later if necessary.
24 *
25 * Revision 1.2  1994/08/14  22:21:28  cfields
26 * include /usr/ucbinclude/sysexits.h if SYSV
27 * index to strchr
28 * extern int regerrno --- why??? It's not used!
29 * 7.7 checkin; changes by vrt
30 *
31 * Revision 1.1  94/04/08  12:37:12  vrt
32 * Initial revision
33 *
34 * Revision 1.23  93/07/14  02:14:35  srz
35 * Check for DELETED_TRN on reply transaction.
36 *
37 * Revision 1.22  1993/05/19  15:36:13  raeburn
38 * Handle errors in setting up temp file properly.
39 * Also, make RPC_NS_TIMEOUT a EX_TEMPFAIL ("try again later") error.
40 *
41 * Revision 1.21  1993/02/16  21:10:13  srz
42 * Trim trailing white-space when comparing subjects.  If daemon does not have
43 * access to read long name of meeting, use in-reply-to transaction number
44 * regardless of meeting name.
45 *
46 * Revision 1.20  1993/02/09  23:47:04  srz
47 * Fix continuation lines in header fields.  Add better In-reply-to: handling to
48 * deal with "[xxxx] in meeting_name" syntax, not replying if meeting name does
49 * not match.  Add -s option for subject matching.
50 *
51 * Revision 1.19  1992/09/11  19:45:36  srz
52 * Enter transaction anyways if In-reply-to: transaction does not exist.
53 *
54 * Revision 1.18  1992/06/26  02:20:05  raeburn
55 * getting in sync with current source tree
56 *
57 * Revision 1.17  92/01/10  00:03:58  srz
58 * Haynes' fix for realloc stuff (on Suns).
59 *
60 * Revision 1.16  91/07/27  02:27:28  srz
61 * Added check in case EX_CONFIG wasn't defined.
62 *
63 * Revision 1.15  91/07/05  20:48:09  bjaspan
64 * ported to svr4
65 *
66 * Revision 1.14  91/07/05  19:16:33  bjaspan
67 * actually, I meant ucbinclude
68 *
69 * Revision 1.13  91/07/05  19:12:47  bjaspan
70 * use /usr/ucb/sysexits.h on svr4
71 *
72 * Revision 1.12  91/05/29  16:54:27  raeburn
73 * Discarded some unused code; use exit codes that sendmail will recognize, and
74 * use SMTP codes in error messages printed.  Renamed PipeToMeeting to
75 * SendToMeeting.  Some other minor changes dealing with initialization of
76 * variables.  Deleted useless `p' option, added h to indicate that hostname
77 * should be extracted from meeting name (not currently used, though).
78 *
79 * Revision 1.11  90/02/24  18:46:12  srz
80 * Added deriving signature from From: field.
81 *
82 * Revision 1.10  89/06/03  00:30:54  srz
83 * Added standard copyright notice.
84 *
85 * Revision 1.9  89/04/17  17:09:21  srz
86 * Added error table initialization.
87 *
88 * Revision 1.8  89/01/05  07:13:11  raeburn
89 * replaced included header files with <discuss/discuss.h>; also added
90 * newline after message header
91 *
92 * Revision 1.7  88/01/15  22:42:39  srz
93 * set_module now returns fatal flag, again.
94 *
95 * Revision 1.6  88/01/05  03:09:30  srz
96 * Put location of DSPIPE into config.h
97 *
98 * Revision 1.5  87/10/24  04:26:44  wesommer
99 * Rewritten for speed and efficiency.  "popen" is a crock.
100 *
101 * Revision 1.4  87/07/17  03:34:57  tytso
102 * Bugfixes made, added -p option, removed zippy stuff
103 *
104 * Revision 1.3  87/05/02  02:12:58  tytso
105 * Replaced the regexp and options parsing code with the UNIX
106 * library routines.  Cleaned up code.  Added -A (all headers)
107 * option.
108 *
109 */
110
111#include <stdio.h>
112#include <string.h>
113#include <ctype.h>
114#include <sys/types.h>
115#include <sys/file.h>
116#include <sysexits.h>
117#include <regex.h>
118
119
120#include <discuss/discuss.h>
121#include <rpc.h>
122#include "config.h"
123
124#define DEFAULT_SUBJECT "No subject found in mail header"
125#define BUFFLEN 400
126#define LISTLEN 40
127
128/* Ultrix sux */
129#ifndef EX_CONFIG
130#define EX_CONFIG EX_SOFTWARE
131#endif
132
133#ifndef lint
134static char rcsid[] =
135    "$Header: /afs/dev.mit.edu/source/repository/athena/bin/discuss/mclient/dsmail.c,v 1.6 1997-12-17 00:31:38 ghudson Exp $";
136#endif
137
138char *malloc(), *realloc ();
139char *mktemp();
140FILE *popen();
141FILE *fopen();
142FILE *fdopen();
143int getopt();
144
145extern char *optarg;                /* External variables for getopt */
146extern int optind;
147
148char *deflist[] = {
149        "^to$","^from$","^cc$",".*-to$",".*-from$","^date$", NULL
150};
151               
152char *subjlist[] = {
153        "^subject$",NULL
154};
155
156char *inreplyto[] = {
157        "^in-reply-to$",NULL
158};
159
160char *fromlist[] = {
161        "^from$",NULL
162};     
163
164char *progname;
165char *save[LISTLEN],*reject[LISTLEN];
166char *usr_mtg = "";
167int dodefs, allfields, debug, have_host, subject_match=0;
168char *optarg;
169int optind;
170extern tfile unix_tfile();
171int reply_to;
172
173void PRS();
174void lower();
175void trim();
176void SendToMeeting();
177int parse_reply_to();
178int have_trn_num();
179int subject_compare();
180
181extern char *malloc(),*realloc();
182
183main(argc,argv)
184        int argc;
185        char *argv[];
186{
187     FILE *f;
188     char line[BUFFLEN+1],*colonp,*ep;
189     char *subject=NULL,*reply_to_str=NULL;
190     int i,ok_prev=0,iscont = 0, have_signature = 0, len;
191     char filename[60], signature[35], field_name[100];
192     
193     init_dsc_err_tbl();
194
195     PRS(argc,argv);                            /* Parse args */
196
197     line[BUFFLEN]='\0';
198
199     if (debug)
200          f=stdout;
201     else {
202          (void) mktemp(strcpy(filename, "/tmp/DSXXXXXX"));
203          if ((f = fopen(filename,"w+")) == NULL)
204            {
205              fprintf (stderr, "250-Can't create temporary file ");
206              fflush (stderr);
207              perror(filename);
208              return EX_TEMPFAIL;
209            }
210          if (fchmod(fileno(f),0600))
211            {
212              perror("250-Can't chmod temporary file");
213              return EX_TEMPFAIL;
214            }
215     }
216
217     if (debug) printf("start of text->");
218     
219     if (fgets(line,BUFFLEN,stdin)==NULL)
220          exit(EX_NOINPUT);
221
222     while (*line != '\n') {                    /* Do headers */
223          if (!iscont) {
224               char *cp;
225
226               ep = line + strlen(line);
227               colonp = strchr(line, ':');
228               if (colonp == NULL)
229                    colonp = ep;
230               len = colonp - line;
231               if (len > sizeof(field_name))
232                    len = sizeof(field_name)-1;
233               strncpy(field_name, line, len);
234               field_name[len] = '\0';
235               lower(field_name);
236
237               if (list_compare(field_name,subjlist)) { /* Subject */
238                    cp = colonp;
239                    if (*cp == ':')
240                         cp++;
241                    while (isspace(*cp))
242                         cp++;
243
244                    /* ignore second subject line */
245                    if (subject==NULL) {
246                         subject=malloc(ep-cp+1);
247                         (void) strcpy(subject,cp);
248
249                         /* Trim subject */
250                         trim(subject);
251                    }   
252               } else if (list_compare(field_name, inreplyto)) {
253                    /* ignore second subject line */
254                    cp = colonp;
255                    if (*cp == ':')
256                         cp++;
257
258                    if (reply_to_str==NULL) {
259                         reply_to_str=malloc(ep-cp+1);
260                         (void) strcpy(reply_to_str,cp);
261                    }   
262               }
263               else if (list_compare(field_name,fromlist)) {
264                    cp = colonp;
265                    if (*cp == ':') {
266                         cp++;
267                         extract_full_name(cp, signature, sizeof(signature));
268                         have_signature = TRUE;
269                         if (debug)
270                              printf ("got sig: %s\n",
271                                      signature);
272                    }
273               }
274          } else {
275               if (list_compare(field_name, inreplyto) && reply_to_str != NULL) {
276                    /* Concat reply-to */
277                    reply_to_str = realloc(reply_to_str,strlen(reply_to_str) + strlen(line) + 1);
278                    strcpy(reply_to_str+strlen(reply_to_str),line);
279               }
280          }
281
282          if ((ok_prev && iscont) || (!iscont && CheckField(field_name))) {
283               ok_prev=1;
284               fprintf(f,"%s",line);
285          } else
286               ok_prev=0;
287
288          iscont = line[strlen(line)-1] != '\n';
289          if (fgets(line,BUFFLEN,stdin)==NULL)
290               goto bye;
291          if (!iscont)
292               iscont = (line[0] == ' ' || line[0] == '\t');
293     }
294     fprintf (f, "\n");
295
296     /* Copy over body of message */
297     while (fgets(line,BUFFLEN,stdin)!=NULL) {
298          fprintf(f,"%s",line);
299     }
300     if (fflush(f) == EOF) {
301          fprintf (stderr, "250-Can't write to ");
302          fflush (stderr);
303          perror (debug ? "standard output" : filename);
304          exit (EX_TEMPFAIL);
305     }
306     
307     SendToMeeting(f,(subject==NULL) ? DEFAULT_SUBJECT : subject,
308                   reply_to_str,
309                   (have_signature) ? signature : NULL);
310 bye:
311     if (!debug)
312          (void) unlink(filename);
313     exit (EX_OK);
314     
315}
316
317void SendToMeeting(f, subject, reply_to_str, signature)
318char *subject;
319char *reply_to_str;
320char *signature;     
321FILE *f;
322{
323     int len,have_mtg_info;
324     static char module[100] = "discuss@";
325     char *mtg_name,*cp,*short_name;
326     int fatal_err, result, smtp_code, exit_code, reply_to_trn;
327     tfile transaction;
328     mtg_info minfo;
329     trn_info tinfo;
330     int trn_no, i;
331     
332     gethostname(&module[8], sizeof(module)-8);
333     init_rpc();
334     set_module(module, &fatal_err, &result);
335
336     switch (result) {
337     case 0:
338          break;
339     case RPC_NS_TIMEOUT:
340          smtp_code = 250;
341          exit_code = EX_TEMPFAIL;
342          break;
343     default:
344          smtp_code = 554;
345          exit_code = EX_CONFIG;
346          break;
347     }
348     if (result) {
349          fprintf(stderr, "%03d-Can't connect to discuss server: %s\n",
350                  smtp_code, error_message(result));
351          exit (exit_code);
352     }
353     
354     rewind(f); lseek(fileno(f), 0, L_SET);
355     transaction = unix_tfile(fileno(f));
356
357     cp = strchr(subject, '\n');
358     if (cp)
359          *cp = '\0';
360
361     /* Parse reply_to_string */
362     have_mtg_info = FALSE;
363     reply_to_trn = 0;
364     if (reply_to_str != NULL && have_trn_num(reply_to_str)) {
365          short_name = usr_mtg + strlen(usr_mtg);
366          while (short_name > usr_mtg && *short_name != '/')
367               short_name--;
368
369          if (*short_name == '/')
370               short_name++;
371
372          reply_to_trn = parse_reply_to(reply_to_str, short_name);
373          if (reply_to_trn == 0) {
374               /* Get mtg info, to check out long name */
375               get_mtg_info(usr_mtg, &minfo, &result);
376               if (result == 0) {
377                    have_mtg_info = TRUE;
378                    reply_to_trn = parse_reply_to(reply_to_str, minfo.long_name);
379               } else
380                    reply_to_trn = parse_reply_to(reply_to_str, NULL);
381          }
382     }
383
384     if (reply_to_trn == 0 && subject_match && strcmp(subject, DEFAULT_SUBJECT) && *subject != '\0') {
385          if (!have_mtg_info) {
386               /* Get mtg info, to check out long name */
387               get_mtg_info(usr_mtg, &minfo, &result);
388               if (result == 0)
389                    have_mtg_info = TRUE;
390          }
391          if (have_mtg_info) {
392               /* Walk through meeting, doing subject comparisons */
393               for (i = 0; i < subject_match; i++) {
394                    if (minfo.last-i < minfo.first)
395                         break;
396
397                    get_trn_info(usr_mtg, minfo.last-i, &tinfo, &result);
398                    if (result == 0) {
399                         if (subject_compare(tinfo.subject, subject)) {
400                              reply_to_trn = minfo.last-i;
401                              dsc_destroy_trn_info(&tinfo);
402                              break;
403                         }
404                         dsc_destroy_trn_info(&tinfo);
405                    }
406               }
407          }
408     }
409
410     if (debug) {
411          printf("subject is ``%s''\nreply to %d in %s\n",
412                 subject, reply_to_trn, usr_mtg);
413     }
414
415     if (signature == NULL || *signature == '\0') {
416          add_trn(usr_mtg, transaction, subject, reply_to_trn, &trn_no, &result);
417     } else {
418          if (get_server_version() < SERVER_2) {
419               add_trn(usr_mtg, transaction, subject, reply_to_trn, &trn_no, &result);
420          } else {
421               add_trn2(usr_mtg, transaction, subject, signature, reply_to_trn, &trn_no, &result);
422          }
423     }
424
425     /* If error, try it as a non-reply */
426     if ((result == NO_SUCH_TRN || result == DELETED_TRN || result == NO_ACCESS)  && reply_to_trn != 0) {
427          tdestroy(transaction);
428          rewind(f); lseek(fileno(f), 0, L_SET);
429          transaction = unix_tfile(fileno(f));
430          if (signature == NULL || *signature == '\0' || get_server_version() < SERVER_2) {
431               add_trn(usr_mtg, transaction, subject, 0, &trn_no, &result);
432          } else {
433               add_trn2(usr_mtg, transaction, subject, signature, 0, &trn_no, &result);
434          }
435     }
436     
437     switch (result) {
438     case 0:
439          break;
440     default:
441          smtp_code = 550;
442          exit_code = EX_CANTCREAT;
443     }
444     if (result) {
445          fprintf (stderr, "%03d-Can't enter transaction", smtp_code);
446          if (reply_to)
447               fprintf (stderr, " as reply to %d", reply_to);
448          fprintf (stderr, "\n%03d- into meeting %s: %s\n",
449                   smtp_code, usr_mtg, error_message (result));
450          exit(exit_code);
451     }
452     (void) fclose(f);
453}
454
455void
456lower(s)
457char *s;
458{
459     while (*s) {
460          if (isupper(*s))
461               *s = tolower(*s);
462          s++;
463     }
464}
465
466void
467trim(s)
468char *s;
469{
470     char *cp;
471
472     cp = &s[strlen(s)]-1;
473     while (cp >= s && isspace(*cp)) {
474          *cp-- = '\0';
475     }
476}
477
478int CheckField(key)
479        char *key;
480{
481        int keepfield;
482
483        keepfield=allfields;
484        if (!keepfield && dodefs && list_compare(key,deflist))
485                keepfield=1;
486        if (!keepfield && list_compare(key,save))
487                keepfield=1;
488        if (keepfield && list_compare(key,reject))
489                keepfield=0;
490        return(keepfield);
491}
492
493/* Parse command line arguments */
494void PRS(argc,argv)
495        int argc;
496        char **argv;
497{
498        int c,rp,sp;
499       
500        progname=argv[0];
501        sp=rp=0;
502        optind=1;               /* Initialize for getopt */
503        while ((c = getopt(argc,argv,"AZDs:da:r:h")) != EOF)
504                switch(c) {
505                case 'd':
506                        dodefs=!dodefs;
507                        break;
508
509                case 's':
510                        subject_match = atoi(optarg);
511                        break;
512
513                case 'D':
514                        debug=!debug;
515                        break;
516
517                case 'A':
518                        allfields=!allfields;
519                        break;
520
521                case 'a':
522                        lower(optarg);
523                        save[sp++]=optarg;
524                        if (sp>=LISTLEN) {
525                                fprintf(stderr,"500-Too many accept fields\n");
526                                exit (EX_USAGE);
527                        }
528                        break;
529
530                case 'h':
531                        have_host = 1;
532                        break;
533
534                case 'r':
535                        lower(optarg);
536                        reject[rp++]=optarg;
537                        if (sp>=LISTLEN) {
538                                fprintf(stderr,"500-Too many reject fields\n");
539                                exit (EX_USAGE);
540                        }
541                }   
542        if (optind>=argc)
543                goto lusage;
544        usr_mtg=argv[optind];
545        if (have_host) {
546                usr_mtg = strchr (usr_mtg, ':');
547                if (!usr_mtg)
548                        goto lusage;
549                usr_mtg++;
550        }
551        save[sp]=NULL;          /* Insert terminators */
552        reject[rp]=NULL;
553        return;
554 lusage:
555        printf("500-Usage: %s [-dADZ] [-s subject-match-count] [-a field] [-r field] meeting-path-name\n",
556               progname);
557        exit (EX_USAGE);
558}
559
560int list_compare(s,list)
561        char *s,**list;
562{
563        char buf[BUFSIZ];
564        regex_t reg;
565        int status;
566
567        while (*list!=NULL) {
568                status = regcomp(&reg, *list, REG_NOSUB);
569                if (status != 0) {
570                        regerror(status, &reg, buf, sizeof(buf));
571                        fprintf(stderr,"554-%s - %s: %s\n",
572                                progname, *list, buf);
573                }
574                if (regexec(&reg, s, 0, NULL, 0) == 0) {
575                        regfree(&reg);
576                        return 1;
577                }
578                regfree(&reg);
579                list++;
580        }
581        return(0);
582}
583
584strip_addr(addr, dest, dest_size)
585char *addr,*dest;
586int dest_size;
587{
588     char *dest_end,*dp,*sp,*quote_start;
589     int paren_level,found_angle;
590
591     dest_end = &dest[dest_size-1];
592     dp = dest;
593     sp = addr;
594     paren_level = 0;
595
596eat_white:
597     while (isspace(*sp) && *sp != '\n')
598          sp++;
599
600     if (*sp == '(')
601          goto eat_comment;
602
603     if (*sp == '"')
604          goto eat_string;
605
606     if (*sp == '<') {
607          dp = dest;
608          sp++;
609          found_angle = TRUE;
610          goto eat_white;
611     }
612
613     if (*sp == '>' && found_angle) {
614          *sp++;
615          goto eat_white;
616     }
617
618     if (*sp == '\0' || *sp == '\n') {
619          *dp++ = '\0';
620          goto post_proc;
621     }
622
623     *dp++ = *sp++;
624     if (dp == dest_end) {
625          *dp++ = '\0';
626          goto post_proc;
627     }
628
629     goto eat_white;
630
631eat_comment:
632     paren_level++;
633     sp++;
634
635cont_comment:
636     while (*sp != ')' && *sp != '(' && *sp) {
637          sp++;
638     }
639
640     if (*sp == '\0') {
641          *dp = '\0';
642          goto post_proc;
643     }
644
645     if (*sp == '(')
646          goto eat_comment;
647
648     sp++;              /* ) */
649     paren_level--;
650     if (paren_level <= 0)
651          goto eat_white;
652
653     goto cont_comment;
654
655eat_string:
656     quote_start = sp;
657     sp++;
658
659     while(*sp != '"' && *sp)
660          sp++;
661
662     if (!*sp) {
663          *dp = '\0';
664          goto post_proc;
665     }
666
667     if (*++sp == '@') {                /* "foo"@bar */
668          sp = quote_start;
669          *dp++ = *sp++;
670          while (dp < dest_end && *sp != '"')
671               *dp++ = *sp++;
672
673          if (dp == dest_end) {
674               *dp = '\0';
675               goto post_proc;
676          }
677          *dp++ = *sp++;
678          if (dp == dest_end) {
679               *dp++ = '\0';
680               goto post_proc;
681          }
682     }
683     goto eat_white;
684
685     /* No post processing */
686post_proc:
687     return;
688}
689
690/*
691 *
692 *   Routine to extract a full name from an address.  If no full name
693 *   can be found, then we simply return the stripped address.
694 *
695 */
696extract_full_name(addr, dest, dest_size)
697char *addr,*dest;
698int dest_size;
699{
700     char *dest_end,*dp,*sp,*bracket,*close_paren;
701     int paren_level,non_white;
702
703     dest_end = &dest[dest_size-1];
704     dp = dest;
705     sp = addr;
706
707     /* Find angle bracket (if possible) */
708     while (*sp && *sp != '<' && *sp != '\n')
709          sp++;
710
711     bracket = NULL;
712     if (*sp == '<')
713          bracket = sp;
714
715     non_white = 0;
716     if (bracket != NULL) {
717          for (sp = addr; sp < bracket; sp++) {
718               if (!isspace(*sp) && *sp != '"')
719                    non_white++;
720          }
721     }
722
723     if (non_white > 1) {               /* We have a name */
724          sp = addr;
725          while (isspace(*sp) || *sp == '"')    /* Skip leading spaces */
726               sp++;
727
728          while (isspace(*(bracket-1)) || *(bracket-1) == '"')  /* Skip trailing spaces */
729               bracket--;
730
731          /* Copy it over */
732          while (sp < bracket && dp < dest_end)
733               *dp++ = *sp++;
734
735          *dp++ = '\0';
736          return;
737     }
738
739     /* Now, let's see if we have name in a comment (look back from the
740        end for a parenthesis. */
741     for (sp = addr; *sp && *sp != '\n'; sp++)
742          ;
743
744     sp--;
745     while (sp > addr && isspace(*sp))
746          sp--;
747
748     if (*sp == ')') {                  /* Name in comment */
749          close_paren = sp;
750          paren_level = 1;
751          sp--;
752
753          for (;sp > addr; sp--) {
754               if (*sp == ')')
755                    paren_level++;
756               else if (*sp == '(') {
757                    paren_level--;
758                    if (paren_level == 0)
759                         break;
760               }
761          }
762
763          if (*sp == '(') {             /* Copy it over */
764               sp++;
765
766               while(isspace(*sp))
767                    sp++;
768
769               while (sp < close_paren && dp < dest_end)
770                    *dp++ = *sp++;
771
772               *dp = '\0';
773               return;
774          }
775     }
776
777     strip_addr(addr, dest, dest_size);
778     return;
779}         
780
781/*
782 *
783 *   parse_reply_to() - Parse an in-reply-to message for a given message.
784 *
785 */
786int
787parse_reply_to(str, mtg_name)
788char *str;
789char *mtg_name;
790{
791     char *bracketp,*end_bracketp,*startp,*cp;
792     int trn_num,mtg_name_len;
793
794     startp = str;
795     while (1) {
796          bracketp = strchr(startp, '[');
797          if (bracketp == NULL)
798               return(0);
799
800          end_bracketp = strchr(bracketp, ']');
801          if (end_bracketp == NULL || end_bracketp - bracketp > 10)
802               return(0);
803
804          trn_num = 0;
805          cp = bracketp+1;
806          while (isdigit(*cp)) {
807               trn_num = trn_num*10 + *cp++ - '0';
808          }
809         
810          if (*cp == '\\')                              /* Skip quoting char */
811               cp++;
812         
813          if (*cp != ']')
814               trn_num = 0;
815         
816          if (trn_num == 0)
817               return(0);
818         
819          cp++;
820          while (isspace(*cp) || *cp == '"')
821               cp++;
822         
823          if (mtg_name == NULL)                         /* Match anything */
824               return(trn_num);
825
826          /* Look for "in" */
827          if (*cp != 'i' && *cp != 'I')
828               return(trn_num);
829         
830          cp++;
831          if (*cp != 'n' && *cp != 'N')
832               return(trn_num);
833
834          cp++;
835          while (isspace(*cp) || *cp == '"')
836               cp++;
837
838          /* Check for meeting name.  If it doesn't match, we don't have
839             a transaction number */
840          mtg_name_len = strlen(mtg_name);
841          if (mtg_name == NULL || strlen(cp) < mtg_name_len) {
842               startp = cp;
843               continue;
844          }
845
846          /* Check if match, and ends fine (random punctuation or space) */
847          if (!strncasecmp(cp, mtg_name, mtg_name_len) &&
848              !isalnum(*(cp+mtg_name_len)) && *(cp+mtg_name_len) != '_' &&
849              *(cp+mtg_name_len) != '-')
850               return(trn_num);
851
852          startp = cp;
853     }
854}
855
856int
857have_trn_num(str)
858char *str;
859{
860     char *bracketp,*end_bracketp,*cp;
861     int trn_num;
862
863     bracketp = strchr(str, '[');
864     if (bracketp == NULL)
865          return(FALSE);
866
867     end_bracketp = strchr(bracketp, ']');
868     if (end_bracketp == NULL || end_bracketp - bracketp > 10)
869          return;
870
871     trn_num = 0;
872     cp = bracketp+1;
873     while (isdigit(*cp)) {
874          trn_num = trn_num*10 + *cp++ - '0';
875     }
876
877     if (*cp == '\\')                           /* Skip quoting char */
878          cp++;
879
880     if (*cp != ']')
881          trn_num = 0;
882
883     if (trn_num == 0)
884          return(FALSE);
885
886     return(TRUE);
887}
888
889/*
890 *
891 *   Compare subjects, ignoring 're: *' at the beginning and trailing
892 *      white space
893 *
894 */
895int
896subject_compare(subj1, subj2)
897char *subj1, *subj2;
898{
899     char *cp;
900     int min_len, len1, len2;
901
902     while (*subj1) {
903          while (isspace(*subj1))
904               subj1++;
905
906          cp = subj1;
907
908          if (*cp != 'r' && *cp != 'R')
909               break;
910
911          cp++;
912          if (*cp != 'e' && *cp != 'E')
913               break;
914          cp++;
915
916          if (*cp != ':')
917               break;
918
919          subj1 = cp+1;
920     }
921
922     while (*subj2) {
923          while (isspace(*subj2))
924               subj2++;
925
926          cp = subj2;
927
928          if (*cp != 'r' && *cp != 'R')
929               break;
930
931          cp++;
932          if (*cp != 'e' && *cp != 'E')
933               break;
934          cp++;
935
936          if (*cp != ':')
937               break;
938
939          subj2 = cp+1;
940     }
941
942     /* Compare subjects, ignoring trailing white-space */
943     len1 = strlen(subj1);
944     len2 = strlen(subj2);
945     if (len1 < len2)
946          min_len = len1;
947     else
948          min_len = len2;
949
950     if (min_len <= 0)
951          return(0);
952
953     if (strncasecmp(subj1, subj2, min_len))
954          return(0);
955
956     if (len1 == len2)
957          return(1);
958
959     if (len1 < len2)
960          cp = &subj2[len1];
961     else
962          cp = &subj1[len2];
963
964     /* If rest if white-space, we match */
965     while (*cp) {
966          if (*cp != ' ')
967               return(0);
968          cp++;
969     }
970     return(1);
971}
Note: See TracBrowser for help on using the repository browser.