home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume3 / dnamail / dnamaild.c < prev    next >
C/C++ Source or Header  |  1989-02-03  |  10KB  |  411 lines

  1. /*************************************************************
  2. * DNAMAILD - handle remote mail from DECnet nodes.
  3. *
  4. * To use:
  5. *   If compiled with -DSTANDALONE, then just execute this program
  6. *   whenever you want to receive mail (only handles one connection).
  7. *
  8. *   Without the STANDALONE option, add a line like the following to
  9. *   /usr/sunlink/dna/dnaserver.reg:
  10. *
  11. *     27  MAIL  /usr/sunlink/dna/dnamaild
  12. *
  13. *   (Remember to add the line "Tdna" to sendmail.cf, since
  14. *   this program gets run as user "dna".  This is not needed if
  15. *   compiled with STANDALONE option.)
  16. *
  17. * Copyright
  18. *  Darin Johnson, Lockheed Missiles and Space
  19. *
  20. * Permission to copy and/or modify as long as reference is made
  21. * to the authors.  This program may not be sold.
  22. *************************************************************/
  23.  
  24. #include    <stdio.h>
  25. #include    <ctype.h>
  26. #include    <signal.h>
  27. #include    <fcntl.h>
  28. #include    <sys/ioctl.h>
  29. #include    <netdna/dna.h>
  30. #include    "dnamail.h"
  31.  
  32. /* External variable definitions */
  33. extern int errno;        /* External variable errno     */
  34.  
  35. /* Global data definitions */
  36. short ll;            /* Logical link identifier     */
  37. char buffer[MAXLINE];        /* Character buffer          */
  38. char *my_hostname;
  39. OpenBlock opblk;        /* OpenBlock              */
  40. Image16 idata;
  41. struct ses_io_type sesopts;
  42. SessionData sd = {0, {0, ""}};
  43.  
  44. FILE *tmpf;
  45. char tmp_name[32];
  46. char *from;
  47.  
  48.   /* list of addresses */
  49. typedef struct addr_struct {
  50.   char *addr;
  51.   struct addr_struct *next;
  52. } ADDRESS;
  53.  
  54. ADDRESS *addr_head, *addr_tail;
  55.  
  56.   /* use a variable, since ioctl() wants an address to this */
  57. short T_num = MAIL_OBJECT;
  58.  
  59. /* if we are not run from dnaserver, then we have to set up our own link */
  60. #ifdef STANDALONE
  61. get_connection() {        /* get decnet connection set up */
  62. int ret;
  63.  
  64. /*
  65.  * Before establishing a logical link, we must first
  66.  * open the logical link device, "/dev/dna". 
  67.  */
  68. if ((ll = open("/dev/dna", O_RDWR)) < 0)
  69. dna_exit("Open Fail");
  70.  
  71. if (ioctl(ll, SES_GET_LINK, 0)) 
  72. dna_exit("Error getting a logical link");
  73.  
  74. /*
  75.  * Next, we must register ourself as a server.
  76.  */
  77.  
  78. ret = ioctl(ll, SES_NUM_SERVER, &T_num);
  79. if (ret == -1)
  80. dna_exit("Server Registration Failed");
  81.  
  82. if (ioctl(ll, SES_GET_AI, &opblk) < 0)
  83. dna_exit("Ioctl Get AI Failed");
  84.  
  85. if (ioctl(ll, SES_ACCEPT, &sd) < 0)
  86. dna_exit("Ioctl Accept failed");
  87. }        /* end received Open Block */
  88. #endif STANDALONE
  89.  
  90. /* add address onto list */
  91. add_address(user)
  92. char *user;
  93. {
  94.   ADDRESS *tmpa;
  95.   tmpa = (ADDRESS*)malloc(sizeof(ADDRESS));
  96.   tmpa->addr = copystr(user);
  97.   tmpa->next = NULL;
  98.   if (addr_tail) {
  99.     addr_tail->next = tmpa;
  100.     addr_tail = tmpa;
  101.   } else {
  102.     addr_head = addr_tail = tmpa;
  103.   }
  104. }
  105.  
  106. /* deliver completed message to all recipients */
  107. deliver() {
  108. #ifdef DEBUG
  109.   return;
  110. #else
  111.   FILE *sm;
  112.   ADDRESS *tmp, *jnk;
  113.   char c;
  114.   int ret;
  115.  
  116.     /* close temporary file since we are done writing to it */
  117.   fclose(tmpf);
  118.     /* reopen it so we can send it */
  119.   tmpf = fopen(tmp_name, "r");
  120.   if (!tmpf) {
  121.     dna_exit("Can't open temp file");
  122.   }
  123.   tmp = addr_head;
  124.     /* loop through each recipient */
  125.   while (tmp!=NULL) {
  126.       /* build command */
  127.     sprintf(buffer, "/usr/lib/sendmail -oem -f \"%s\" %s",
  128.          from, tmp->addr);
  129. #ifdef DEBUG
  130.     fprintf(stderr, "cmd = <%s>\n", buffer);
  131. #endif
  132.       /* open pipe to sendmail command */
  133.     if (sm = popen(buffer, "w")) {
  134.       rewind(tmpf);
  135.     /* now copy temp file to pipe */
  136.       while ((c=getc(tmpf))!=EOF)
  137.     putc(c, sm);
  138.       ret = pclose(sm);
  139.         /* check errors */
  140.       if (ret) {
  141.     sprintf(buffer, "sendmail can't send to %s on %s", tmp->addr, my_hostname);
  142.     status_err(buffer);    /* send status back to remote node */
  143.       } else
  144.     status_ok();    /* send status back to remote node */
  145.     } else
  146.       dna_exit("Can't connect to sendmail");
  147.     /* now go to next address */
  148.     jnk = tmp;
  149.     tmp=tmp->next;
  150.     cfree(jnk->addr);
  151.     free(jnk);
  152.   }
  153.   fclose(tmpf);
  154.   tmpf = NULL;
  155. #endif
  156. }
  157.  
  158. /* clean up username from VMS side -
  159.      VMS format is:  USERNAME        "comment"
  160.      we want:        USERNAME        (comment) 
  161.    There also may be quotes around the username, so they get zapped.
  162.    I am unsure of the exact format used by VMS, but this hasn't caused
  163.    trouble so far...
  164.    We also append the remote node name to the front.
  165. */
  166. fix_user(str)
  167. char *str;
  168. {
  169.   char *fq, *lq;
  170.   if (*str == '"') {    /* remove quotes around username */
  171.     str++;
  172.     fq = (char *)index(str, '"');
  173.     *fq = ' ';
  174.   } else {
  175.     fq = (char *)index(str, '"');
  176.     lq = (char *)rindex(str, '"');
  177.     if (fq && lq && fq < lq) {
  178.         /* convert quotes */
  179.       *fq = '(';
  180.       *lq = ')';
  181.     }
  182.   }
  183.     /* we have to set this up for sendmail */
  184.   from = (char *)calloc(strlen(str)+strlen(opblk.op_node_name)+5, 1);
  185.   sprintf(from, "%s!%s", opblk.op_node_name, str);
  186. }
  187.  
  188. /* Actually receive the mail.  Places all recipients into a list and
  189.    saves the message/headers into a temporary file.  Mail protocol was
  190.    derived from VMS microfiche.  See dnamail.c for other half of protocol.
  191.  
  192.    Protocol:
  193.      1) read a record - if EOF, then exit
  194.      2) record read in 1) is who the mail is "From:"
  195.      3) loop until a 'marker' is read (record containing single NULL)
  196.        a) read recipient address
  197.        b) send back OK status (really, the status should tell if
  198.       this address is good and/or the user exists, but I ignore
  199.       this part since sendmail we mail errors back)
  200.      4) read "To: line.  This is the line typed by the VMS mail user
  201.     to specify the recipients.  Used only as part of the header.
  202.      5) read "Subject:" line.  Used only as part of the header.
  203.      6) keep reading message body until a 'marker' is seen.
  204.      7) now send back a status for each address from 3a) above
  205.     indicating whether the message was delivered or not.  (Note
  206.     that we shouldn't send back a status if we sent back a bad
  207.     status in 3b), which we don't do anyway)
  208.      8) go to step 1), in case there are more messages being sent
  209.     (in case VMS decides to 'cache' this link)
  210. */
  211. receive_mail() {
  212.   int len, ret;
  213.  
  214.   while (1) {
  215.     len=get(buffer);
  216.     if (len < 0) {    /* no more messages being sent */
  217. #ifdef DEBUG
  218.       fprintf(stderr, "DONE!!\n");
  219. #endif
  220.       break;
  221.     }
  222.  
  223.       /* add our own header for tracking purposes */
  224.     fprintf(tmpf, "Received: by %s; %s\n", version, mailtime());
  225.  
  226. #ifdef DEBUG
  227.     fprintf(stderr, "USER = <%*s>\n", len, buffer);
  228. #endif
  229.       /* record read above is USER */
  230.     buffer[len]=NULL;
  231.     fix_user(buffer);
  232.     fprintf(tmpf, "From: %s\n", from);
  233.       /* get list of recipients */
  234.     while (1) {
  235.       len = get(buffer);
  236.       if (len==1 && buffer[0]==NULL) {        /* end of list */
  237. #ifdef DEBUG
  238.     fprintf(stderr, "(MARKER)\n");
  239. #endif
  240.     break;
  241.       }
  242. #ifdef DEBUG
  243.       fprintf(stderr, "ADDR = <%*s>\n", len, buffer);
  244. #endif
  245.       buffer[len] = NULL;
  246.       add_address(buffer);    /* add address to list */
  247.       status_ok();    /* send back OK status since we aren't checking now */
  248.     }      
  249.  
  250.       /* get the To: line */
  251.     len = check_get(buffer);
  252. #ifdef DEBUG
  253.     fprintf(stderr, "TO = <%*s>\n", len, buffer);
  254. #endif
  255.     buffer[len] = NULL;
  256.     fprintf(tmpf, "To: %s\n", buffer);
  257.       /* get Subject: line */
  258.     len = check_get(buffer);
  259. #ifdef DEBUG
  260.     fprintf(stderr, "SUBJ = <%*s>\n", len, buffer);
  261. #endif
  262.     buffer[len]=NULL;
  263.     fprintf(tmpf, "Subject: %s\n", buffer);
  264.     fprintf(tmpf, "\n");    /* mark end of headers */
  265.       /* now get message */
  266.     while (1) {
  267.       len = check_get(buffer);
  268.       if (len==1 && buffer[0]==NULL) {    /* end of message */
  269. #ifdef DEBUG
  270.     fprintf(stderr, "(MARKER)\n");
  271. #endif
  272.     break;
  273.       }
  274. #ifdef DEBUG
  275.       fprintf(stderr, "TXT = <%*s>\n", len, buffer);
  276. #endif
  277.       buffer[len]=NULL;
  278.       fprintf(tmpf, "%s\n", buffer);
  279.     }
  280. #ifdef DEBUG
  281.     fprintf(stderr, "    Sending message\n");
  282. #endif
  283.       /* now try to deliver the message */
  284.     deliver();
  285.   }
  286. }
  287.  
  288. /* send string over decnet link */
  289. send(s, len)
  290. char *s;
  291. int len;
  292. {
  293.   if (write(ll, s, len) < 0)
  294.     dna_exit("SEND");
  295. }
  296.  
  297. /* do a get(), but check errors here */
  298. int check_get(s)
  299. char *s;
  300. {
  301.   int l;
  302.   if ((l=get(s))<0)
  303.     dna_exit("GET");
  304. }
  305.  
  306. /* read a string from decnet link.  Return length of string. */
  307. int get(s)
  308. char *s;
  309. {
  310.   int len, readmask;
  311.     /* using select() here since it was needed earlier in development,
  312.        don't know if it is needed now */
  313.   readmask = 1 << ll;
  314.   if ((len=select(32, &readmask, 0, 0, 0)) < 0) {
  315.     perror("select");
  316.     my_exit(1);
  317.   }
  318.   if ((len=read(ll, s, MAXLINE)) >= 0)
  319.     s[len] = NULL;    /* close off string */
  320.   return len;
  321. }
  322.  
  323. /* print out decnet error and call my_exit() */
  324. dna_exit(str)
  325. char *str;
  326. {
  327.     dnaerror(str);
  328.     my_exit(1);
  329. }
  330.  
  331. /* cleanup and then exit() */
  332. my_exit(st)
  333. int st;
  334. {
  335.   if (tmpf) {
  336.     fclose(tmpf);
  337. #ifndef DEBUG
  338.     unlink(tmp_name);
  339. #endif
  340.   }
  341.   exit(st);
  342. }
  343.  
  344. /* send OK status up decnet link */
  345. status_ok()
  346. {
  347.   long st;
  348.   st = 0x01000000;    /* same as 0x1 on VAX */
  349.   send(&st, sizeof(long));
  350. }
  351.  
  352. /* send error status and message up decnet link */
  353. status_err(msg)
  354. char *msg;
  355. {
  356.   long st;
  357.   st = 0x00000000;
  358.   send(&st, sizeof(long));
  359.   send(msg, strlen(msg));
  360.   send("", 1);    /* mark end of message */
  361. }
  362.  
  363. /* if we are standalone we call get_connection, otherwise
  364.    dnaserver has passed number of file descriptor for logical link
  365.    in argv */
  366. main(argc, argv)
  367. int argc;
  368. char *argv[];
  369. {
  370.   int i;
  371.     /* always a good practice to do this when creating temp files */
  372.   for (i=0; i<20; i++)
  373.     if (signal(i, SIG_IGN)!=SIG_IGN)
  374.       signal(i, my_exit);
  375.  
  376.   gethostname(buffer, sizeof(buffer));
  377.   my_hostname = copystr(buffer);
  378.  
  379. #ifdef STANDALONE
  380.   get_connection();
  381. #else
  382.     /* set up ll to point be descriptor passed */
  383.   if (argc<2 || (ll=atoi(argv[1]))==0) {
  384.     fprintf(stderr, "%s: Aborting, should not be run interactively\n", argv[0]);
  385.     exit(1);
  386.   }
  387.     /* accept link */
  388.   if (ioctl(ll, SES_GET_AI, &opblk) < 0)
  389.     dna_exit("Ioctl Get AI Failed");
  390.   if (ioctl(ll, SES_ACCEPT, &sd) < 0)
  391.     dna_exit("Ioctl Accept failed");
  392. #endif
  393.  
  394.     /* create temp file */
  395.   strcpy(tmp_name, TMPFILE),
  396.   mktemp(tmp_name);
  397.   tmpf = fopen(tmp_name, "w");
  398.   addr_head = addr_tail = NULL;
  399.  
  400.     /* now read mail from link - actually we may have to wait around
  401.        while the user types in the message, but this shouldn't bother
  402.        us */
  403.   receive_mail();
  404.  
  405.     /* cleanup */
  406.   fclose(tmpf);
  407.   unlink(tmp_name);
  408.   close(ll);
  409.   return;
  410. }
  411.