コード例 #1
0
ファイル: ext_imap.cpp プロジェクト: 2bj/hhvm
Variant f_imap_mailboxmsginfo(const Resource& imap_stream) {
  ImapStream *obj = imap_stream.getTyped<ImapStream>();
  Object ret(SystemLib::AllocStdClassObject());

  int64_t unreadmsg = 0, deletedmsg = 0, msize = 0;

  for (unsigned long i = 1; i <= obj->m_stream->nmsgs; i++) {
    MESSAGECACHE * cache = mail_elt (obj->m_stream, i);
    mail_fetchstructure (obj->m_stream, i, NIL);

    if (!cache->seen || cache->recent) {
      unreadmsg++;
    }

    if (cache->deleted) {
      deletedmsg++;
    }
    msize = msize + cache->rfc822_size;
  }

  ret.o_set("Unread", (int64_t)unreadmsg);
  ret.o_set("Deleted", (int64_t)deletedmsg);
  ret.o_set("Nmsgs", (int64_t)obj->m_stream->nmsgs);
  ret.o_set("Size", (int64_t)msize);

  char date[100];
  rfc822_date(date);
  ret.o_set("Date", String(date, CopyString));
  ret.o_set("Driver", String(obj->m_stream->dtb->name, CopyString));
  ret.o_set("Mailbox", String(obj->m_stream->mailbox, CopyString));
  ret.o_set("Recent", (int64_t)msize);

  return ret;
}
コード例 #2
0
ファイル: ext_imap.cpp プロジェクト: abacaxinho/hhvm
static Variant HHVM_FUNCTION(imap_check, const Resource& imap_stream) {
  ImapStream *obj = imap_stream.getTyped<ImapStream>();
  if (mail_ping(obj->m_stream) == NIL) {
    return false;
  }
  if (obj->m_stream && obj->m_stream->mailbox) {
    Object ret(SystemLib::AllocStdClassObject());
    char date[100];
    rfc822_date(date);
    ret.o_set("Date", String(date, CopyString));
    ret.o_set("Driver", String(obj->m_stream->dtb->name, CopyString));
    ret.o_set("Mailbox", String(obj->m_stream->mailbox, CopyString));
    ret.o_set("Nmsgs", (int64_t)obj->m_stream->nmsgs);
    ret.o_set("Recent", (int64_t)obj->m_stream->recent);
    return ret;
  }
  return false;
}
コード例 #3
0
ファイル: smtp.c プロジェクト: anandakumarr/mailsend
/* SMTP: mail */
static int smtpMail(int sfd,char *to,char *cc,char *bcc,char *from,char *rrr,char *rt,
                    char *subject,char *attach_file,char *msg_body_file,
                    char *the_msg,int is_mime,int add_dateh)
{
    char
        *os="Unix",
        boundary[17],
        related[17],
        alternative[17],
        mbuf[1024];

    int
        newline_before;

    Sll
        *oneline_attachment_list,
        *attachment_list,
        *embed_image_list;

#ifdef WINNT
    os="Windows";
#else
    os="Unix";
#endif /* WINNT */

    memset(boundary, 0, sizeof(boundary));
    memset(related, 0, sizeof(related));
    memset(alternative, 0, sizeof(alternative));

    attachment_list=get_attachment_list();
    embed_image_list = get_embed_image_attachment_list();
    oneline_attachment_list = get_oneline_attachment_list();
    if (attachment_list || embed_image_list || oneline_attachment_list)
    {
        is_mime=1;
    }

    if (subject)
    {
        memset(buf,0,sizeof(buf));
        (void) snprintf(buf,sizeof(buf)-1,"Subject: %s\r\n",subject);

        msock_puts(buf);

        showVerbose(buf);
    }

    /* headers */
    if (from)
    {
        memset(buf,0,sizeof(buf));
        if (*g_from_name != '\0')
        {
            /* Name in From: */

            memset(buf,0,sizeof(buf));
            (void) snprintf(buf,sizeof(buf)-1,"From: %s <%s>\r\n",
                            g_from_name,from);
        }
        else
        {
            (void) snprintf(buf,sizeof(buf)-1,"From: %s\r\n",from);
        }
        msock_puts(buf);

        showVerbose(buf);
    }

    if (add_dateh)
    {
        /* add Date: header */
        char
            datebuf[65];

        memset(datebuf,0,sizeof(datebuf));
        if (rfc822_date(time(NULL),datebuf,sizeof(datebuf)-1) == 0)
        {
            memset(buf,0,sizeof(buf));
            (void) snprintf(buf,sizeof(buf)-1,"Date: %s\r\n",datebuf);
            msock_puts(buf);

            showVerbose(buf);
        }
    }
    
    if (to)
    {
        memset(buf,0,sizeof(buf));
        (void) snprintf(buf,sizeof(buf)-1,"To: %s\r\n",to);
        msock_puts(buf);

        showVerbose(buf);

    }

    if (cc)
    {
        memset(buf,0,sizeof(buf));
        (void) snprintf(buf,sizeof(buf)-1,"Cc: %s\r\n",cc);
        msock_puts(buf);
        showVerbose(buf);
    }

    /*
    if (bcc)
    {
        memset(buf,0,sizeof(buf));
        (void) snprintf(buf,sizeof(buf)-1,"Bcc: %s\r\n",bcc);
        msock_puts(buf);

        showVerbose(buf);
    }
    */

    if (rt != NULL)
    {
        memset(buf,0,sizeof(buf));
        (void) snprintf(buf,sizeof(buf)-1,"Reply-To: %s\r\n",rt);
        msock_puts(buf);
        showVerbose(buf);

    }
    if (rrr != NULL)
    {
        memset(buf,0,sizeof(buf));
        (void) snprintf(buf,sizeof(buf)-1,"Disposition-Notification-To: %s\r\n",rrr);
        msock_puts(buf);
        showVerbose(buf);
    }

    /* add custom headers if any. No verification is done */
    {
        Sll 
            *l,
            *custom_header_list;
        custom_header_list = get_custom_header_list();
        if (custom_header_list)
        {
            for (l = custom_header_list; l; l = l->next)
            {
                if (l->data)
                {
                    msock_puts((char *) l->data);
                    msock_puts("\r\n");
                    showVerbose((char *) l->data);
                    showVerbose("\r\n");
                }
            }
        }
    }


    memset(buf,0,sizeof(buf));
    (void) snprintf(buf,sizeof(buf)-1,"X-Mailer: %s (%s)\r\n",MAILSEND_VERSION,os);
    msock_puts(buf);
    showVerbose(buf);

    memset(buf,0,sizeof(buf));
    (void) snprintf(buf,sizeof(buf)-1,"X-Copyright: %s\r\n",NO_SPAM_STATEMENT);
    msock_puts(buf);
    showVerbose(buf);

    if (is_mime)
    {
        int
            rc;
        srand(time(NULL));
        memset(boundary,0,sizeof(boundary));
        mutilsGenerateMIMEBoundary(boundary,sizeof(boundary));

        /* if msg body file is specified, include and return */
        if (msg_body_file)
        {
            return (include_msg_body());
        }

        rc = print_content_type_header(boundary);
        RETURN_IF_NOT_ZERO(rc);

        rc = process_oneline_messages(boundary);
        RETURN_IF_NOT_ZERO(rc);

        rc = process_embeded_images(boundary);
        RETURN_IF_NOT_ZERO(rc);

        rc = process_attachments(boundary);
        RETURN_IF_NOT_ZERO(rc);

        /* handle MIME attachments ends */
        goto done;
    } /* is_mime */

    /* mail body */
    if (attach_file == NULL && the_msg == NULL) /* read from stdin */
    {

        /* if stdin is a terminal, print the instruction */
        if (isInConsole(_fileno(stdin)))
        {
            (void) printf("=========================================================================\n");
            (void) printf("Type . in a new line and press Enter to end the message, CTRL+C to abort\n");
            (void) printf("=========================================================================\n");
        }

#ifdef WINNT
        SetConsoleCtrlHandler(CntrlHandler,TRUE);
#endif /* WINNT */

        newline_before=1;
        while (fgets(mbuf,sizeof(mbuf)-1,stdin) && (break_out == 0))
        {
            if (newline_before && *mbuf == '.')
            {
                break;
            }
            else
            {
                int
                    len;
                /* vinicio qmail fix */
                len=strlen(mbuf);
                if (mbuf[len-1] != '\n')
                    strcat(mbuf,"\r\n");
                else
                {
                   mbuf[--len]='\0';
                   strcat(mbuf,"\r\n");
                }
                /* vinicio qmail fix */
                msock_puts(mbuf);
                showVerbose("[C] %s",mbuf);
            }
            newline_before=(*mbuf != '\0' && mbuf[strlen(mbuf)-1] == '\n');
            if (break_out == 1)
            {
                (void) fprintf(stderr," Breaking out\n");
                return (0);
            }
        }
    }
done:

    return (0);
}
コード例 #4
0
void
CClientMimeHandler::envelope()
{
    if (theEnvelopeItem.isNull()) {
        throw EmailException("PARSE_ERROR", "The message could not be parsed.");
    }

    //set the date from the client.
    //If this is not set it defaults to the date of the SMTP server.
    char line[MAILTMPLEN];
    rfc822_date (line);
    theEnvelope->date = (unsigned char *) fs_get (1+strlen (line));
    strcpy((char *)theEnvelope->date,line);


    Iterator_t    lChildIter;
    zorba::Item   lChild;
    String lNodeName, lNodeValue;
    String lName, lMailbox, lHost;

    lChildIter = theEnvelopeItem.getChildren();
    lChildIter->open();
    while (lChildIter->next(lChild)) {
        if (lChild.getNodeKind() != store::StoreConsts::elementNode) {
            continue;
        }

        getNodeName(lChild, lNodeName);
        getTextValue(lChild, lNodeValue);

        if (lNodeName == "date") {
            char lDate[MAILTMPLEN];
            parseXmlDateTime(lNodeValue, lDate);
            theEnvelope->date = (unsigned char *) fs_get (1+strlen (lDate));
            strcpy ((char *)theEnvelope->date, lDate);
        } else if (lNodeName == "from") {
            getNameAndEmailAddress(lChild, lName, lMailbox, lHost);
            theEnvelope->from = create_mail_address(lName, lMailbox, lHost);
        } else if (lNodeName == "sender") {
            getNameAndEmailAddress(lChild, lName, lMailbox, lHost);
            theEnvelope->sender = create_mail_address(lName, lMailbox, lHost);
        } else if (lNodeName == "replyto") {
            getNameAndEmailAddress(lChild, lName, lMailbox, lHost);
            theEnvelope->reply_to = create_mail_address(lName, lMailbox, lHost);
        } else if (lNodeName == "subject") {
            encodeStringForEMailHeader(lNodeValue, theEnvelope->subject);
        } else if (lNodeName == "recipient") {
            Iterator_t lRecipentChildren = lChild.getChildren();
            lRecipentChildren->open();
            Item lRecipentChild;
            // read the recipient element but skip comments
            while (lRecipentChildren->next(lRecipentChild)) {
                if (lRecipentChild.getNodeKind() == store::StoreConsts::elementNode) {
                    break;
                }
            }
            getNodeName(lRecipentChild, lNodeName);
            lRecipentChildren->close();

            if (lNodeName == "to") {
                getNameAndEmailAddress(lRecipentChild, lName, lMailbox, lHost);
                // there can be multiple to nodes, iterate to the next free one!
                ADDRESS** lNext = &theEnvelope->to;
                while (*lNext) {
                    lNext = &((*lNext)->next);
                }
                *lNext = create_mail_address(lName, lMailbox, lHost);
            } else if(lNodeName == "cc") {
                getNameAndEmailAddress(lRecipentChild, lName, lMailbox, lHost);
                ADDRESS** lNext = &theEnvelope->cc;
                while (*lNext) {
                    lNext = &((*lNext)->next);
                }
                *lNext = create_mail_address(lName, lMailbox, lHost);
            } else if (lNodeName == "bcc") {
                getNameAndEmailAddress(lRecipentChild, lName, lMailbox, lHost);
                ADDRESS** lNext = &theEnvelope->bcc;
                while (*lNext) {
                    lNext = &((*lNext)->next);
                }
                *lNext = create_mail_address(lName, lMailbox, lHost);
            }
        }
    }
    lChildIter->close();
}
コード例 #5
0
ファイル: dmail.c プロジェクト: alpinemail/alpine
int main (int argc,char *argv[])
{
  FILE *f = NIL;
  int c,ret = 0;
  unsigned long msglen;
  char *s,tmp[MAILTMPLEN];
  uid_t ruid = getuid ();
  struct passwd *pwd = ruid ? getpwnam ("daemon") : NIL;
  openlog ("dmail",LOG_PID,LOG_MAIL);
				/* must not be root or daemon! */
  if (!ruid || (pwd && (pwd->pw_uid == ruid)))
    _exit (fail ("dmail may not be invoked by root or daemon",EX_USAGE));
#include "linkage.c"
				/* process all flags */
  for (--argc; argc && (*(s = *++argv)) == '-'; argc--) switch (s[1]) {
  case 'D':			/* debug */
    debug = T;			/* extra debugging */
    break;
  case 's':			/* deliver as seen */
    flagseen = T;
    break;
  case 'f':
  case 'r':			/* flag giving return path */
    if (sender) _exit (fail ("duplicate -r",EX_USAGE));
    if (argc--) sender = cpystr (*++argv);
    else _exit (fail ("missing argument to -r",EX_USAGE));
    break;
  case 'k':
    if (keywords) _exit (fail ("duplicate -k",EX_USAGE));
    if (argc--) keywords = cpystr (*++argv);
    else _exit (fail ("missing argument to -k",EX_USAGE));
    break;
  case 'p':
    if (s[2] && ((s[2] == '-') || isdigit (s[2]))) precedence = atol (s + 2);
    else if (argc-- && ((*(s = *++argv) == '-') || isdigit (*s)))
      precedence = atol (s);
    else _exit (fail ("missing argument to -p",EX_USAGE));
    break;
  default:			/* anything else */
    _exit (fail ("unknown switch",EX_USAGE));
  }

  if (argc > 1) _exit (fail ("too many recipients",EX_USAGE));
  else if (!(f = tmpfile ())) _exit(fail ("can't make temp file",EX_TEMPFAIL));
				/* build delivery headers */
  if (sender) fprintf (f,"Return-Path: <%s>\015\012",sender);
				/* start Received line: */
  fprintf (f,"Received: via dmail-%s.%s for %s; ",CCLIENTVERSION,version,
	   (argc == 1) ? *argv : myusername ());
  rfc822_date (tmp);
  fputs (tmp,f);
  fputs ("\015\012",f);
				/* copy text from standard input */
  if (!fgets (tmp,MAILTMPLEN-1,stdin) || !(s = strchr (tmp,'\n')) ||
      (s == tmp) || s[1]) _exit (fail ("bad first message line",EX_USAGE));
  else if (s[-1] == '\015') {	/* nuke leading "From " line */
    if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
	(tmp[3] != 'm') || (tmp[4] != ' ')) fputs (tmp,f);
    while ((c = getchar ()) != EOF) putc (c,f);
  }
  else {
    if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
	(tmp[3] != 'm') || (tmp[4] != ' ')) {
      *s++ = '\015';		/* overwrite NL with CRLF */
      *s++ = '\012';
      *s = '\0';		/* tie off string */
      fputs (tmp,f);		/* write line */
    }
  }
				/* copy text from standard input */
  while ((c = getchar ()) != EOF) {
				/* add CR if needed */
    if (c == '\012') putc ('\015',f);
    putc (c,f);
  }
  msglen = ftell (f);		/* size of message */
  fflush (f);			/* make sure all changes written out */
  if (ferror (f)) ret = fail ("error writing temp file",EX_TEMPFAIL);
  else if (!msglen) ret = fail ("empty message",EX_TEMPFAIL);
				/* single delivery */
  else ret = deliver (f,msglen,argc ? *argv : myusername ());
  fclose (f);			/* all done with temporary file */
  _exit (ret);			/* normal exit */
  return 0;			/* stupid gcc */
}
コード例 #6
0
ファイル: tmail.c プロジェクト: Distrotech/imap
int main (int argc,char *argv[])
{
  FILE *f = NIL;
  int pid,c,ret = 0;
  unsigned long msglen,status = 0;
  char *s,tmp[MAILTMPLEN];
  uid_t ruid = getuid ();
  struct passwd *pwd;
  openlog ("tmail",LOG_PID,LOG_MAIL);
#include "linkage.c"
				/* make sure have some arguments */
  if (--argc < 1) _exit (fail ("usage: tmail [-D] user[+folder]",EX_USAGE));
				/* process all flags */
  while (argc && (*(s = *++argv)) == '-') {
    argc--;			/* gobble this argument */
    switch (s[1]) {		/* what is this flag? */
    case 'D':			/* debug */
      debug = T;		/* don't fork */
      break;
    case 'I':			/* inbox specifier */
      if (inbox || format) _exit (fail ("duplicate -b or -I",EX_USAGE));
      if (argc--) inbox = cpystr (*++argv);
      else _exit (fail ("missing argument to -I",EX_USAGE));
      break;
    case 'f':			/* new name for this flag */
    case 'r':			/* flag giving return path */
      if (sender) _exit (fail ("duplicate -f or -r",EX_USAGE));
      if (argc--) sender = cpystr (*++argv);
      else _exit (fail ("missing argument to -f or -r",EX_USAGE));
      break;
    case 'b':			/* create INBOX in this format */
      if (inbox || format) _exit (fail ("duplicate -b or -I",EX_USAGE));
      if (!argc--) _exit (fail ("missing argument to -b",EX_USAGE));
      if (!(format = mail_parameters (NIL,GET_DRIVER,*++argv)))
	_exit (fail ("unknown format to -b",EX_USAGE));
      else if (!(format->flags & DR_LOCAL) ||
	       !compare_cstring (format->name,"dummy"))
	_exit (fail ("invalid format to -b",EX_USAGE));
      break;
    /* following flags are undocumented */
    case 'p':			/* precedence for quota */
      if (s[2] && ((s[2] == '-') || isdigit (s[2]))) precedence = atol (s + 2);
      else if (argc-- && ((*(s = *++argv) == '-') || isdigit (*s)))
	precedence = atol (s);
      else _exit (fail ("missing argument to -p",EX_USAGE));
      break;
    case 'd':			/* obsolete flag meaning multiple users */
      break;			/* ignore silently */
    /* -s has been deprecated and replaced by the -s and -k flags in dmail.
     * dmail's -k flag does what -s once did in tmail; dmail's -s flag
     * takes no argument and just sets \Seen.  Flag setting is more properly
     * done in dmail which runs as the user and is clearly at the user's
     * behest.  Since tmail runs privileged, -s would have to be disabled
     * unless the caller is also privileged.
     */
    case 's':			/* obsolete flag meaning delivery flags */
      if (!argc--)		/* takes an argument */
	_exit (fail ("missing argument to deprecated flag",EX_USAGE));
      syslog (LOG_INFO,"tmail called with deprecated flag: -s %.200s",*++argv);
      break;
    default:			/* anything else */
      _exit (fail ("unknown switch",EX_USAGE));
    }
  }

  if (!argc) ret = fail ("no recipients",EX_USAGE);
  else if (!(f = tmpfile ())) ret = fail ("can't make temp file",EX_TEMPFAIL);
  else {			/* build delivery headers */
    if (sender) fprintf (f,"Return-Path: <%s>\015\012",sender);
				/* start Received line: */
    fprintf (f,"Received: via tmail-%s.%s",CCLIENTVERSION,version);
				/* not root or daemon? */
    if (ruid && !((pwd = getpwnam ("daemon")) && (ruid == pwd->pw_uid))) {
      pwd = getpwuid (ruid);	/* get unprivileged user's information */
      if (inbox || format) {
	if (pwd) sprintf (tmp,"user %.80s",pwd->pw_name);
	else sprintf (tmp,"UID %ld",(long) ruid);
	strcat (tmp," is not privileged to use -b or -I");
	_exit (fail (tmp,EX_USAGE));
      }
      fputs (" (invoked by ",f);
      if (pwd) fprintf (f,"user %s",pwd->pw_name);
      else fprintf (f,"UID %ld",(long) ruid);
      fputs (")",f);
    }
				/* write "for" if single recipient */
    if (argc == 1) fprintf (f," for %s",*argv);
    fputs ("; ",f);
    rfc822_date (tmp);
    fputs (tmp,f);
    fputs ("\015\012",f);
				/* copy text from standard input */
    if (!fgets (tmp,MAILTMPLEN-1,stdin) || !(s = strchr (tmp,'\n')) ||
	(s == tmp) || s[1]) _exit (fail ("bad first message line",EX_USAGE));
    if (s[-1] == '\015') {	/* nuke leading "From " line */
      if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
	  (tmp[3] != 'm') || (tmp[4] != ' ')) fputs (tmp,f);
      while ((c = getchar ()) != EOF) putc (c,f);
    }
    else {
      mm_log ("tmail called with LF-only newlines",WARN);
      if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
	  (tmp[3] != 'm') || (tmp[4] != ' ')) {
	*s++ = '\015';		/* overwrite NL with CRLF */
	*s++ = '\012';
	*s = '\0';		/* tie off string */
	fputs (tmp,f);		/* write line */
      }
				/* copy text from standard input */
      while ((c = getchar ()) != EOF) {
				/* add CR if needed */
	if (c == '\012') putc ('\015',f);
	putc (c,f);
      }
    }
    msglen = ftell (f);		/* size of message */
    fflush (f);			/* make sure all changes written out */

    if (ferror (f)) ret = fail ("error writing temp file",EX_TEMPFAIL);
    else if (!msglen) ret = fail ("empty message",EX_TEMPFAIL);
				/* single delivery */
    else if (argc == 1) ret = deliver (f,msglen,*argv);
    else do {			/* multiple delivery uses daughter forks */
      if ((pid = fork ()) < 0) ret = fail (strerror (errno),EX_OSERR);
      else if (pid) {		/* mother process */
	grim_pid_reap_status (pid,NIL,(void *) status);
				/* normal termination? */
	if (!ret) ret = (status & 0xff) ? EX_SOFTWARE : (status & 0xff00) >> 8;
      }
				/* daughter process */
      else _exit (deliver (f,msglen,*argv));
    } while (--argc && *argv++);
    mm_dlog (ret ? "error in delivery" : "all recipients delivered");
  }
コード例 #7
0
ファイル: tmail.c プロジェクト: Distrotech/pine
int main (int argc,char *argv[])
{
  FILE *f = NIL;
  int pid,c,ret = 0;
  unsigned long msglen,status = 0;
  char *s,tmp[MAILTMPLEN];
  uid_t ruid = getuid ();
  struct passwd *pwd;
  openlog ("tmail",LOG_PID,LOG_MAIL);
#include "linkage.c"
				/* make sure have some arguments */
  if (--argc < 1) _exit (fail ("usage: tmail [-D] user[+folder]",EX_USAGE));
				/* process all flags */
  while (argc && (*(s = *++argv)) == '-') {
    argc--;			/* gobble this argument */
    switch (s[1]) {		/* what is this flag? */
    case 'D':			/* debug */
      debug = T;		/* don't fork */
      break;
    case 'd':			/* obsolete flag meaning multiple users */
      break;
    case 'I':			/* inbox specifier */
      if (argc--) inbox = cpystr (*++argv);
      else _exit (fail ("missing argument to -I",EX_USAGE));
      break;
    case 'f':			/* new name for this flag */
    case 'r':			/* flag giving return path */
      if (argc--) sender = cpystr (*++argv);
      else _exit (fail ("missing argument to -r",EX_USAGE));
      break;
    default:			/* anything else */
      _exit (fail ("unknown switch",EX_USAGE));
    }
  }

  if (!argc) ret = fail ("no recipients",EX_USAGE);
  else if (!(f = tmpfile ())) ret = fail ("can't make temp file",EX_TEMPFAIL);
  else {			/* build delivery headers */
    if (sender) fprintf (f,"Return-Path: <%s>\015\012",sender);
				/* start Received line: */
    fprintf (f,"Received: via tmail-%s",version);
				/* not root or daemon? */
    if (ruid && !((pwd = getpwnam ("daemon")) && (ruid == pwd->pw_uid))) {
      pwd = getpwuid (ruid);	/* get unprivileged user's information */
      if (inbox) {
	if (pwd) sprintf (tmp,"user %.80s",pwd->pw_name);
	else sprintf (tmp,"UID %ld",(long) ruid);
	strcat (tmp," is not privileged to use -I");
	_exit (fail (tmp,EX_USAGE));
      }
      fputs (" (invoked by ",f);
      if (pwd) fprintf (f,"user %s",pwd->pw_name);
      else fprintf (f,"UID %ld",(long) ruid);
      fputs (")",f);
    }
				/* write "for" if single recipient */
    if (argc == 1) fprintf (f," for %s",*argv);
    fputs ("; ",f);
    rfc822_date (tmp);
    fputs (tmp,f);
    fputs ("\015\012",f);
				/* copy text from standard input */
    if (!fgets (tmp,MAILTMPLEN-1,stdin) || !(s = strchr (tmp,'\n')) ||
	(s == tmp) || s[1]) _exit (fail ("bad first message line",EX_USAGE));
    if (s[-1] == '\015') {	/* nuke leading "From " line */
      if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
	  (tmp[3] != 'm') || (tmp[4] != ' ')) fputs (tmp,f);
      while ((c = getchar ()) != EOF) putc (c,f);
    }
    else {
      mm_log ("tmail called with LF-only newlines",WARN);
      if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
	  (tmp[3] != 'm') || (tmp[4] != ' ')) {
	*s++ = '\015';		/* overwrite NL with CRLF */
	*s++ = '\012';
	*s = '\0';		/* tie off string */
	fputs (tmp,f);		/* write line */
      }
				/* copy text from standard input */
      while ((c = getchar ()) != EOF) {
				/* add CR if needed */
	if (c == '\012') putc ('\015',f);
	putc (c,f);
      }
    }
    msglen = ftell (f);		/* size of message */
    fflush (f);			/* make sure all changes written out */

    if (ferror (f)) ret = fail ("error writing temp file",EX_TEMPFAIL);
    else if (!msglen) ret = fail ("empty message",EX_TEMPFAIL);
				/* single delivery */
    else if (argc == 1) ret = deliver (f,msglen,*argv);
    else do {			/* multiple delivery uses daughter forks */
      if ((pid = fork ()) < 0) ret = fail (strerror (errno),EX_OSERR);
      else if (pid) {		/* mother process */
	grim_pid_reap_status (pid,NIL,(void *) status);
				/* normal termination? */
	if (!ret) ret = (status & 0xff) ? EX_SOFTWARE : (status & 0xff00) >> 8;
      }
				/* daughter process */
      else _exit (deliver (f,msglen,*argv));
    } while (--argc && *argv++);
    mm_dlog (ret ? "error in delivery" : "all recipients delivered");
  }