home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / pine / c-client / mtest.c < prev    next >
C/C++ Source or Header  |  1994-03-29  |  18KB  |  674 lines

  1. /*
  2.  * Program:    Mail library test program
  3.  *
  4.  * Author:    Mark Crispin
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date:    8 July 1988
  13.  * Last Edited:    8 September 1993
  14.  *
  15.  * Sponsorship:    The original version of this work was developed in the
  16.  *        Symbolic Systems Resources Group of the Knowledge Systems
  17.  *        Laboratory at Stanford University in 1987-88, and was funded
  18.  *        by the Biomedical Research Technology Program of the National
  19.  *        Institutes of Health under grant number RR-00785.
  20.  *
  21.  * Original version Copyright 1988 by The Leland Stanford Junior University.
  22.  * Copyright 1993 by the University of Washington.
  23.  *
  24.  *  Permission to use, copy, modify, and distribute this software and its
  25.  * documentation for any purpose and without fee is hereby granted, provided
  26.  * that the above copyright notices appear in all copies and that both the
  27.  * above copyright notices and this permission notice appear in supporting
  28.  * documentation, and that the name of the University of Washington or The
  29.  * Leland Stanford Junior University not be used in advertising or publicity
  30.  * pertaining to distribution of the software without specific, written prior
  31.  * permission.  This software is made available "as is", and
  32.  * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY
  33.  * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE,
  34.  * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  35.  * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF
  36.  * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY
  37.  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  38.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
  39.  * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF
  40.  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  41.  *
  42.  */
  43.  
  44. #include <stdio.h>
  45. #include <ctype.h>
  46. #include <signal.h>
  47. /*~~~~ Transposed the include order */
  48. #include "osdep.h"
  49. #include "mail.h"
  50. #if unix
  51. #include <pwd.h>
  52. #include <netdb.h>
  53. #endif
  54. #ifdef noErr
  55. #include <MacTCPCommonTypes.h>
  56. #include <AddressXlation.h>
  57. #endif
  58. #include "rfc822.h"
  59. #include "smtp.h"
  60. #include "nntp.h"
  61. #include "misc.h"
  62. #include "vms_mail.h"
  63.  
  64. char *curhst = NIL;        /* currently connected host */
  65. char *curusr = NIL;        /* current login user */
  66. char personalname[256];        /* user's personal name */
  67. extern DRIVER imapdriver,vmsmaildriver,nntpdriver;
  68.  
  69. static char *hostlist[] = {    /* SMTP server host list */
  70.   "localhost",
  71.   NIL
  72. };
  73.  
  74. static char *newslist[] = {    /* Netnews server host list */
  75.   "kineret.huji.ac.il",
  76.   NIL
  77. };
  78.  
  79. #ifndef VMS
  80. void main  ();
  81. #endif
  82. void mm  ();
  83. void header  ();
  84. void display_body  ();
  85. void status  ();
  86. void prompt  ();
  87. void smtptest  ();
  88.  
  89. /* Main program - initialization */
  90.  
  91. #ifndef VMS
  92. void
  93. #endif    /* VMS */
  94. main ()
  95. {
  96.   MAILSTREAM *stream = NIL;
  97.   char tmp[MAILTMPLEN];
  98.   long debug;
  99. #ifdef noErr
  100.   size_t *base = (size_t *) 0x000908;
  101.                 /* increase stack size on a Mac */
  102.   SetApplLimit ((Ptr) (*base - (size_t) 65535L));
  103. #endif
  104. #if unix
  105.   char *name;
  106.   char *suffix;
  107.   struct passwd *pwd;
  108.   struct hostent *host_name;
  109.   gethostname (tmp,MAILTMPLEN);    /* get local name */
  110.                 /* get it in full form */
  111.   curhst = (host_name = gethostbyname (tmp)) ?
  112.     cpystr (host_name->h_name) : cpystr (tmp);
  113.                 /* get user name and passwd entry */
  114.   if (name = (char *) getlogin ()) pwd = getpwnam (name);
  115.   else {
  116.     pwd = getpwuid (getuid ());    /* get it this way if detached, etc */
  117.     name = pwd->pw_name;
  118.   }
  119.   curusr = cpystr (name);    /* current user is this name */
  120.   strcpy (tmp,pwd->pw_gecos);    /* probably not necessay but be safe */
  121.                 /* dyke out the office and phone poop */
  122.   if (suffix = strchr (tmp,',')) suffix[0] = '\0';
  123.   strcpy (personalname,tmp);    /* make a permanent copy of it */
  124. #else
  125.   prompt ("Personal name: ",personalname);
  126.   curusr = malloc(256);
  127.   cuserid(curusr);
  128.   curhst = cpystr ("VMS");
  129. #endif
  130.   puts ("MTest -- C client test program");
  131.   mail_link (&nntpdriver);    /* link in NNTP driver */
  132.   mail_link (&imapdriver);    /* link in IMAP driver */
  133.   mail_link (&vmsmaildriver);    /* link in VMS/MAIL driver */
  134. #ifdef MSDOS
  135.   mail_link (&dawzdriver);    /* link in dawz mail driver */
  136.   mail_link (&nntpdriver);    /* link in NNTP driver */
  137.   mail_link (&dummydriver);    /* finally dummy driver at the end */
  138. #endif
  139. #if unix
  140.   mail_link (&tenexdriver);    /* link in Tenex mail driver */
  141.   mail_link (&mhdriver);    /* link in mh mail driver */
  142.   mail_link (&mboxdriver);    /* link in mbox mail driver */
  143.   mail_link (&bezerkdriver);    /* link in Berkeley mail driver */
  144.   mail_link (&newsdriver);    /* link in netnews mail driver */
  145.   mail_link (&nntpdriver);    /* link in NNTP driver */
  146.   mail_link (&philedriver);    /* line in file driver */
  147.   mail_link (&dummydriver);    /* finally dummy driver at the end */
  148. #endif
  149.                 /* user wants protocol telemetry? */
  150.   prompt ("Debug protocol (y/n)?",tmp);
  151.   ucase (tmp);
  152.   debug = (tmp[0] == 'Y') ? T : NIL;
  153.   do {
  154.     prompt ("Mailbox ('?' for help): ",tmp);
  155.     if (!strcmp (tmp,"?")) {
  156.       puts ("Enter INBOX, mailbox name, or IMAP mailbox as {host}mailbox");
  157.       puts ("Known local mailboxes:");
  158.       mail_find (NIL,"*");
  159.       puts ("or just hit return to quit");
  160.     }
  161.     else if (tmp[0]) {
  162.     printf("Tmp='%s', stream=%d\n", tmp, stream);
  163.     stream = mail_open (stream,tmp,debug ? OP_DEBUG : NIL);
  164.     }
  165.   } while (!stream && tmp[0]);
  166.   mm (stream,debug);        /* run user interface if opened */
  167. #ifdef noErr
  168.                 /* clean up resolver */
  169.   if (resolveropen) CloseResolver ();
  170. #endif
  171. }
  172.  
  173. /* MM command loop
  174.  * Accepts: MAIL stream
  175.  */
  176.  
  177. void mm (stream,debug)
  178.     MAILSTREAM *stream;
  179.     long debug;
  180. {
  181.   char cmd[256],cmdx[128];
  182.   char *arg;
  183.   long i;
  184.   long last = 0;
  185.   BODY *body;
  186.   status (stream);        /* first report message status */
  187.   while (stream) {
  188.     prompt ("MTest>",cmd);    /* prompt user, get command */
  189.                 /* get argument */
  190.     if (arg = strchr (cmd,' ')) *arg++ = '\0';
  191.     switch (*ucase (cmd)) {    /* dispatch based on command */
  192.     case 'B':            /* Body command */
  193.       if (arg) last = atoi (arg);
  194.       else if (last == 0 ) {
  195.     puts ("?Missing message number");
  196.     break;
  197.       }
  198.       if (last > 0 && last <= stream->nmsgs) {
  199.     mail_fetchstructure (stream,last,&body);
  200.     if (body) display_body (body,NIL,(long) 0);
  201.     else puts ("%No body information available");
  202.       }
  203.       else puts ("?Bad message number");
  204.       break;
  205.     case 'C':            /* Check command */
  206.       mail_check (stream);
  207.       status (stream);
  208.       break;
  209.     case 'D':            /* Delete command */
  210.       if (arg) last = atoi (arg);
  211.       else {
  212.     if (last == 0) {
  213.       puts ("?Missing message number");
  214.       break;
  215.     }
  216.     arg = cmd;
  217.     sprintf (arg,"%ld",last);
  218.       }
  219.       if (last > 0 && last <= stream->nmsgs)
  220.     mail_setflag (stream,arg,"\\DELETED");
  221.       else puts ("?Bad message number");
  222.       break;
  223.     case 'E':            /* Expunge command */
  224.       mail_expunge (stream);
  225.       last = 0;
  226.       break;
  227.     case 'F':            /* Find command */
  228.       if (!arg) arg = "*";
  229.       puts ("Subscribed mailboxes:");
  230.       mail_find (NIL,arg);
  231.       puts ("Subscribed bboards:");
  232.       mail_find_bboards (NIL,arg);
  233.       puts ("Known mailboxes:");
  234.       mail_find_all (NIL,arg);
  235.       puts ("Known bboards:");
  236.       mail_find_all_bboard (NIL,arg);
  237.       if ((*stream->mailbox == '{') ||
  238.       ((*stream->mailbox == '*') && (stream->mailbox[1] == '{'))) {
  239.     puts ("Remote Subscribed mailboxes:");
  240.     mail_find (stream,arg);
  241.     puts ("Remote Subscribed bboards:");
  242.     mail_find_bboards (stream,arg);
  243.     puts ("Remote known mailboxes:");
  244.     mail_find_all (stream,arg);
  245.     puts ("Remote known bboards:");
  246.     mail_find_all_bboard (stream,arg);
  247.       }
  248.       break;
  249.     case 'G':
  250.       mail_gc (stream,GC_ENV|GC_TEXTS|GC_ELT);
  251.       break;
  252.     case 'H':            /* Headers command */
  253.       if (arg) {
  254.     if (!(last = atoi (arg))) {
  255.       mail_search (stream,arg);
  256.       for (i = 1; i <= stream->nmsgs; ++i)
  257.         if (mail_elt (stream,i)->searched) header (stream,i);
  258.       break;
  259.     }
  260.       }
  261.       else if (last == 0) {
  262.     puts ("?Missing message number");
  263.     break;
  264.       }
  265.       if (last > 0 && last <= stream->nmsgs) header (stream,last);
  266.       else puts ("?Bad message number");
  267.       break;
  268.     case 'M':
  269.       prompt ("Destination: ",cmdx);
  270.       mail_move (stream,arg,cmdx);
  271.       break;
  272.     case 'N':            /* New mailbox command */
  273.       if (!arg) {
  274.     puts ("?Missing mailbox");
  275.     break;
  276.       }
  277.                 /* get the new mailbox */
  278.       while (!(stream = mail_open (stream,arg,debug)))
  279.     prompt ("Mailbox: ",arg);
  280.       last = 0;
  281.       status (stream);
  282.       break;
  283.     case 'Q':            /* Quit command */
  284.       mail_close (stream);
  285.       stream = NIL;
  286.       break;
  287.     case 'S':            /* Send command */
  288.       smtptest (debug);
  289.       break;
  290.     case 'T':            /* Type command */
  291.       if (arg) last = atoi (arg);
  292.       else if (last == 0 ) {
  293.     puts ("?Missing message number");
  294.     break;
  295.       }
  296.       if (last > 0 && last <= stream->nmsgs) {
  297.     printf ("%s",mail_fetchheader (stream,last));
  298.     puts (mail_fetchtext (stream,last));
  299.       }
  300.       else puts ("?Bad message number");
  301.       break;
  302.     case 'U':            /* Undelete command */
  303.       if (arg) last = atoi (arg);
  304.       else {
  305.     if (last == 0 ) {
  306.       puts ("?Missing message number");
  307.       break;
  308.     }
  309.     arg = cmd;
  310.     sprintf (arg,"%ld",last);
  311.       }
  312.       if (last > 0 && last <= stream->nmsgs)
  313.     mail_clearflag (stream,arg,"\\DELETED");
  314.       else puts ("?Bad message number");
  315.       break;
  316.     case 'X':            /* Xit command */
  317.       mail_expunge (stream);
  318.       mail_close (stream);
  319.       stream = NIL;
  320.       break;
  321.     case '+':
  322.       mail_debug (stream); debug = T;
  323.       break;
  324.     case '-':
  325.       mail_nodebug (stream); debug = NIL;
  326.       break;
  327.     case '?':            /* ? command */
  328.       puts ("Body, Check, Delete, Expunge, Find, GC, Headers, Move,");
  329.       puts (" New Mailbox, Quit, Send, Type, Undelete, Xit,");
  330.       puts (" +, -, or <RETURN> for next message");
  331.       break;
  332.     case '\0':        /* null command (type next message) */
  333.       if (last > 0 && last++ < stream->nmsgs) {
  334.     printf ("%s",mail_fetchheader (stream,last));
  335.     puts (mail_fetchtext (stream,last));
  336.       }
  337.       else puts ("%No next message");
  338.       break;
  339.     default:            /* bogus command */
  340.       printf ("?Unrecognized command: %s\n",cmd);
  341.       break;
  342.     }
  343.   }
  344. }
  345.  
  346. /* MM display header
  347.  * Accepts: IMAP2 stream
  348.  *        message number
  349.  */
  350.  
  351. void header (stream,msgno)
  352.     MAILSTREAM *stream;
  353.     long msgno;
  354. {
  355.   unsigned long i;
  356.   char tmp[256];
  357.   char *t;
  358.   MESSAGECACHE *cache = mail_elt (stream,msgno);
  359.  
  360.   mail_fetchstructure (stream,msgno,NIL);
  361.   tmp[0] = cache->recent ? (cache->seen ? 'R': 'N') : ' ';
  362.   tmp[1] = (cache->recent | cache->seen) ? ' ' : 'U';
  363.   tmp[2] = cache->flagged ? 'F' : ' ';
  364.   tmp[3] = cache->answered ? 'A' : ' ';
  365.   tmp[4] = cache->deleted ? 'D' : ' ';
  366.   sprintf (tmp+5,"%4ld) ",cache->msgno);
  367.   mail_date (tmp+11,cache);
  368.   tmp[17] = ' ';
  369.   tmp[18] = '\0';
  370.   mail_fetchfrom (tmp+18,stream,msgno,(long) 20);
  371.   strcat (tmp," ");
  372.   if (i = cache->user_flags) {
  373.     strcat (tmp,"{");
  374.     while (i) {
  375.       strcat (tmp,stream->user_flags[find_rightmost_bit (&i)]);
  376.       if (i) strcat (tmp," ");
  377.     }
  378.     strcat (tmp,"} ");
  379.   }
  380.   mail_fetchsubject (t = tmp + strlen (tmp),stream,msgno,(long) 25);
  381.   sprintf (t += strlen (t)," (%ld chars)",cache->rfc822_size);
  382.   puts (tmp);
  383. }
  384.  
  385. /* MM display body
  386.  * Accepts: BODY structure pointer
  387.  *        prefix string
  388.  *        index
  389.  */
  390.  
  391. void display_body (body,pfx,i)
  392.     BODY *body;
  393.     char *pfx;
  394.     long i;
  395. {
  396.   char tmp[256];
  397.   char *s = tmp;
  398.   PARAMETER *par;
  399.   PART *part;            /* multipart doesn't have a row to itself */
  400.   if (body->type == TYPEMULTIPART) {
  401.                 /* if not first time, extend prefix */
  402.     if (pfx) sprintf (tmp,"%s%ld.",pfx,++i);
  403.     else tmp[0] = '\0';
  404.     for (i = 0,part = body->contents.part; part; part = part->next)
  405.       display_body (&part->body,tmp,i++);
  406.   }
  407.   else {            /* non-multipart, output oneline descriptor */
  408.     if (!pfx) pfx = "";        /* dummy prefix if top level */
  409.     sprintf (s," %s%ld %s",pfx,++i,body_types[body->type]);
  410.     if (body->subtype) sprintf (s += strlen (s),"/%s",body->subtype);
  411.     if (body->description) sprintf (s += strlen (s)," (%s)",body->description);
  412.     if (par = body->parameter) do
  413.       sprintf (s += strlen (s),";%s=%s",par->attribute,par->value);
  414.     while (par = par->next);
  415.     if (body->id) sprintf (s += strlen (s),", id = %s",body->id);
  416.     switch (body->type) {    /* bytes or lines depending upon body type */
  417.     case TYPEMESSAGE:        /* encapsulated message */
  418.     case TYPETEXT:        /* plain text */
  419.       sprintf (s += strlen (s)," (%ld lines)",body->size.lines);
  420.       break;
  421.     default:
  422.       sprintf (s += strlen (s)," (%ld bytes)",body->size.bytes);
  423.       break;
  424.     }
  425.     puts (tmp);            /* output this line */
  426.  
  427.                 /* encapsulated message? */
  428.     if (body->type == TYPEMESSAGE && (body = body->contents.msg.body)) {
  429.       if (body->type == TYPEMULTIPART) display_body (body,pfx,i-1);
  430.       else {            /* build encapsulation prefix */
  431.     sprintf (tmp,"%s%ld.",pfx,i);
  432.     display_body (body,tmp,(long) 0);
  433.       }
  434.     }
  435.   }
  436. }
  437.  
  438.  
  439. /* MM status report
  440.  * Accepts: MAIL stream
  441.  */
  442.  
  443. void status (stream)
  444.     MAILSTREAM *stream;
  445. {
  446.   long i;
  447.   char date[50];
  448.   rfc822_date (date);
  449.   puts (date);
  450.   if (stream) {
  451.     if (stream->mailbox) printf ("Mailbox: %s, %ld messages, %ld recent\n",
  452.                  stream->mailbox,stream->nmsgs,stream->recent);
  453.     else puts ("%No mailbox is open on this stream");
  454.     if (stream->user_flags[0]) {
  455.       printf ("Keywords: %s",stream->user_flags[0]);
  456.       for (i = 1; i < NUSERFLAGS && stream->user_flags[i]; ++i)
  457.     printf (", %s",stream->user_flags[i]);
  458.       puts ("");
  459.     }
  460.   }
  461. }
  462.  
  463.  
  464. /* Prompt user for input
  465.  * Accepts: pointer to prompt message
  466.  *          pointer to input buffer
  467.  */
  468.  
  469. void prompt (msg,txt)
  470.     char *msg;
  471.     char *txt;
  472. {
  473.   printf ("%s",msg);
  474.   gets (txt);
  475. }
  476.  
  477. /* Interfaces to C-client */
  478.  
  479.  
  480. void mm_searched (stream,number)
  481.     MAILSTREAM *stream;
  482.     long number;
  483. {
  484. }
  485.  
  486.  
  487. void mm_exists (stream,number)
  488.     MAILSTREAM *stream;
  489.     long number;
  490. {
  491. }
  492.  
  493.  
  494. void mm_expunged (stream,number)
  495.     MAILSTREAM *stream;
  496.     long number;
  497. {
  498. }
  499.  
  500.  
  501. void mm_flags (stream,number)
  502.     MAILSTREAM *stream;
  503.     long number;
  504. {
  505. }
  506.  
  507.  
  508. void mm_notify (stream,string,errflg)
  509.     MAILSTREAM *stream;
  510.     char *string;
  511.     long errflg;
  512. {
  513.   mm_log (string,errflg);
  514. }
  515.  
  516.  
  517. void mm_mailbox (string)
  518.     char *string;
  519. {
  520.   putchar (' ');
  521.   puts (string);
  522. }
  523.  
  524.  
  525. void mm_bboard (string)
  526.     char *string;
  527. {
  528.   putchar (' ');
  529.   puts (string);
  530. }
  531.  
  532. void mm_log (string,errflg)
  533.     char *string;
  534.     long errflg;
  535. {
  536.   switch ((short) errflg) {
  537.   case NIL:
  538.     printf ("[%s]\n",string);
  539.     break;
  540.   case PARSE:
  541.   case WARN:
  542.     printf ("%%%s\n",string);
  543.     break;
  544.   case ERROR:
  545.     printf ("?%s\n",string);
  546.     break;
  547.   }
  548. }
  549.  
  550.  
  551. void mm_dlog (string)
  552.     char *string;
  553. {
  554.   puts (string);
  555. }
  556.  
  557.  
  558. void mm_login (host,user,pwd,trial)
  559.     char *host;
  560.     char *user;
  561.     char *pwd;
  562.     long trial;
  563. {
  564.   char tmp[MAILTMPLEN];
  565.   if (curhst) fs_give ((void **) &curhst);
  566.   curhst = (char *) fs_get (1+strlen (host));
  567.   strcpy (curhst,host);
  568.   sprintf (tmp,"{%s} username: ",host);
  569.   prompt (tmp,user);
  570.   if (curusr) fs_give ((void **) &curusr);
  571.   curusr = (char *) fs_get (1+strlen (user));
  572.   strcpy (curusr,user);
  573.   prompt ("password: ",pwd);
  574. }
  575.  
  576.  
  577. void mm_critical (stream)
  578.     MAILSTREAM *stream;
  579. {
  580. }
  581.  
  582.  
  583. void mm_nocritical (stream)
  584.     MAILSTREAM *stream;
  585. {
  586. }
  587.  
  588.  
  589. long mm_diskerror (stream,errcode,serious)
  590.     MAILSTREAM *stream;
  591.     long errcode;
  592.     long serious;
  593. {
  594. #if unix
  595.   kill (getpid (),SIGSTOP);
  596. #else
  597.   abort ();
  598. #endif
  599.   return NIL;
  600. }
  601.  
  602.  
  603. void mm_fatal (string)
  604.     char *string;
  605. {
  606.   printf ("?%s\n",string);
  607. }
  608.  
  609. /* SMTP tester */
  610.  
  611. void smtptest (debug)
  612.     long debug;
  613. {
  614.   SMTPSTREAM *stream = NIL;
  615.   char line[MAILTMPLEN];
  616.   unsigned char *text = (unsigned char *) fs_get (8*MAILTMPLEN);
  617.   ENVELOPE *msg = mail_newenvelope ();
  618.   BODY *body = mail_newbody ();
  619.   sprintf (line,"%s <%s@%s>",personalname,curusr,curhst);
  620.   rfc822_parse_adrlist (&msg->from,line,curhst);
  621.   sprintf (line,"%s@%s",curusr,curhst);
  622.   rfc822_parse_adrlist (&msg->return_path,line,curhst);
  623.   prompt ("To: ",line);
  624.   rfc822_parse_adrlist (&msg->to,line,curhst);
  625.   if (msg->to) {
  626.     prompt ("cc: ",line);
  627.     rfc822_parse_adrlist (&msg->cc,line,curhst);
  628.   }
  629.   else {
  630.     prompt ("Newsgroups: ",line);
  631.     if (*line) msg->newsgroups = cpystr (line);
  632.     else {
  633.       mail_free_body (&body);
  634.       mail_free_envelope (&msg);
  635.       fs_give ((void **) &text);
  636.     }
  637.   }
  638.   prompt ("Subject: ",line);
  639.   msg->subject = cpystr (line);
  640.   puts (" Msg (end with a line with only a '.'):");
  641.   body->type = TYPETEXT;
  642.   *text = '\0';
  643.   while (gets (line)) {
  644.     if (line[0] == '.') {
  645.       if (line[1] == '\0') break;
  646.       else strcat ((char *) text,".");
  647.     }
  648.     strcat ((char *) text,line);
  649.     strcat ((char *) text,"\015\012");
  650.   }
  651.   body->contents.text = text;
  652.   rfc822_date (line);
  653.   msg->date = (char *) fs_get (1+strlen (line));
  654.   strcpy (msg->date,line);
  655.   if (msg->to) {
  656.     puts ("Sending...");
  657.     if (stream = smtp_open (hostlist,debug)) {
  658.       if (smtp_mail (stream,"MAIL",msg,body)) puts ("[Ok]");
  659.       else printf ("[Failed - %s]\n",stream->reply);
  660.     }
  661.   }
  662.   else {
  663.     puts ("Posting...");
  664.     if (stream = nntp_open (newslist,debug)) {
  665.       if (nntp_mail (stream,msg,body)) puts ("[Ok]");
  666.       else printf ("[Failed - %s]\n",stream->reply);
  667.     }
  668.   }
  669.   if (stream) smtp_close (stream);
  670.   else puts ("[Can't open connection to any server]");
  671.   mail_free_envelope (&msg);
  672.   mail_free_body (&body);
  673. }
  674.