home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / b / bmh02src.zip / SEND.C < prev    next >
C/C++ Source or Header  |  1992-08-16  |  12KB  |  495 lines

  1. /*
  2.    send.c : Taken from bm.
  3.  
  4.    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.    Permission granted for non-commercial copying and use, provided
  6.    this notice is retained.
  7.    Copyright 1987 1988 Dave Trulli NN2Z, All Rights Reserved.
  8.    Permission granted for non-commercial copying and use, provided
  9.    this notice is retained.
  10.  
  11.    920801 : Added dosend.
  12. */
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <time.h>
  17. #include <ctype.h>
  18. #include <sys/types.h>
  19. #include <dir.h>
  20. #include "rc.h"
  21. #include "smtp.h"
  22. #include "lock.h"
  23. #include "misc.h"
  24. #include "send.h"
  25. #include "header.h"
  26. #include "mailer.h"
  27.  
  28. /* address structure */
  29. struct addr {
  30.    struct addr *next;
  31.    char *user;
  32.    char *host;
  33.    int sent;
  34. };
  35.  
  36. static struct addr *addrecip(struct addr **head, char *user, char *host);
  37. static void del_addrlist(struct addr *list);
  38. static struct addr *expandalias(struct addr **head, char *user);
  39. static struct addr *make_tolist(int argc, char *argv[]);
  40. static int queuejob(FILE *dfile, struct addr *tolist, long position);
  41. static int recordmsg(FILE *dfile, char *to);
  42.  
  43. /*
  44.  * send a message
  45.  * return -1 on error, 0 otherwise
  46.  * calls dosend
  47.  */
  48. int
  49. dosmtpsend(FILE *fpin, char *to, char *cc, char *subj)
  50. {
  51.    char msgid[255], from[255];
  52.  
  53.    sprintf(msgid, "%ld@%s", get_msgid(getrc(mqueue)), getrc(hostname));
  54.  
  55.    if ( getrc(fullname) != NULL )
  56.       sprintf(from, "%s@%s (%s)", getrc(username),
  57.          getrc(hostname), getrc(fullname) );
  58.    else 
  59.       sprintf(from, "%s@%s", getrc(username), getrc(hostname) );
  60.  
  61.    return dosend(fpin, to, cc, subj, from, msgid);
  62. }
  63.  
  64. static int
  65. writes(FILE *fp, struct addr *tp)
  66. {
  67.    int len = 0;
  68.  
  69.    if (tp->next != NULL) {
  70.       len = writes(fp, tp->next);  /* recurse */
  71.       if (len > 50) {
  72.          fputs(",\n\t", fp);
  73.          len = 0;
  74.          }
  75.       else
  76.          fputs(", ", fp);
  77.       }
  78.       
  79.    fputs(tp->user, fp);
  80.    len += strlen(tp->user);
  81.    if ( (tp->host != NULL) || (*tp->host != '\0') ) {
  82.       fprintf(fp, "@%s", tp->host);
  83.       len += strlen(tp->host) + 1;
  84.       }
  85. /*
  86.    fprintf(stderr, "send: mailing %s@%s\n", tp->user,
  87.       tp->host == NULL ? getrc(hostname) : tp->host);
  88. */
  89.    return len;
  90. }
  91.  
  92. static int
  93. write2s(FILE *fp, char *header, struct addr *tolist)
  94. {
  95.    fputs(header, fp);
  96.    (void) writes(fp, tolist);
  97.    putc('\n', fp);
  98.  
  99.    return ferror(fp);
  100. }
  101.  
  102. int
  103. dosend(FILE *fp, char *to, char *cc, char *subj, char *from, char *msgid)
  104. {                                   
  105.    char tf[256];
  106.    FILE *tfile;
  107.    int c, argc, ret = -1;
  108.    struct addr *tolist, *cclist = NULL;
  109.    char *argv[MAXARGS];
  110.  
  111.    if ( (to == NULL) || ((argc = parse(to, argv, MAXARGS)) < 1) ||
  112.       ((tolist = make_tolist(argc, argv)) == NULL) ) {
  113.       fprintf(stderr, "bmh: no recpients, send aborted\n");
  114.       return -1;
  115.       }
  116.  
  117.    if ( (tfile = tempfile("bmh", tf, "w+")) == NULL) {
  118.       del_addrlist(tolist);
  119.       return -1;
  120.       }
  121.  
  122.    /*
  123.     *  write RFC822-compatible headers
  124.     */
  125.    fprintf(tfile, "Date: %s", ptime(time(NULL)));
  126.    fprintf(tfile, "Message-Id: <%s>\n", msgid);
  127.    fprintf(tfile, "From: %s\n", from);
  128.  
  129.    if (getrc(replyto) != NULL)
  130.       fprintf(tfile, "Reply-To: %s\n", getrc(replyto));
  131.  
  132.    write2s(tfile, "To: ", tolist);
  133.  
  134.    if (cc != NULL) 
  135.       if ( (argc = parse(cc, argv, MAXARGS)) > 0)
  136.          cclist = make_tolist(argc, argv);
  137.    if (cclist != NULL)
  138.       write2s(tfile, "Cc: ", cclist);
  139.  
  140.    fprintf(tfile, "Subject: %s\n", subj == NULL ? "" : subj);
  141.  
  142.    /*
  143.     * Hack to allow misc headers be sent
  144.     */
  145.    {
  146.       char line[256];
  147.       int done1 = 0;
  148.  
  149.       while (fgets(line, sizeof(line), fp) != NULL)
  150.          if ( (htype(line) != NOHEADER) ||
  151.               (done1 && ((line[0] == ' ') || (line[0] == '\t')))
  152.             ) {
  153.             done1 = 1;
  154.             if (fputs(line, tfile) == EOF)
  155.                goto cleanup;
  156.             }
  157.          else {
  158.             if ( (fputc('\n', tfile) == EOF) ||  /* End of message headers */
  159.                  (fputs(line, tfile) == EOF) )   /* first line of message  */
  160.                goto cleanup;
  161.             break;
  162.             }
  163.    }
  164.  
  165.    while ( (c = getc(fp)) != EOF)
  166.       if ( putc(c, tfile) == EOF )
  167.          goto cleanup;
  168.  
  169.    queuejob(tfile, tolist, 0L);
  170.    recordmsg(tfile, from);          /* save copy for sender */
  171.  
  172.    ret = 0;
  173.  
  174.    cleanup:
  175.    if (ret == -1)
  176.       perror("bmh: smtp dosend,");
  177.  
  178.    del_addrlist(tolist);
  179.  
  180.    if (cclist != NULL) {
  181.       queuejob(tfile, cclist, 0L);
  182.       del_addrlist(cclist);
  183.       }
  184.  
  185.    (void) fclose(tfile);
  186.    unlink(tf);
  187.  
  188.    return ret;
  189. }
  190.  
  191. /*
  192.  * Print out the time and date field as
  193.  *   "DAY day MONTH year hh:mm:ss ZONE"
  194.  */
  195. char *
  196. ptime(long t)
  197. {
  198.    static char str[40];
  199.    struct tm *ltm;
  200.    char tz[4];
  201.    char *p;
  202.    static char *days[7] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
  203.    static char *months[12] = {
  204.       "Jan","Feb","Mar","Apr","May","Jun",
  205.       "Jul","Aug","Sep","Oct","Nov","Dec" };
  206.  
  207.    ltm = localtime(&t); /* Read the system time */
  208.  
  209.    if ((p = getenv("TZ")) == NULL)
  210.       strcpy(tz, "GMT");
  211.    else
  212.       strncpy(tz, p, 3);
  213.  
  214.    /* rfc 822 format */
  215.    sprintf(str,"%s, %.2d %s %02d %02d:%02d:%02d %.3s\n",
  216.       days[ltm->tm_wday],
  217.       ltm->tm_mday,
  218.       months[ltm->tm_mon],
  219.       ltm->tm_year,
  220.       ltm->tm_hour,
  221.       ltm->tm_min,
  222.       ltm->tm_sec,
  223.       tz);
  224.  
  225.    return(str);
  226. }
  227.  
  228. /*
  229.  * save copy in the record file
  230.  */
  231. static int
  232. recordmsg(FILE *dfile, char *from) 
  233. {
  234.    FILE *fp;
  235.  
  236.    if (getrc(record) == NULL)
  237.       return -1;
  238.  
  239.    if ( (fp = fopen(getrc(record), "a")) == NULL)
  240.       fprintf(stderr, "bm: unable to append to %s\n", getrc(record));
  241.    else {
  242.       int c;
  243.       time_t t = time(NULL);
  244.  
  245.       fprintf(fp, "From %s %s", from, ctime(&t));
  246.       fseek(dfile, 0L, 0);
  247.  
  248.       while((c = getc(dfile)) != EOF)
  249.          if( putc(c, fp) == EOF) {
  250.             (void) fclose(fp);
  251.             return -1;
  252.             }
  253.       (void) fclose(fp);
  254.       }
  255.       
  256.    return 0;
  257. }
  258.  
  259. /*
  260.  * place a mail job in the outbound queue
  261.  */
  262. static int
  263. queuejob(FILE *dfile, struct addr *tolist, long position)
  264. {
  265.    FILE *fp;
  266.    char tmpstring[50];
  267.    struct addr *tp, *sp;
  268.    char prefix[255];
  269.    int c;
  270.    long id;
  271.  
  272.    for (tp = tolist; tp != NULL; tp = tp->next) {
  273.       if (tp->sent)
  274.          continue;
  275.       fseek(dfile, position, SEEK_SET);
  276.       id = get_msgid(getrc(mqueue));
  277.       sprintf(prefix, "%s/%ld", getrc(mqueue), id);
  278.       (void) lockit(prefix);
  279.       sprintf(tmpstring,"%s/%ld%s", getrc(mqueue), id, EXT);
  280.       if((fp = fopen(tmpstring,"w")) == NULL) {
  281.          printf("unable to open %s\n", tmpstring);
  282.          (void) bm_unlock(prefix);
  283.          return -1;
  284.       }
  285.       while((c = getc(dfile)) != EOF)
  286.          if(putc(c,fp) == EOF) {
  287.             (void) fclose(fp);
  288.             (void) bm_unlock(prefix);
  289.             return -1;
  290.             }
  291.       (void) fclose(fp);
  292.  
  293.       sprintf(tmpstring, "%s/%ld.wrk", getrc(mqueue), id);
  294.       if((fp = fopen(tmpstring, "w")) == NULL) {
  295.          (void) bm_unlock(prefix);
  296.          return -1;
  297.       }
  298.  
  299.       fprintf(fp, "%s\n%s@%s\n", tp->host, getrc(username), getrc(hostname));
  300.       fprintf(fp,"%s@%s\n",tp->user,tp->host);
  301.       tp->sent++;
  302.       /* find and other addresses to the same host */
  303.       for (sp = tp->next; sp != NULL; sp = sp->next) {
  304.          if (sp->sent)
  305.             continue;
  306.          if (strcmp(tp->host,sp->host) == 0) {
  307.             fprintf(fp,"%s@%s\n", sp->user, sp->host);
  308.             sp->sent++;
  309.          }
  310.       }
  311.       (void) fclose(fp);
  312.       (void) bm_unlock(prefix);
  313.    }
  314.    return 0;
  315. }
  316.  
  317. #define SKIPWORD(X) while(*X && *X!=' ' && *X!='\t' && *X!='\n' && *X!= ',') X++;
  318. #define SKIPSPACE(X) while(*X ==' ' || *X =='\t' || *X =='\n' || *X == ',') X++;
  319.  
  320. /*
  321.  * check for and alias and expand alias into a address list
  322.  */
  323. static struct addr *
  324. expandalias(struct addr **head, char *user)
  325. {
  326.    FILE *fp;
  327.    char *s, *p, *h;
  328.    int inalias;
  329.    struct addr *tp;
  330.    char buf[LINELEN];
  331.    
  332.    if ( (fp= fopen(getrc(alias), "r")) == NULL)
  333.       return addrecip(head, user, getrc(hostname) );
  334.  
  335.    inalias = 0;
  336.    while (fgets(buf, LINELEN, fp) != NULL) {
  337.       p = buf;
  338.       if ( *p == '#' || *p == '\0')
  339.          continue;
  340.       rip(p);
  341.  
  342.       /* if not in an matching entry skip continuation lines */
  343.       if (!inalias && isspace(*p))
  344.          continue;
  345.  
  346.       /* when processing an active alias check for a continuation */
  347.       if (inalias) {
  348.          if (!isspace(*p)) 
  349.             break;   /* done */
  350.       } else {
  351.          s = p;
  352.          SKIPWORD(p);
  353.          *p++ = '\0';   /* end the alias name */
  354.          if (strcmp(s,user) != 0)
  355.             continue;   /* no match go on */
  356.          inalias = 1;
  357.       }
  358.  
  359.       /* process the recipients on the alias line */
  360.       SKIPSPACE(p);
  361.       while(*p != '\0' && *p != '#') {
  362.          s = p;
  363.          SKIPWORD(p);
  364.          if (*p != '\0')
  365.             *p++ = '\0';
  366.          /* find hostname */
  367.          if ((h = strchr(s,'@')) != NULL)
  368.             *h++ = '\0';
  369.          else
  370.             h = getrc(hostname);
  371.          tp = addrecip(head,s,h);
  372.          SKIPSPACE(p);
  373.       }
  374.    }
  375.    (void) fclose(fp);
  376.  
  377.    if (inalias)   /* found and processed and alias. */
  378.       return tp;
  379.  
  380.    /* no alias found treat as a local address */
  381.    return addrecip(head, user, getrc(hostname));
  382. }
  383.  
  384. /*
  385.  * convert a arg list to an list of address structures
  386.  */
  387. static struct addr *
  388. make_tolist(int argc, char *argv[])
  389. {
  390.    struct addr *tolist = NULL, *tp;
  391.    int i;
  392.  
  393.    for (i = 0; i < argc; i++) {
  394.       char *user = argv[i],
  395.            *host = strchr(argv[i], '@');
  396.  
  397.       if (host != NULL) {
  398.          *host++ = '\0';
  399.          if (stricmp(host, getrc(hostname)) == 0)
  400.             host = NULL;
  401.          }
  402.  
  403.       if (host == NULL)    /* a local address */
  404.          tp = expandalias(&tolist, user);
  405.       else                 /* a remote address */
  406.          tp = addrecip(&tolist, user, host);
  407.  
  408.       if (tp == NULL) {
  409.          fprintf(stderr, "bm: out of memory\n");
  410.          del_addrlist(tolist);
  411.          return NULL;
  412.       }
  413.    }
  414.    return tolist;
  415. }
  416.  
  417. /*
  418.  * delete a list of mail addresses
  419.  */
  420. static void
  421. del_addrlist(struct addr *list)
  422. {
  423.    struct addr *tp, *tp1;
  424.  
  425.    for (tp = list; tp != NULL; tp = tp1) {
  426.       tp1 = tp->next;
  427.       if (tp->user != NULL);
  428.          free(tp->user);
  429.       if (tp->host != NULL);
  430.          free(tp->host);
  431.       free(tp);
  432.    }
  433. }
  434.  
  435. /* add an address to the from of the list pointed to by head 
  436. ** return NULL if out of memory.
  437. */
  438. static struct addr *
  439. addrecip(struct addr **head, char *user, char *host)
  440. {
  441.    struct addr *tp;
  442.  
  443.    if ( (tp = (struct addr *)calloc(1,sizeof(struct addr))) == NULL)
  444.       return NULL;
  445.  
  446.    tp->next = NULL;
  447.  
  448.    /* allocate storage for the user's login */
  449.    if ((tp->user = malloc((unsigned)strlen(user)+1)) == NULL) {
  450.       (void) free((char *)tp);
  451.       return NULL;
  452.    }
  453.    strcpy(tp->user,user);
  454.  
  455.    /* allocate storage for the host name */
  456.    if (host != NULL)
  457.       if ((tp->host = malloc((unsigned)strlen(host)+1)) == NULL) {
  458.          (void) free(tp->user);
  459.          (void) free((char *)tp);
  460.          return NULL;
  461.       }
  462.    strcpy(tp->host,host);
  463.  
  464.    /* add entry to front of existing list */
  465.    if (*head == NULL)
  466.       *head = tp;
  467.    else {
  468.       tp->next = *head;
  469.       *head = tp;
  470.    }
  471.    return tp;
  472. }
  473.  
  474. /*
  475.  * forward a message in its orginal form
  476.  */
  477. int
  478. bouncemsg(FILE *fp, char *to)
  479. {
  480.    struct addr *list;
  481.    int argc;
  482.    char *argv[MAXARGS];
  483.  
  484.    if ( ((argc = parse(to, argv, MAXARGS)) < 1) ||
  485.       ((list = make_tolist(argc, argv)) == NULL) ) {
  486.       fprintf(stderr, "bmh: no recpients, send aborted\n");
  487.       return -1;
  488.       }
  489.    else {
  490.       queuejob(fp, list, ftell(fp)); /* ftell = hack.. */
  491.       del_addrlist(list);
  492.       return 0;
  493.       }
  494. }
  495.