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