darin@decwrl.dec.com@c.UUCP (Darin Johnson) (05/09/88)
comp.sources.misc: Volume 3, Issue 12 Submitted-By: "Darin Johnson" <darin@decwrl.dec.com@c.UUCP> Archive-Name: dnamail This mailer handles decnet mail to/from a Sun running Sunlink/DNI. I am posting this mailer to both comp.sys.sun and comp.sources.misc. The reason for both groups is that I used to have problems getting sources from the comp.sys.sun archives, and I assume other people still have this problem. The following is a shar file, you should know what to do... ================ Cut, fold, or mutilate here ======================== #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # Makefile # README # dnamail.doc # dnamail.h # dnamail.c # dnamaild.c # dnamisc.c # dnaerror.c # main.diff # sub.diff # This archive created: Sun May 8 13:56:04 1988 export PATH; PATH=/bin:$PATH echo shar: extracting "'Makefile'" '(415 characters)' if test -f 'Makefile' then echo shar: will not over-write existing file "'Makefile'" else cat << \SHAR_EOF > 'Makefile' # DISTRIB = Makefile README dnamail.doc dnamail.h dnamail.c dnamaild.c dnamisc.c \ dnaerror.c main.diff sub.diff OBJS = dnaerror.o dnamisc.o all: dnamail dnamaild dnamail: dnamail.o $(OBJS) cc -o dnamail dnamail.o $(OBJS) dnamaild: dnamaild.o $(OBJS) cc -o dnamaild dnamaild.o $(OBJS) dnamail.o dnamaild.o dnamisc.o: dnamail.h shar: $(DISTRIB) shar -cv $(DISTRIB) > dnamail.shar clean: rm -f *.o core SHAR_EOF if test 415 -ne "`wc -c < 'Makefile'`" then echo shar: error transmitting "'Makefile'" '(should have been 415 characters)' fi chmod +x 'Makefile' fi # end of overwriting check echo shar: extracting "'README'" '(877 characters)' if test -f 'README' then echo shar: will not over-write existing file "'README'" else cat << \SHAR_EOF > 'README' OK, here is my mailer for use with Sunlink/DNI. You may use this with or without sendmail, although using it with sendmail is much more convenient (although it requires changes to the sendmail configuration files.) 1) Read dnamail.doc for instructions 2) The patch files should work with the default 'sendmail.cf' files off of the Sun distribution tape. If not, you can install the patches by hand. Be SURE to keep the ".orig" files around in case of problems. 4) Let me know of any problems you have setting this up, or of any bugs. This way I can either fix the code, or fix the documentation. Note the copyright restrictions (as small as they are). Of course, if Sun is negotiable, I may let them have it ;-) Darin Johnson Lockheed Missiles & Space (...lll-lcc.arpa!leadsv!laic!darin) (...ucbvax!sun!sunncal!leadsv!laic!darin) SHAR_EOF if test 877 -ne "`wc -c < 'README'`" then echo shar: error transmitting "'README'" '(should have been 877 characters)' fi chmod +x 'README' fi # end of overwriting check echo shar: extracting "'dnamail.doc'" '(9031 characters)' if test -f 'dnamail.doc' then echo shar: will not over-write existing file "'dnamail.doc'" else cat << \SHAR_EOF > 'dnamail.doc' 1) Intro Dnamail and dnamaild allow a Sun computer with the Sunlink/DNI software to send and receive mail from VMS computers (may work with other DECnet computers, but hasn't been tested). These programs cooperate with the sendmail program, so that users do not need to use any special commands to send and receive mail. This means that 'mailtool' may be used to read and compose messages. Dnamail may also be used independently of sendmail, although message editing is lacking. 2) Installation >> The DNI software has a bug that needs to be fixed before >> dnamail will work. The bug is related to failure to read/write >> zero-length records. You can get the patch from Sun >> (bug #1007228), and possibly from the sun archives at rice.edu. >> You could possibly get them from me, but save this as a last resort. Look over 'Makefile' and 'dnamail.h'. If you want to have dnamaild run 'standalone', then uncomment the STANDALONE definition in dnamail.h. When dnamaild is compiled with the STANDALONE option, then it will not automatically be called from dnaserver, but must be run before you expect any mail to show up. It will handle one mail connection and then exit. Obviously, this option is not too useful, but it helps if you are trying to debug. Do 'make all'. This should make the executables 'dnamail' and 'dnamaild'. Put the executables into /usr/sunlink/dna, or use a symbolic link. Add the following line to /usr/sunlink/dna/dnaserver.reg (if you want to run dnamaild 'standalone', then you shouldn't do this): 27 MAIL /usr/sunlink/dna/dnamaild Modify sendmail.cf appropriately and restart sendmail. Test... Before making sendmail.cf changes, you can try running dnamail directly - just type /usr/sunlink/dna/dnamail. After making the sendmail.cf changes, you can test by just sending mail. 3) Sendmail.cf changes In order to have dnamail and dnamaild cooperate with sendmail, changes must be made to /usr/lib/sendmail.cf. >> If you have made changes to sendmail.cf before, or no someone >> who has, then the modifications will be relatively straightforward. >> If you don't fit into the above category, then I suggest that you >> read the 'Sendmail Installation and Operation' tutorial in the >> Sun system administrators guide to familiarize yourself with >> sendmail. On the Sun installation tape(s), sendmail.cf came in two forms, sendmail.main.cf and sendmail.subsidiary.cf. With dnamail, there are four combinations - main, subsidiary, sub_decnet, and main_decnet. Remember to make a symbolic link to the correct file on each machine (see the Sun system administrators manual). 'diff' output is included in this distribution showing the changes to be made to the original sendmail.main.cf and sendmail.subsidiary.cf so that they will handle DECnet. If you have not changed your original .cf much from the original SMI-3.2 version, then the patches may work as is. If not, then use the patches and the following instructions as a guide. Even if patch works, you still need to read these instructions (two other files need changing). Briefly - use patch to create new version of the .cf files. Then for every Sun that runs DNI, uncomment the 'DSdnahost' line for it (use a private copy!). REMEMBER: Make backups of the original .cf files!! It also helps to comment each of the lines you changed. Here are the basic changes. Anything that looks like multiple spaces should actually be a tab. - in /etc/hosts, add 'dnahost' as an alternate name for the machine you want to be the DECnet relay. For example, my site has: 192.9.200.1 nova dnahost If you have more than one machine running Sunlink/DNI, then pick one machine to be the relay for machines without Sunlink/DNI. - Edit a file called "/usr/sunlink/dna/dnahosts" to contain a list of all VMS/DECnet nodes you want to send mail to, one node per line. You do not need to have ALL the VMS machines listed, just the ones you want to send mail to (a listed machine can deliver mail to a machine that you didn't list). - Add the following lines somewhere near the beginning of sendmail.main.cf and sendmail.subsidiary.cf. # Major decnet relay (relayed by #ether) DSdnahost # get list of decnet machines we want to be able to send mail to FS/usr/sunlink/dna/dnahosts The DS line defines a macro, $S, to be the name of the machine that will actually connect to DECnet. Any machine that can't handle DECnet mail will forward any DECnet mail to this machine to handle it instead. If all your machines are on DECnet, then you don't need to do this. If you already have a $S macro (search for ^DS in vi), then choose an unused macro instead. The FS line defines a class, $S, that defines the VMS nodes we can send mail to with dnamail. - Add 'dna' as a trusted user. Look for the following lines in sendmail.main.cf and sendmail.subsidiary.cf: Troot Tdaemon Tuucp and add the following line to these: Tdna - In sendmail.main.cf (only), look for the following lines (in ruleset 0): # resolve UUCP domain R<@$-.uucp>:$+ $#uucp $@$1 $:$2 @host.uucp:... and add these next lines BEFORE them: #################################################### # If $S (decnet gateway) is defined, then forward to $S, else # resolve to dna mailer. #################################################### R$+<@$=S> $?S $#ether $@$S $:$2!$1 $| $#dna $@$2 $:$1 $. R$+<@$=S.uucp> $?S $#ether $@$S $:$2!$1 $| $#dna $@$2 $:$1 $. (If you aren't using 'S' as the macro for 'dnahost', then subsitute in the macro letter you are using). - In sendmail.subsidiary.cf (only), look for the following lines (in ruleset 0): # optimize names of known ethernet hosts R$*<@$*$%y.LOCAL>$* $#ether $@$3 $:$1<@$2$3>$4 user@host.here and add these next lines BEFORE them: #################################################### # If $S (decnet gateway) is defined, then forward to $S, else # resolve to dna mailer. #################################################### R$+<@$=S> $?S $#ether $@$S $:$2!$1 $| $#dna $@$2 $:$1 $. R$+<@$=S.uucp> $?S $#ether $@$S $:$2!$1 $| $#dna $@$2 $:$1 $. (If you aren't using 'S' as the macro for 'dnahost', then subsitute in the macro letter you are using). - Add the following lines to sendmail.main.cf and sendmail.subsidiary.cf (at the end of the file, or grouped with the other mailer definitions): ############################################################ ############################################################ ##### ##### DECnet Mailer specification ##### ##### Messages processed by this configuration are assumed to leave ##### the internet domain. Hence, they may not necessarily correspond ##### to RFC822 in all details. ##### ############################################################ ############################################################ Mdna, P=/usr/sunlink/dna/dnamail, F=mnSF, S=14, R=24, A=dnamail -f $f -n $h $u S14 # none needed S24 # none needed - Now copy sendmail.main.cf to sendmail.main_decnet.cf. Also copy sendmail.subsidiary.cf to sendmail.sub_decnet.cf. Edit both of these new files and change the following line: DSdnahost to: # DSdnahost (this comments the line out). This one line should be the only change. Now for each machine that is a valid DECnet node, make a link from sendmail.cf (in /private/usr/lib for standard installations) to sendmail.main_decnet.cf or sendmail.sub_decnet.cf. Depending upon whether the machine is a main mail machine or not, use one of the following commands: ln -s /usr/lib/sendmail.main_decnet.cf /private/usr/lib/sendmail.cf or ln -s /usr/lib/sendmail.sub_decnet.cf /private/usr/lib/sendmail.cf That's it!! After making the changes, you need to restart sendmail. Since sendmail does not have the capability of 're-reading' the configuration file, you will have to stop the currently running sendmail, and then run it again (as root) with the same parameters as the old invocation (usually, /usr/lib/sendmail -bd -q1h). 4) Usage If the installation has gone smoothly, everything should be nearly transparent to users. To send mail from Sun to VAX, use an address like: vmsnode!user To send mail fromt VAX to Sun, use an address like: SUNNODE::"user" The quotes (") are necessary so that VMS mail does not convert everything to uppercase. Longer addresses are just as easy: SUNNODE::"node1!node2!..." (In this case, leaving off the quotes causes the '!' to be treated as comment characters). To set mail to be forwarded from the vax, you will have to use 3 quotes instead of one: SET FORWARD SOMESUN::"""someuser""" SHAR_EOF if test 9031 -ne "`wc -c < 'dnamail.doc'`" then echo shar: error transmitting "'dnamail.doc'" '(should have been 9031 characters)' fi chmod +x 'dnamail.doc' fi # end of overwriting check echo shar: extracting "'dnamail.h'" '(460 characters)' if test -f 'dnamail.h' then echo shar: will not over-write existing file "'dnamail.h'" else cat << \SHAR_EOF > 'dnamail.h' /* these lines get compiled into every object file */ static char *version = "DnaMail (v1.1)"; static char *CopyRight = "Copyright (C) D. B. Johnson, Feb., 1988; Lockheed Missiles & Space"; /* uncomment this if you want to run standalone */ /* #define STANDALONE */ /* local defines */ #define MAXLINE 256 #define MAIL_OBJECT 27 #define TMPFILE "/tmp/dnamail.XXXXXX" #define TRUE 1 #define FALSE 0 /* external routines */ char *copystr(), *mailtime(); SHAR_EOF if test 460 -ne "`wc -c < 'dnamail.h'`" then echo shar: error transmitting "'dnamail.h'" '(should have been 460 characters)' fi chmod +x 'dnamail.h' fi # end of overwriting check echo shar: extracting "'dnamail.c'" '(11700 characters)' if test -f 'dnamail.c' then echo shar: will not over-write existing file "'dnamail.c'" else cat << \SHAR_EOF > 'dnamail.c' /************************************************************* * DNAMAIL - Deliver mail to remote DECnet nodes. * Use interactively or with sendmail interface * * 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 <fcntl.h> #include <pwd.h> #include <ctype.h> #include <sysexits.h> /* the 'proper' exits to return to sendmail */ #include <sys/ioctl.h> #include <netdna/dna.h> #include <sys/time.h> #include "dnamail.h" /* list of strings */ struct clist { char *str; struct clist *next; }; extern int errno; char *use_str = "USAGE: %s [-d] [-s subject] [-n node] [address-list]\n"; #define usage() printf(use_str, argv[0]) char buff[MAXLINE]; char *subject; char *node; char debug; char ttyflag; char *from; char *from_o; int num_addr; char *to_line; int baduser_flag; char **to; /* char *to[] */ int ll; /* DECnet file descriptor */ /* open DECnet connection to mail protocol. Descriptor is in 'll' */ get_connection() { OpenBlock ob; /* info for opening DECnet link */ int ret; /* return status code */ if (debug) fprintf(stderr, "Trying to open /dev/dna\n"); if ((ll = open("/dev/dna", O_RDWR)) < 0) { dnaerror("Open failed"); exit(EX_SOFTWARE); } if (debug) fprintf(stderr, "Trying to get logical link\n"); if (ioctl(ll, SES_GET_LINK, 0)) { dnaerror("Error getting logical link"); exit_with_status(); } if (debug) fprintf(stderr, "Trying to get link to mail server on remote node\n"); /* set up open block with access information */ strcpy(ob.op_node_name, node); /* node we want to send mail to */ ob.op_object_nbr = MAIL_OBJECT; ob.op_userid[0] = ob.op_account[0] = ob.op_password[0] = NULL; ob.op_opt_data.im_length = 0; if (ioctl(ll, SES_LINK_ACCESS, &ob) < 0) { dnaerror("link access"); exit_with_status(); } if (debug) fprintf(stderr, "Link established...\n"); /* ll now contains descriptor to open DECnet connection to MAIL.EXE on node 'node' */ } /* convert dna errors into errors sendmail can understand. Then exit. */ exit_with_status() { switch(errno) { case NET_RESOUR: case NODE_DOWN: case NODE_UNREACH: exit(EX_TEMPFAIL); case NODE_NAME: exit(EX_NOHOST); case OBJ_NAME: exit(EX_UNAVAILABLE); default: exit(EX_PROTOCOL); } } /* close up connection */ drop_connection() { SessionData sd; /* misc session info */ sd.sd_reason = 0; sd.sd_data.im_length = 0; ioctl(ll, SES_DISCONNECT, &sd); close(ll); if (debug) fprintf(stderr, "Connection terminated by us\n"); } /* Sends headers. Collects headers from message into a list. Then sends subject line (which terminates VMS header) followed by other headers (which are treated as part of the normal message by VMS). The actual reason this routine exists is to search for a Subject: line so it can be sent as the DECnet subject line. Of course, later versions of the software might do more with these headers. */ send_headers() { struct clist *headers, *tail; if (ttyflag || subject) { /* if we are a tty or have an explicit subject */ /* then we only want to send the subject rather than search for it */ send(subject); return; } sprintf(buff, "Received: by %s; %s", version, mailtime()); /* initialize list of headers */ headers = (struct clist*)malloc(sizeof(struct clist)); headers->next = NULL; headers->str = copystr(buff); tail = headers; /* read in headers */ while (gets(buff) > 0) { /* add onto header list */ tail->next = (struct clist*)malloc(sizeof(struct clist)); tail = tail->next; tail->next=NULL; tail->str = copystr(buff); if (strlen(buff) == 0) /* empty line means no more headers */ break; if (!strncmp(buff, "Subject: ", 9)) { /* found the Subject: */ subject = &tail->str[9]; } } /* now write out header lines */ send(subject); /* this terminates the DECnet mail header */ tail=headers; /* send list of headers - these are treated by DECnet mail as part of the normal message */ while (tail) { send(tail->str); tail=tail->next; cfree(headers->str); free(headers); headers=tail; } } /* the actual workhorse. Sends mail using correct DECnet mail protocol. Information about the protocol was derived from microfiche VMS listings for V4.0. See dnamaild.c for the other half of the protocol. Protocol: 'send' means to write a record over decnet. A 'marker' is a record containing a single NULL (used to terminate list of users and message). 1) send who this mail is from (becomes From: line) 2) for each user we are sending mail to: a) send address b) get status back (tells us if address is valid or not) 3) send a 'marker' specifying the end of step 2 4) send To: line. This line contains the original list of recipients as entered by the user. (this line is treated as a 'header' by VMS) 5) send Subj: line (this is handled by send_headers() ) 6) send each line of the message 7) terminate message with a 'marker'. 8) For each address that was valid in step 2, read a status value back to see if message actually got sent. */ send_message() { int i; if (debug) fprintf(stderr, "Send the From: line\n"); send(from); /* for each user, send address and get status */ baduser_flag = 0; for (i=0; i<num_addr; i++) { if (debug) fprintf(stderr, "Checking user <%s>\n", to[i]); send(to[i]); if (check_status()) { /* status tell if deliverable or not */ if (debug) fprintf(stderr, "\tcheck_status returned true\n"); to[i] = NULL; baduser_flag = 1; /* remember that we had an invalid address */ } } send_marker(); /* specifies end of address check */ if (debug) fprintf(stderr, "sending To: line\n"); send (to_line); /* send_headers() will send the Subj: line after parsing the headers */ send_headers(); /* now send actual message */ if (debug) fprintf(stderr, "Sending message body\n"); if (ttyflag) printf("Enter your message below. Press CTRL/D when complete, or CTRL/C to quit:\n"); while (gets(buff) > 0) send(buff); send_marker(); /* specifies end of message */ /* for each address, check status to see if it was actually sent */ for (i=0; i<num_addr; i++) if (to[i] && check_status()) baduser_flag = 1; /* so we can exit with an appropriate error */ } /* read status back from remote node. Since I am assuming the remote node is a VAX, I assume a VAX byte order. If there was an error, then read in status message */ int check_status() { #ifndef DEBUG long st; /* read longword */ if (read(ll, &st, sizeof(long)) < 0) { dnaerror("CheckStatus"); exit_with_status(); } /* 0x01000000 is really 0x1 on VAX */ if (st == 0x01000000) return 0; /* else we have an error - read error message */ while (1) { if ((st=read(ll, buff, sizeof(buff))) < 0) { dnaerror("CheckStatus"); exit_with_status(); } /* is this end of status message ? */ if (st == 1 && buff[0] == NULL) break; buff[st] = NULL; fprintf(stderr, "%s\n", buff); /* write to stderr so sendmail sees it */ } return 1; #else return 0; #endif } /* send a string over the decnet connection */ send(s) char *s; { #ifndef DEBUG if (write(ll, s, (s?strlen(s):0)) < 0) { dnaerror("SEND"); exit_with_status(); } #else printf("SEND= %s\n", (s?s:"")); #endif } /* send NULL over decnet link - used as marker */ send_marker() { #ifndef DEBUG if (write(ll, "", 1) < 0) { dnaerror("SEND"); exit_with_status(); } #else printf("SEND_MARKER\n"); #endif } /* clean up addresses for VMS side - convert to uppercase, anything else needed */ char *fix_addr(addr) char *addr; { char inquote, esc; char *p; /* make sure usernames are uppercase so that MAIL.EXE doesn't yell at us */ inquote = 0; for (p=buff; *addr; addr++) { if (esc = (*addr=='\\')) addr++; if (*addr=='"' && !esc) { addr++; inquote ^= 1; } if (!inquote && islower(*addr)) *p++ = toupper(*addr); else *p++ = *addr; } *p = NULL; return copystr(buff); } /* make one long address out of all specified on command line - append "node::" to beginning of each. Return in 'to_line' */ get_addresses(argv, index, num_addresses) char *argv[]; int index, num_addresses; { int i; int comma_flag; comma_flag = 0; num_addr = num_addresses; to = (char **)malloc(sizeof(char *) * num_addr); for (i=0; i<num_addr; i++) { if (comma_flag) strcat(buff, " "); strcat(buff, node); strcat(buff, "::"); strcat(buff, argv[i+index]); to[i] = fix_addr(argv[i+index]); comma_flag = 1; } to_line = copystr(buff); } /* parse arguments, get anything not specified, and call send_message() */ main(argc, argv) int argc; char *argv[]; { int st, /* return status */ i; /* misc. */ extern char *optarg; /* for use with getopt() */ extern int optind; char opt; char *copystr(); char *t1; struct passwd *pw; subject = node = from = from_o = NULL; debug = ttyflag = FALSE; /* parse arguments */ while ((opt=getopt(argc, argv, "ds:n:f:")) != EOF) { switch(opt) { case 'd': /* debug flag */ debug = TRUE; break; case 's': /* subject */ subject = optarg; break; case 'n': /* remote node */ node = optarg; break; case 'f': /* not included in usage()! */ from_o = optarg; break; default: usage(); exit(EX_USAGE); } } /* see if we are a tty as opposed to sendmail */ ttyflag = isatty(0); /* prompt for node if not specified */ if (!node) { fputs("Node: ", stdout); if (!gets(buff)) { puts("Unexpected EOF"); exit(1); } node = copystr(buff); } /* uppercase node name */ for (t1 = node; *t1; t1++) if (islower(*t1)) *t1 = toupper(*t1); /* get recipients if not specified */ if (!argv[optind]) { fputs("To: ", stdout); if (!gets(buff)) { puts("Unexpected EOF"); exit(1); } /* create to[] array */ to = (char **)malloc(sizeof(char*)); /* room for one address */ to_line = copystr(buff); num_addr = 1; to[0] = fix_addr(buff); } else { /* build to_line and to[] from arguments */ get_addresses(argv, optind, (argc-optind)); } /* get subject if not specified */ if (!subject && ttyflag) { fputs("Subject: ", stdout); if (!gets(buff)) { puts("Unexpected EOF"); exit(1); } subject = copystr(buff); } /* figure out who this is from if not specified or this is a tty */ if (!from_o) { t1 = (char *)getlogin(); if (!t1) { pw = getpwuid(getuid()); t1 = pw->pw_name; } from_o = t1; } sprintf(buff, "\"%s\"", from_o); from = copystr(buff); if (debug) { fprintf(stderr, "From: '%s'\n", from); fprintf(stderr, "To: <%s>", to_line); } /* get connection, send mail, close connection */ #ifndef DEBUG get_connection(); #endif send_message(); #ifndef DEBUG drop_connection(); #endif /* if mail wasn't sent to a user, then exit with appropriate error code, so sendmail can take the appropriate action */ if (baduser_flag) exit(EX_NOUSER); else exit(EX_OK); } SHAR_EOF if test 11700 -ne "`wc -c < 'dnamail.c'`" then echo shar: error transmitting "'dnamail.c'" '(should have been 11700 characters)' fi chmod +x 'dnamail.c' fi # end of overwriting check echo shar: extracting "'dnamaild.c'" '(10282 characters)' if test -f 'dnamaild.c' then echo shar: will not over-write existing file "'dnamaild.c'" else cat << \SHAR_EOF > 'dnamaild.c' /************************************************************* * 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; } SHAR_EOF if test 10282 -ne "`wc -c < 'dnamaild.c'`" then echo shar: error transmitting "'dnamaild.c'" '(should have been 10282 characters)' fi chmod +x 'dnamaild.c' fi # end of overwriting check echo shar: extracting "'dnamisc.c'" '(794 characters)' if test -f 'dnamisc.c' then echo shar: will not over-write existing file "'dnamisc.c'" else cat << \SHAR_EOF > 'dnamisc.c' /************************************************************* miscellaneous routines *************************************************************/ #include <stdio.h> #include <sys/time.h> /* returns a newly allocated copy of a string */ char *copystr(str) char *str; { char *tmp, *calloc(); if (!str) return NULL; tmp = calloc(strlen(str)+1, 1); strcpy(tmp, str); return tmp; } /* figure out correct time and timezone */ char *mailtime() { long my_time; char *atime; static char buf[32]; struct timeval tv; struct timezone tzp; my_time = time(0L); atime = asctime(localtime(&my_time)); atime[strlen(atime)-1] = '\0'; /* zap "\n" */ gettimeofday(&tv, &tzp); sprintf(buf, "%s %s", atime, timezone(tzp.tz_minuteswest, tzp.tz_dsttime)); return buf; } SHAR_EOF if test 794 -ne "`wc -c < 'dnamisc.c'`" then echo shar: error transmitting "'dnamisc.c'" '(should have been 794 characters)' fi chmod +x 'dnamisc.c' fi # end of overwriting check echo shar: extracting "'dnaerror.c'" '(474 characters)' if test -f 'dnaerror.c' then echo shar: will not over-write existing file "'dnaerror.c'" else cat << \SHAR_EOF > 'dnaerror.c' /* Since dnaerror.c is copyrighted, this file just includes the copy */ /* you should already have. You may have to change the path name if */ /* your setup is not standard. If you don't have this file (even */ /* on the original tape), then you will have to get one from Sun, */ /* or derive your own. */ /* */ /* All dnaerror does, is to simulate perror(), but with DECNET errors */ /* if they apply. */ #include "/usr/sunlink/dna/tests/dnaerror.c" SHAR_EOF if test 474 -ne "`wc -c < 'dnaerror.c'`" then echo shar: error transmitting "'dnaerror.c'" '(should have been 474 characters)' fi chmod +x 'dnaerror.c' fi # end of overwriting check echo shar: extracting "'main.diff'" '(3720 characters)' if test -f 'main.diff' then echo shar: will not over-write existing file "'main.diff'" else cat << \SHAR_EOF > 'main.diff' This is a diff to convert sendmail.main.cf to use dnamail. Changes: 1) Define macro 'S' to be name of machine that can forward DECnet mail (default is 'dnahost'). Comment out this line for if this machine runs Sunlink/DNI. 2) Define class 'S' to be list of machines we can send mail to via DECnet. 3) Add 'dna' as a trusted user. 4) Add 'dna' as a mailer 5) Addresses to machines in class 'S' are mailed by #dna or forwarded to 'dnahost' to be mailed. *** sendmail.main.cf Sat May 7 18:43:55 1988 --- sendmail.main.new Sat May 7 19:10:07 1988 *************** *** 48,53 **** --- 48,58 ---- # Otherwise, the default is to use the hosts.byname map if YP # is running (or else the /etc/hosts file if no YP). + # define this $S if you want to forward decnet mail to $S + # if this node can handle decnet, then DON'T define $S + # DBJ + DSdnahost + ################################################# # # General configuration information *************** *** 91,96 **** --- 96,104 ---- DVSMI-3.2 + # get list of decnet machines we can send mail to + FS/usr/sunlink/dna/dnahosts + ########################## ### Special macros ### ########################## *************** *** 154,163 **** ######################### ### Trusted users ### ######################### ! Troot Tdaemon Tuucp ############################# ### Format of headers ### --- 162,174 ---- ######################### ### Trusted users ### ######################### ! # ! # added dna, since dnamaild gets run as that user.. ! # Troot Tdaemon Tuucp + Tdna ############################# ### Format of headers ### *************** *** 269,274 **** --- 280,287 ---- S6 R$*<@$*$=D>$* $1<@$2LOCAL>$4 convert local domain R$*<@$*$=D.$=U>$* $1<@$2LOCAL>$5 or full domain name + #added by DBJ - just in case someone still uses the old form + R$*<$*.decnet>$* $1<$2.uucp>$3 convert to uucp ############################################################ ############################################################ *************** *** 366,373 **** --- 379,408 ---- S23 R$+ $:$>5$1 convert to old style + ############################################################ + ############################################################ + ##### + ##### DECnet Mailer specification + ##### + ##### Messages processed by this configuration are assumed to leave + ##### the internet domain. Hence, they may not necessarily correspond + ##### to RFC822 in all details. + ##### + ##### added by DBJ + ##### + ############################################################ + ############################################################ + Mdna, P=/usr/sunlink/dna/dnamail, F=mnSF, S=14, R=24, + A=dnamail -f $f -n $h $u + S14 + # none needed + + S24 + # none needed + + ############################################################ ############################################################ ##### *************** *** 415,420 **** --- 450,470 ---- # Clean up addresses for external use -- kills LOCAL, route-addr ,=>: and etc. R$* $:$>9 $1 Then continue... + + # added by DBJ + #################################################### + # This gets shoved in the center of Ruleset 0 in + # order to handle decnet nodes. + # + # If $S (decnet gateway) is defined, then forward to $S, else + # resolve to dna mailer. + # + # added by DBJ + #################################################### + + R$+<@$=S> $?S $#ether $@$S $:$2!$1 $| $#dna $@$2 $:$1 $. + R$+<@$=S.uucp> $?S $#ether $@$S $:$2!$1 $| $#dna $@$2 $:$1 $. + # resolve UUCP domain R<@$-.uucp>:$+ $#uucp $@$1 $:$2 @host.uucp:... SHAR_EOF if test 3720 -ne "`wc -c < 'main.diff'`" then echo shar: error transmitting "'main.diff'" '(should have been 3720 characters)' fi chmod +x 'main.diff' fi # end of overwriting check echo shar: extracting "'sub.diff'" '(3714 characters)' if test -f 'sub.diff' then echo shar: will not over-write existing file "'sub.diff'" else cat << \SHAR_EOF > 'sub.diff' This is a diff to convert sendmail.subsidiary.cf to use dnamail. Changes: 1) Define macro 'S' to be name of machine that can forward DECnet mail (default is 'dnahost'). Comment out this line for if this machine runs Sunlink/DNI. 2) Define class 'S' to be list of machines we can send mail to via DECnet. 3) Add 'dna' as a trusted user. 4) Add 'dna' as a mailer 5) Addresses to machines in class 'S' are mailed by #dna or forwarded to 'dnahost' to be mailed. *** sendmail.subsidiary.cf Sat May 7 18:43:55 1988 --- sendmail.subsidiary.new Sat May 7 19:10:58 1988 *************** *** 36,41 **** --- 36,46 ---- DRmailhost CRmailhost + # define this $S if you want to forward decnet mail to $S + # if this node can handle decnet, then DON'T define $S + # DBJ + DSdnahost + ################################################# # # General configuration information *************** *** 79,84 **** --- 84,92 ---- DVSMI-3.2 + # get list of decnet machines we can send mail to + FS/usr/sunlink/dna/dnahosts + ########################## ### Special macros ### ########################## *************** *** 142,151 **** ######################### ### Trusted users ### ######################### ! Troot Tdaemon Tuucp ############################# ### Format of headers ### --- 150,162 ---- ######################### ### Trusted users ### ######################### ! # ! # added dna, since dnamaild gets run as that user.. ! # Troot Tdaemon Tuucp + Tdna ############################# ### Format of headers ### *************** *** 257,262 **** --- 268,275 ---- S6 R$*<@$*$=D>$* $1<@$2LOCAL>$4 convert local domain R$*<@$*$=D.$=U>$* $1<@$2LOCAL>$5 or full domain name + #added by DBJ - just in case someone still uses the old form + R$*<$*.decnet>$* $1<$2.uucp>$3 convert to uucp ############################################################ ############################################################ *************** *** 354,360 **** --- 367,396 ---- S23 R$+ $:$>5$1 convert to old style + ############################################################ + ############################################################ + ##### + ##### DECnet Mailer specification + ##### + ##### Messages processed by this configuration are assumed to leave + ##### the internet domain. Hence, they may not necessarily correspond + ##### to RFC822 in all details. + ##### + ##### added by DBJ + ##### + ############################################################ + ############################################################ + Mdna, P=/usr/sunlink/dna/dnamail, F=mnSF, S=14, R=24, + A=dnamail -f $f -n $h $u + + S14 + # none needed + + S24 + # none needed + + ############################################################ ############################################################ ##### *************** *** 407,412 **** --- 443,463 ---- R<@$=V.uucp>:$+ $:$>9 $1 First clean up, then... R<@$=V.uucp>:$+ $#uucp $@$1 $:$2 @host.uucp:... R$+<@$=V.uucp> $#uucp $@$2 $:$1 user@host.uucp + + # added by DBJ + #################################################### + # This gets shoved in the center of Ruleset 0 in + # order to handle decnet nodes. + # + # If $S (decnet gateway) is defined, then forward to $S, else + # resolve to dna mailer. + # + # added by DBJ + #################################################### + + R$+<@$=S> $?S $#ether $@$S $:$2!$1 $| $#dna $@$2 $:$1 $. + R$+<@$=S.uucp> $?S $#ether $@$S $:$2!$1 $| $#dna $@$2 $:$1 $. + # optimize names of known ethernet hosts R$*<@$*$%y.LOCAL>$* $#ether $@$3 $:$1<@$2$3>$4 user@host.here SHAR_EOF if test 3714 -ne "`wc -c < 'sub.diff'`" then echo shar: error transmitting "'sub.diff'" '(should have been 3714 characters)' fi chmod +x 'sub.diff' fi # end of overwriting check # End of shell archive exit 0 -- Darin Johnson (...lll-lcc.arpa!leadsv!laic!darin) (...ucbvax!sun!sunncal!leadsv!laic!darin) "All aboard the DOOMED express!"