home *** CD-ROM | disk | FTP | other *** search
- /*************************************************************
- * DNAMAILD - handle remote mail from DECnet nodes.
- *
- * To use:
- * If compiled with -DSTANDALONE, then just execute this program
- * whenever you want to receive mail (only handles one connection).
- *
- * Without the STANDALONE option, add a line like the following to
- * /usr/sunlink/dna/dnaserver.reg:
- *
- * 27 MAIL /usr/sunlink/dna/dnamaild
- *
- * (Remember to add the line "Tdna" to sendmail.cf, since
- * this program gets run as user "dna". This is not needed if
- * compiled with STANDALONE option.)
- *
- * Copyright
- * Darin Johnson, Lockheed Missiles and Space
- *
- * Permission to copy and/or modify as long as reference is made
- * to the authors. This program may not be sold.
- *************************************************************/
-
- #include <stdio.h>
- #include <ctype.h>
- #include <signal.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <netdna/dna.h>
- #include "dnamail.h"
-
- /* External variable definitions */
- extern int errno; /* External variable errno */
-
- /* Global data definitions */
- short ll; /* Logical link identifier */
- char buffer[MAXLINE]; /* Character buffer */
- char *my_hostname;
- OpenBlock opblk; /* OpenBlock */
- Image16 idata;
- struct ses_io_type sesopts;
- SessionData sd = {0, {0, ""}};
-
- FILE *tmpf;
- char tmp_name[32];
- char *from;
-
- /* list of addresses */
- typedef struct addr_struct {
- char *addr;
- struct addr_struct *next;
- } ADDRESS;
-
- ADDRESS *addr_head, *addr_tail;
-
- /* use a variable, since ioctl() wants an address to this */
- short T_num = MAIL_OBJECT;
-
- /* if we are not run from dnaserver, then we have to set up our own link */
- #ifdef STANDALONE
- get_connection() { /* get decnet connection set up */
- int ret;
-
- /*
- * Before establishing a logical link, we must first
- * open the logical link device, "/dev/dna".
- */
- if ((ll = open("/dev/dna", O_RDWR)) < 0)
- dna_exit("Open Fail");
-
- if (ioctl(ll, SES_GET_LINK, 0))
- dna_exit("Error getting a logical link");
-
- /*
- * Next, we must register ourself as a server.
- */
-
- ret = ioctl(ll, SES_NUM_SERVER, &T_num);
- if (ret == -1)
- dna_exit("Server Registration Failed");
-
- if (ioctl(ll, SES_GET_AI, &opblk) < 0)
- dna_exit("Ioctl Get AI Failed");
-
- if (ioctl(ll, SES_ACCEPT, &sd) < 0)
- dna_exit("Ioctl Accept failed");
- } /* end received Open Block */
- #endif STANDALONE
-
- /* add address onto list */
- add_address(user)
- char *user;
- {
- ADDRESS *tmpa;
- tmpa = (ADDRESS*)malloc(sizeof(ADDRESS));
- tmpa->addr = copystr(user);
- tmpa->next = NULL;
- if (addr_tail) {
- addr_tail->next = tmpa;
- addr_tail = tmpa;
- } else {
- addr_head = addr_tail = tmpa;
- }
- }
-
- /* deliver completed message to all recipients */
- deliver() {
- #ifdef DEBUG
- return;
- #else
- FILE *sm;
- ADDRESS *tmp, *jnk;
- char c;
- int ret;
-
- /* close temporary file since we are done writing to it */
- fclose(tmpf);
- /* reopen it so we can send it */
- tmpf = fopen(tmp_name, "r");
- if (!tmpf) {
- dna_exit("Can't open temp file");
- }
- tmp = addr_head;
- /* loop through each recipient */
- while (tmp!=NULL) {
- /* build command */
- sprintf(buffer, "/usr/lib/sendmail -oem -f \"%s\" %s",
- from, tmp->addr);
- #ifdef DEBUG
- fprintf(stderr, "cmd = <%s>\n", buffer);
- #endif
- /* open pipe to sendmail command */
- if (sm = popen(buffer, "w")) {
- rewind(tmpf);
- /* now copy temp file to pipe */
- while ((c=getc(tmpf))!=EOF)
- putc(c, sm);
- ret = pclose(sm);
- /* check errors */
- if (ret) {
- sprintf(buffer, "sendmail can't send to %s on %s", tmp->addr, my_hostname);
- status_err(buffer); /* send status back to remote node */
- } else
- status_ok(); /* send status back to remote node */
- } else
- dna_exit("Can't connect to sendmail");
- /* now go to next address */
- jnk = tmp;
- tmp=tmp->next;
- cfree(jnk->addr);
- free(jnk);
- }
- fclose(tmpf);
- tmpf = NULL;
- #endif
- }
-
- /* clean up username from VMS side -
- VMS format is: USERNAME "comment"
- we want: USERNAME (comment)
- There also may be quotes around the username, so they get zapped.
- I am unsure of the exact format used by VMS, but this hasn't caused
- trouble so far...
- We also append the remote node name to the front.
- */
- fix_user(str)
- char *str;
- {
- char *fq, *lq;
- if (*str == '"') { /* remove quotes around username */
- str++;
- fq = (char *)index(str, '"');
- *fq = ' ';
- } else {
- fq = (char *)index(str, '"');
- lq = (char *)rindex(str, '"');
- if (fq && lq && fq < lq) {
- /* convert quotes */
- *fq = '(';
- *lq = ')';
- }
- }
- /* we have to set this up for sendmail */
- from = (char *)calloc(strlen(str)+strlen(opblk.op_node_name)+5, 1);
- sprintf(from, "%s!%s", opblk.op_node_name, str);
- }
-
- /* Actually receive the mail. Places all recipients into a list and
- saves the message/headers into a temporary file. Mail protocol was
- derived from VMS microfiche. See dnamail.c for other half of protocol.
-
- Protocol:
- 1) read a record - if EOF, then exit
- 2) record read in 1) is who the mail is "From:"
- 3) loop until a 'marker' is read (record containing single NULL)
- a) read recipient address
- b) send back OK status (really, the status should tell if
- this address is good and/or the user exists, but I ignore
- this part since sendmail we mail errors back)
- 4) read "To: line. This is the line typed by the VMS mail user
- to specify the recipients. Used only as part of the header.
- 5) read "Subject:" line. Used only as part of the header.
- 6) keep reading message body until a 'marker' is seen.
- 7) now send back a status for each address from 3a) above
- indicating whether the message was delivered or not. (Note
- that we shouldn't send back a status if we sent back a bad
- status in 3b), which we don't do anyway)
- 8) go to step 1), in case there are more messages being sent
- (in case VMS decides to 'cache' this link)
- */
- receive_mail() {
- int len, ret;
-
- while (1) {
- len=get(buffer);
- if (len < 0) { /* no more messages being sent */
- #ifdef DEBUG
- fprintf(stderr, "DONE!!\n");
- #endif
- break;
- }
-
- /* add our own header for tracking purposes */
- fprintf(tmpf, "Received: by %s; %s\n", version, mailtime());
-
- #ifdef DEBUG
- fprintf(stderr, "USER = <%*s>\n", len, buffer);
- #endif
- /* record read above is USER */
- buffer[len]=NULL;
- fix_user(buffer);
- fprintf(tmpf, "From: %s\n", from);
- /* get list of recipients */
- while (1) {
- len = get(buffer);
- if (len==1 && buffer[0]==NULL) { /* end of list */
- #ifdef DEBUG
- fprintf(stderr, "(MARKER)\n");
- #endif
- break;
- }
- #ifdef DEBUG
- fprintf(stderr, "ADDR = <%*s>\n", len, buffer);
- #endif
- buffer[len] = NULL;
- add_address(buffer); /* add address to list */
- status_ok(); /* send back OK status since we aren't checking now */
- }
-
- /* get the To: line */
- len = check_get(buffer);
- #ifdef DEBUG
- fprintf(stderr, "TO = <%*s>\n", len, buffer);
- #endif
- buffer[len] = NULL;
- fprintf(tmpf, "To: %s\n", buffer);
- /* get Subject: line */
- len = check_get(buffer);
- #ifdef DEBUG
- fprintf(stderr, "SUBJ = <%*s>\n", len, buffer);
- #endif
- buffer[len]=NULL;
- fprintf(tmpf, "Subject: %s\n", buffer);
- fprintf(tmpf, "\n"); /* mark end of headers */
- /* now get message */
- while (1) {
- len = check_get(buffer);
- if (len==1 && buffer[0]==NULL) { /* end of message */
- #ifdef DEBUG
- fprintf(stderr, "(MARKER)\n");
- #endif
- break;
- }
- #ifdef DEBUG
- fprintf(stderr, "TXT = <%*s>\n", len, buffer);
- #endif
- buffer[len]=NULL;
- fprintf(tmpf, "%s\n", buffer);
- }
- #ifdef DEBUG
- fprintf(stderr, " Sending message\n");
- #endif
- /* now try to deliver the message */
- deliver();
- }
- }
-
- /* send string over decnet link */
- send(s, len)
- char *s;
- int len;
- {
- if (write(ll, s, len) < 0)
- dna_exit("SEND");
- }
-
- /* do a get(), but check errors here */
- int check_get(s)
- char *s;
- {
- int l;
- if ((l=get(s))<0)
- dna_exit("GET");
- }
-
- /* read a string from decnet link. Return length of string. */
- int get(s)
- char *s;
- {
- int len, readmask;
- /* using select() here since it was needed earlier in development,
- don't know if it is needed now */
- readmask = 1 << ll;
- if ((len=select(32, &readmask, 0, 0, 0)) < 0) {
- perror("select");
- my_exit(1);
- }
- if ((len=read(ll, s, MAXLINE)) >= 0)
- s[len] = NULL; /* close off string */
- return len;
- }
-
- /* print out decnet error and call my_exit() */
- dna_exit(str)
- char *str;
- {
- dnaerror(str);
- my_exit(1);
- }
-
- /* cleanup and then exit() */
- my_exit(st)
- int st;
- {
- if (tmpf) {
- fclose(tmpf);
- #ifndef DEBUG
- unlink(tmp_name);
- #endif
- }
- exit(st);
- }
-
- /* send OK status up decnet link */
- status_ok()
- {
- long st;
- st = 0x01000000; /* same as 0x1 on VAX */
- send(&st, sizeof(long));
- }
-
- /* send error status and message up decnet link */
- status_err(msg)
- char *msg;
- {
- long st;
- st = 0x00000000;
- send(&st, sizeof(long));
- send(msg, strlen(msg));
- send("", 1); /* mark end of message */
- }
-
- /* if we are standalone we call get_connection, otherwise
- dnaserver has passed number of file descriptor for logical link
- in argv */
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int i;
- /* always a good practice to do this when creating temp files */
- for (i=0; i<20; i++)
- if (signal(i, SIG_IGN)!=SIG_IGN)
- signal(i, my_exit);
-
- gethostname(buffer, sizeof(buffer));
- my_hostname = copystr(buffer);
-
- #ifdef STANDALONE
- get_connection();
- #else
- /* set up ll to point be descriptor passed */
- if (argc<2 || (ll=atoi(argv[1]))==0) {
- fprintf(stderr, "%s: Aborting, should not be run interactively\n", argv[0]);
- exit(1);
- }
- /* accept link */
- if (ioctl(ll, SES_GET_AI, &opblk) < 0)
- dna_exit("Ioctl Get AI Failed");
- if (ioctl(ll, SES_ACCEPT, &sd) < 0)
- dna_exit("Ioctl Accept failed");
- #endif
-
- /* create temp file */
- strcpy(tmp_name, TMPFILE),
- mktemp(tmp_name);
- tmpf = fopen(tmp_name, "w");
- addr_head = addr_tail = NULL;
-
- /* now read mail from link - actually we may have to wait around
- while the user types in the message, but this shouldn't bother
- us */
- receive_mail();
-
- /* cleanup */
- fclose(tmpf);
- unlink(tmp_name);
- close(ll);
- return;
- }
-