home *** CD-ROM | disk | FTP | other *** search
/ ftp.uv.es / 2014.11.ftp.uv.es.tar / ftp.uv.es / pub / unix / pine4.10.tar.gz / pine4.10.tar / pine4.10 / imap / src / mtest / mtest.c < prev    next >
C/C++ Source or Header  |  1998-09-16  |  21KB  |  748 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:    7 January 1998
  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 1998 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. #include "mail.h"
  48. #include "osdep.h"
  49. #include "rfc822.h"
  50. #include "smtp.h"
  51. #include "nntp.h"
  52.  
  53. /* Excellent reasons to hate ifdefs, and why my real code never uses them */
  54.  
  55. #ifndef unix
  56. # define unix 0
  57. #endif
  58.  
  59. #if unix
  60. # define UNIXLIKE 1
  61. # define MACOS 0
  62. # include <pwd.h>
  63. char *getpass ();
  64. #else
  65. # define UNIXLIKE 0
  66. # ifdef noErr
  67. #  define MACOS 1
  68. #  include <Memory.h>
  69. # else
  70. #  define MACOS 0
  71. # endif
  72. #endif
  73. #include "misc.h"
  74.  
  75. char *curhst = NIL;        /* currently connected host */
  76. char *curusr = NIL;        /* current login user */
  77. char personalname[MAILTMPLEN];    /* user's personal name */
  78.  
  79. static char *hostlist[] = {    /* SMTP server host list */
  80.   "mailhost",
  81.   "localhost",
  82.   NIL
  83. };
  84.  
  85. static char *newslist[] = {    /* Netnews server host list */
  86.   "news",
  87.   NIL
  88. };
  89.  
  90. int main (void);
  91. void mm (MAILSTREAM *stream,long debug);
  92. void overview_header (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov);
  93. void header (MAILSTREAM *stream,long msgno);
  94. void display_body (BODY *body,char *pfx,long i);
  95. void status (MAILSTREAM *stream);
  96. void prompt (char *msg,char *txt);
  97. void smtptest (long debug);
  98.  
  99. /* Main program - initialization */
  100.  
  101. int main ()
  102. {
  103.   MAILSTREAM *stream = NIL;
  104.   void *sdb = NIL;
  105.   char *s,tmp[MAILTMPLEN];
  106.   long debug;
  107. #include "linkage.c"
  108. #if MACOS
  109.   {
  110.     size_t *base = (size_t *) 0x000908;
  111.                 /* increase stack size on a Mac */
  112.     SetApplLimit ((Ptr) (*base - (size_t) 65535L));
  113.   }
  114. #endif
  115. #if UNIXLIKE
  116.   curusr = cpystr(myusername());/* current user is this name */
  117.   {
  118.     char *suffix;
  119.     struct passwd *pwd = getpwnam (curusr);
  120.     if (pwd) {
  121.       strcpy (tmp,pwd->pw_gecos);
  122.                 /* dyke out the office and phone poop */
  123.       if (suffix = strchr (tmp,',')) suffix[0] = '\0';
  124.       strcpy (personalname,tmp);/* make a permanent copy of it */
  125.     }
  126.     else personalname[0] = '\0';
  127.   }
  128. #else
  129.   curusr = cpystr ("somebody");
  130.   personalname[0] = '\0';
  131. #endif
  132.   curhst = cpystr (mylocalhost ());
  133.   puts ("MTest -- C client test program");
  134.   if (!*personalname) prompt ("Personal name: ",personalname);
  135.                 /* user wants protocol telemetry? */
  136.   prompt ("Debug protocol (y/n)?",tmp);
  137.   ucase (tmp);
  138.   debug = (tmp[0] == 'Y') ? T : NIL;
  139.   do {
  140.     prompt ("Mailbox ('?' for help): ",tmp);
  141.     if (!strcmp (tmp,"?")) {
  142.       puts ("Enter INBOX, mailbox name, or IMAP mailbox as {host}mailbox");
  143.       puts ("Known local mailboxes:");
  144.       mail_list (NIL,NIL,"%");
  145.       if (s = sm_read (&sdb)) {
  146.     puts ("Local subscribed mailboxes:");
  147.     do (mm_lsub (NIL,NIL,s,NIL));
  148.     while (s = sm_read (&sdb));
  149.       }
  150.       puts ("or just hit return to quit");
  151.     }
  152.     else if (tmp[0]) stream = mail_open (stream,tmp,debug ? OP_DEBUG : NIL);
  153.   } while (!stream && tmp[0]);
  154.   mm (stream,debug);        /* run user interface if opened */
  155. #if MACOS
  156.                 /* clean up resolver */
  157.   if (resolveropen) CloseResolver ();
  158. #endif
  159.   return NIL;
  160. }
  161.  
  162. /* MM command loop
  163.  * Accepts: MAIL stream
  164.  */
  165.  
  166. void mm (MAILSTREAM *stream,long debug)
  167. {
  168.   void *sdb = NIL;
  169.   char cmd[MAILTMPLEN];
  170.   char *s,*arg;
  171.   unsigned long i;
  172.   unsigned long last = 0;
  173.   BODY *body;
  174.   status (stream);        /* first report message status */
  175.   while (stream) {
  176.     prompt ("MTest>",cmd);    /* prompt user, get command */
  177.                 /* get argument */
  178.     if (arg = strchr (cmd,' ')) *arg++ = '\0';
  179.     switch (*ucase (cmd)) {    /* dispatch based on command */
  180.     case 'B':            /* Body command */
  181.       if (arg) last = atoi (arg);
  182.       else if (!last) {
  183.     puts ("?Missing message number");
  184.     break;
  185.       }
  186.       if (last && (last <= stream->nmsgs)) {
  187.     mail_fetchstructure (stream,last,&body);
  188.     if (body) display_body (body,NIL,(long) 0);
  189.     else puts ("%No body information available");
  190.       }
  191.       else puts ("?Bad message number");
  192.       break;
  193.     case 'C':            /* Check command */
  194.       mail_check (stream);
  195.       status (stream);
  196.       break;
  197.     case 'D':            /* Delete command */
  198.       if (arg) last = atoi (arg);
  199.       else {
  200.     if (last == 0) {
  201.       puts ("?Missing message number");
  202.       break;
  203.     }
  204.     arg = cmd;
  205.     sprintf (arg,"%ld",last);
  206.       }
  207.       if (last && (last <= stream->nmsgs))
  208.     mail_setflag (stream,arg,"\\DELETED");
  209.       else puts ("?Bad message number");
  210.       break;
  211.     case 'E':            /* Expunge command */
  212.       mail_expunge (stream);
  213.       last = 0;
  214.       break;
  215.     case 'F':            /* Find command */
  216.       if (!arg) {
  217.     arg = "%";
  218.     if (s = sm_read (&sdb)) {
  219.       puts ("Local network subscribed mailboxes:");
  220.       do if (*s == '{') (mm_lsub (NIL,NIL,s,NIL));
  221.       while (s = sm_read (&sdb));
  222.     }
  223.       }
  224.       puts ("Subscribed mailboxes:");
  225.       mail_lsub (((arg[0] == '{') && (*stream->mailbox == '{')) ? stream : NIL,
  226.          NIL,arg);
  227.       puts ("Known mailboxes:");
  228.       mail_list (((arg[0] == '{') && (*stream->mailbox == '{')) ? stream : NIL,
  229.          NIL,arg);
  230.       break;
  231.     case 'G':
  232.       mail_gc (stream,GC_ENV|GC_TEXTS|GC_ELT);
  233.       break;
  234.     case 'H':            /* Headers command */
  235.       if (arg) {
  236.     if (!(last = atoi (arg))) {
  237.       mail_search (stream,arg);
  238.       for (i = 1; i <= stream->nmsgs; ++i)
  239.         if (mail_elt (stream,i)->searched) header (stream,i);
  240.       break;
  241.     }
  242.       }
  243.       else if (last == 0) {
  244.     puts ("?Missing message number");
  245.     break;
  246.       }
  247.       if (last && (last <= stream->nmsgs)) header (stream,last);
  248.       else puts ("?Bad message number");
  249.       break;
  250.     case 'L':            /* Literal command */
  251.       if (arg) last = atoi (arg);
  252.       else if (!last) {
  253.     puts ("?Missing message number");
  254.     break;
  255.       }
  256.       if (last && (last <= stream->nmsgs))
  257.     puts (mail_fetch_message (stream,last,NIL,NIL));
  258.       else puts ("?Bad message number");
  259.       break;
  260.     case 'M':
  261.       mail_status (NIL,arg ? arg : stream->mailbox,
  262.            SA_MESSAGES|SA_RECENT|SA_UNSEEN|SA_UIDNEXT|SA_UIDVALIDITY);
  263.       break;
  264.     case 'N':            /* New mailbox command */
  265.       if (!arg) {
  266.     puts ("?Missing mailbox");
  267.     break;
  268.       }
  269.                 /* get the new mailbox */
  270.       while (!(stream = mail_open (stream,arg,debug)))
  271.     prompt ("Mailbox: ",arg);
  272.       last = 0;
  273.       status (stream);
  274.       break;
  275.     case 'O':            /* Overview command */
  276.       if (!arg) {
  277.     puts ("?Missing UID");
  278.     break;
  279.       }
  280.       mail_fetch_overview (stream,arg,overview_header);
  281.       break;
  282.     case 'Q':            /* Quit command */
  283.       mail_close (stream);
  284.       stream = NIL;
  285.       break;
  286.     case 'S':            /* Send command */
  287.       smtptest (debug);
  288.       break;
  289.     case '\0':            /* null command (type next message) */
  290.       if (!last || (last++ >= stream->nmsgs)) {
  291.     puts ("%No next message");
  292.     break;
  293.       }
  294.     case 'T':            /* Type command */
  295.       if (arg) last = atoi (arg);
  296.       else if (!last) {
  297.     puts ("?Missing message number");
  298.     break;
  299.       }
  300.       if (last && (last <= stream->nmsgs)) {
  301.     STRINGLIST *lines = mail_newstringlist ();
  302.     STRINGLIST *cur = lines;
  303.     cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
  304.                        cpystr ("Date")));
  305.     cur = cur->next = mail_newstringlist ();
  306.     cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
  307.                        cpystr ("From")));
  308.     cur = cur->next = mail_newstringlist ();
  309.     cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
  310.                        cpystr (">From")));
  311.     cur = cur->next = mail_newstringlist ();
  312.     cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
  313.                        cpystr ("Subject")));
  314.     cur = cur->next = mail_newstringlist ();
  315.     cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
  316.                        cpystr ("To")));
  317.     cur = cur->next = mail_newstringlist ();
  318.     cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
  319.                        cpystr ("cc")));
  320.     cur = cur->next = mail_newstringlist ();
  321.     cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
  322.                        cpystr ("Newsgroups")));
  323.     printf ("%s",mail_fetchheader_full (stream,last,lines,NIL,NIL));
  324.     puts (mail_fetchtext (stream,last));
  325.     mail_free_stringlist (&lines);
  326.       }
  327.       else puts ("?Bad message number");
  328.       break;
  329.     case 'U':            /* Undelete command */
  330.       if (arg) last = atoi (arg);
  331.       else {
  332.     if (!last) {
  333.       puts ("?Missing message number");
  334.       break;
  335.     }
  336.     arg = cmd;
  337.     sprintf (arg,"%ld",last);
  338.       }
  339.       if (last > 0 && last <= stream->nmsgs)
  340.     mail_clearflag (stream,arg,"\\DELETED");
  341.       else puts ("?Bad message number");
  342.       break;
  343.     case 'X':            /* Xit command */
  344.       mail_expunge (stream);
  345.       mail_close (stream);
  346.       stream = NIL;
  347.       break;
  348.     case '+':
  349.       mail_debug (stream); debug = T;
  350.       break;
  351.     case '-':
  352.       mail_nodebug (stream); debug = NIL;
  353.       break;
  354.     case '?':            /* ? command */
  355.       puts ("Body, Check, Delete, Expunge, Find, GC, Headers, Literal,");
  356.       puts (" MailboxStatus, New Mailbox, Overview, Quit, Send, Type,");
  357.       puts ("Undelete, Xit, +, -, or <RETURN> for next message");
  358.       break;
  359.     default:            /* bogus command */
  360.       printf ("?Unrecognized command: %s\n",cmd);
  361.       break;
  362.     }
  363.   }
  364. }
  365.  
  366. /* MM display header
  367.  * Accepts: IMAP2 stream
  368.  *        message number
  369.  */
  370.  
  371. void overview_header (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov)
  372. {
  373.   unsigned long i;
  374.   char *t,tmp[MAILTMPLEN];
  375.   ADDRESS *adr;
  376.   unsigned long msgno = mail_msgno (stream,uid);
  377.   MESSAGECACHE *elt = mail_elt (stream,msgno);
  378.   MESSAGECACHE selt;
  379.   tmp[0] = elt->recent ? (elt->seen ? 'R': 'N') : ' ';
  380.   tmp[1] = (elt->recent | elt->seen) ? ' ' : 'U';
  381.   tmp[2] = elt->flagged ? 'F' : ' ';
  382.   tmp[3] = elt->answered ? 'A' : ' ';
  383.   tmp[4] = elt->deleted ? 'D' : ' ';
  384.   mail_parse_date (&selt,ov->date);
  385.   sprintf (tmp+5,"%4ld) ",elt->msgno);
  386.   mail_date (tmp+11,&selt);
  387.   tmp[17] = ' ';
  388.   tmp[18] = '\0';
  389.   memset (tmp+18,' ',(size_t) 20);
  390.   tmp[38] = '\0';        /* tie off with null */
  391.                 /* get first from address from envelope */
  392.   for (adr = ov->from; adr && !adr->host; adr = adr->next);
  393.   if (adr) {            /* if a personal name exists use it */
  394.     if (!(t = adr->personal))
  395.       sprintf (t = tmp+400,"%s@%s",adr->mailbox,adr->host);
  396.     memcpy (tmp+18,t,(size_t) min (20,(long) strlen (t)));
  397.   }
  398.   strcat (tmp," ");
  399.   if (i = elt->user_flags) {
  400.     strcat (tmp,"{");
  401.     while (i) {
  402.       strcat (tmp,stream->user_flags[find_rightmost_bit (&i)]);
  403.       if (i) strcat (tmp," ");
  404.     }
  405.     strcat (tmp,"} ");
  406.   }
  407.   sprintf (tmp + strlen (tmp),"%.25s (%ld chars)",
  408.        ov->subject ? ov->subject : " ",ov->optional.octets);
  409.   puts (tmp);
  410. }
  411.  
  412. /* MM display header
  413.  * Accepts: IMAP2 stream
  414.  *        message number
  415.  */
  416.  
  417. void header (MAILSTREAM *stream,long msgno)
  418. {
  419.   unsigned long i;
  420.   char tmp[MAILTMPLEN];
  421.   char *t;
  422.   MESSAGECACHE *cache = mail_elt (stream,msgno);
  423.   mail_fetchstructure (stream,msgno,NIL);
  424.   tmp[0] = cache->recent ? (cache->seen ? 'R': 'N') : ' ';
  425.   tmp[1] = (cache->recent | cache->seen) ? ' ' : 'U';
  426.   tmp[2] = cache->flagged ? 'F' : ' ';
  427.   tmp[3] = cache->answered ? 'A' : ' ';
  428.   tmp[4] = cache->deleted ? 'D' : ' ';
  429.   sprintf (tmp+5,"%4ld) ",cache->msgno);
  430.   mail_date (tmp+11,cache);
  431.   tmp[17] = ' ';
  432.   tmp[18] = '\0';
  433.   mail_fetchfrom (tmp+18,stream,msgno,(long) 20);
  434.   strcat (tmp," ");
  435.   if (i = cache->user_flags) {
  436.     strcat (tmp,"{");
  437.     while (i) {
  438.       strcat (tmp,stream->user_flags[find_rightmost_bit (&i)]);
  439.       if (i) strcat (tmp," ");
  440.     }
  441.     strcat (tmp,"} ");
  442.   }
  443.   mail_fetchsubject (t = tmp + strlen (tmp),stream,msgno,(long) 25);
  444.   sprintf (t += strlen (t)," (%ld chars)",cache->rfc822_size);
  445.   puts (tmp);
  446. }
  447.  
  448. /* MM display body
  449.  * Accepts: BODY structure pointer
  450.  *        prefix string
  451.  *        index
  452.  */
  453.  
  454. void display_body (BODY *body,char *pfx,long i)
  455. {
  456.   char tmp[MAILTMPLEN];
  457.   char *s = tmp;
  458.   PARAMETER *par;
  459.   PART *part;            /* multipart doesn't have a row to itself */
  460.   if (body->type == TYPEMULTIPART) {
  461.                 /* if not first time, extend prefix */
  462.     if (pfx) sprintf (tmp,"%s%ld.",pfx,++i);
  463.     else tmp[0] = '\0';
  464.     for (i = 0,part = body->nested.part; part; part = part->next)
  465.       display_body (&part->body,tmp,i++);
  466.   }
  467.   else {            /* non-multipart, output oneline descriptor */
  468.     if (!pfx) pfx = "";        /* dummy prefix if top level */
  469.     sprintf (s," %s%ld %s",pfx,++i,body_types[body->type]);
  470.     if (body->subtype) sprintf (s += strlen (s),"/%s",body->subtype);
  471.     if (body->description) sprintf (s += strlen (s)," (%s)",body->description);
  472.     if (par = body->parameter) do
  473.       sprintf (s += strlen (s),";%s=%s",par->attribute,par->value);
  474.     while (par = par->next);
  475.     if (body->id) sprintf (s += strlen (s),", id = %s",body->id);
  476.     switch (body->type) {    /* bytes or lines depending upon body type */
  477.     case TYPEMESSAGE:        /* encapsulated message */
  478.     case TYPETEXT:        /* plain text */
  479.       sprintf (s += strlen (s)," (%ld lines)",body->size.lines);
  480.       break;
  481.     default:
  482.       sprintf (s += strlen (s)," (%ld bytes)",body->size.bytes);
  483.       break;
  484.     }
  485.     puts (tmp);            /* output this line */
  486.                 /* encapsulated message? */
  487.     if ((body->type == TYPEMESSAGE) && !strcmp (body->subtype,"RFC822") &&
  488.     (body = body->nested.msg->body)) {
  489.       if (body->type == TYPEMULTIPART) display_body (body,pfx,i-1);
  490.       else {            /* build encapsulation prefix */
  491.     sprintf (tmp,"%s%ld.",pfx,i);
  492.     display_body (body,tmp,(long) 0);
  493.       }
  494.     }
  495.   }
  496. }
  497.  
  498. /* MM status report
  499.  * Accepts: MAIL stream
  500.  */
  501.  
  502. void status (MAILSTREAM *stream)
  503. {
  504.   long i;
  505.   char date[MAILTMPLEN];
  506.   rfc822_date (date);
  507.   puts (date);
  508.   if (stream) {
  509.     if (stream->mailbox)
  510.       printf (" %s mailbox: %s, %ld messages, %ld recent\n",
  511.           stream->dtb->name,stream->mailbox,stream->nmsgs,stream->recent);
  512.     else puts ("%No mailbox is open on this stream");
  513.     if (stream->user_flags[0]) {
  514.       printf ("Keywords: %s",stream->user_flags[0]);
  515.       for (i = 1; i < NUSERFLAGS && stream->user_flags[i]; ++i)
  516.     printf (", %s",stream->user_flags[i]);
  517.       puts ("");
  518.     }
  519.   }
  520. }
  521.  
  522.  
  523. /* Prompt user for input
  524.  * Accepts: pointer to prompt message
  525.  *          pointer to input buffer
  526.  */
  527.  
  528. void prompt (char *msg,char *txt)
  529. {
  530.   printf ("%s",msg);
  531.   gets (txt);
  532. }
  533.  
  534. /* Interfaces to C-client */
  535.  
  536.  
  537. void mm_searched (MAILSTREAM *stream,unsigned long number)
  538. {
  539. }
  540.  
  541.  
  542. void mm_exists (MAILSTREAM *stream,unsigned long number)
  543. {
  544. }
  545.  
  546.  
  547. void mm_expunged (MAILSTREAM *stream,unsigned long number)
  548. {
  549. }
  550.  
  551.  
  552. void mm_flags (MAILSTREAM *stream,unsigned long number)
  553. {
  554. }
  555.  
  556.  
  557. void mm_notify (MAILSTREAM *stream,char *string,long errflg)
  558. {
  559.   mm_log (string,errflg);
  560. }
  561.  
  562.  
  563. void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
  564. {
  565.   putchar (' ');
  566.   if (delimiter) putchar (delimiter);
  567.   else fputs ("NIL",stdout);
  568.   putchar (' ');
  569.   fputs (mailbox,stdout);
  570.   if (attributes & LATT_NOINFERIORS) fputs (", no inferiors",stdout);
  571.   if (attributes & LATT_NOSELECT) fputs (", no select",stdout);
  572.   if (attributes & LATT_MARKED) fputs (", marked",stdout);
  573.   if (attributes & LATT_UNMARKED) fputs (", unmarked",stdout);
  574.   putchar ('\n');
  575. }
  576.  
  577.  
  578. void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
  579. {
  580.   putchar (' ');
  581.   if (delimiter) putchar (delimiter);
  582.   else fputs ("NIL",stdout);
  583.   putchar (' ');
  584.   fputs (mailbox,stdout);
  585.   if (attributes & LATT_NOINFERIORS) fputs (", no inferiors",stdout);
  586.   if (attributes & LATT_NOSELECT) fputs (", no select",stdout);
  587.   if (attributes & LATT_MARKED) fputs (", marked",stdout);
  588.   if (attributes & LATT_UNMARKED) fputs (", unmarked",stdout);
  589.   putchar ('\n');
  590. }
  591.  
  592.  
  593. void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
  594. {
  595.   printf (" Mailbox %s",mailbox);
  596.   if (status->flags & SA_MESSAGES) printf (", %lu messages",status->messages);
  597.   if (status->flags & SA_RECENT) printf (", %lu recent",status->recent);
  598.   if (status->flags & SA_UNSEEN) printf (", %lu unseen",status->unseen);
  599.   if (status->flags & SA_UIDVALIDITY) printf (", %lu UID validity",
  600.                           status->uidvalidity);
  601.   if (status->flags & SA_UIDNEXT) printf (", %lu next UID",status->uidnext);
  602.   printf ("\n");
  603. }
  604.  
  605.  
  606. void mm_log (char *string,long errflg)
  607. {
  608.   switch ((short) errflg) {
  609.   case NIL:
  610.     printf ("[%s]\n",string);
  611.     break;
  612.   case PARSE:
  613.   case WARN:
  614.     printf ("%%%s\n",string);
  615.     break;
  616.   case ERROR:
  617.     printf ("?%s\n",string);
  618.     break;
  619.   }
  620. }
  621.  
  622.  
  623. void mm_dlog (char *string)
  624. {
  625.   puts (string);
  626. }
  627.  
  628.  
  629. void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
  630. {
  631.   char tmp[MAILTMPLEN];
  632.   if (curhst) fs_give ((void **) &curhst);
  633.   curhst = (char *) fs_get (1+strlen (mb->host));
  634.   strcpy (curhst,mb->host);
  635.   if (*mb->user) {
  636.     strcpy (user,mb->user);
  637.     sprintf (tmp,"{%s/%s/user=%s} password: ",mb->host,mb->service,mb->user);
  638.   }
  639.   else {
  640.     sprintf (tmp,"{%s/%s} username: ",mb->host,mb->service);
  641.     prompt (tmp,user);
  642.     strcpy (tmp,"Password: ");
  643.   }
  644.   if (curusr) fs_give ((void **) &curusr);
  645.   curusr = cpystr (user);
  646. #if UNIXLIKE
  647.   strcpy (pwd,getpass (tmp));
  648. #else
  649.   prompt (tmp,pwd);
  650. #endif
  651. }
  652.  
  653.  
  654. void mm_critical (MAILSTREAM *stream)
  655. {
  656. }
  657.  
  658.  
  659. void mm_nocritical (MAILSTREAM *stream)
  660. {
  661. }
  662.  
  663.  
  664. long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
  665. {
  666. #if UNIXLIKE
  667.   kill (getpid (),SIGSTOP);
  668. #else
  669.   abort ();
  670. #endif
  671.   return NIL;
  672. }
  673.  
  674.  
  675. void mm_fatal (char *string)
  676. {
  677.   printf ("?%s\n",string);
  678. }
  679.  
  680. /* SMTP tester */
  681.  
  682. void smtptest (long debug)
  683. {
  684.   SENDSTREAM *stream = NIL;
  685.   char line[MAILTMPLEN];
  686.   char *text = (char *) fs_get (8*MAILTMPLEN);
  687.   ENVELOPE *msg = mail_newenvelope ();
  688.   BODY *body = mail_newbody ();
  689.   msg->from = mail_newaddr ();
  690.   msg->from->personal = cpystr (personalname);
  691.   msg->from->mailbox = cpystr (curusr);
  692.   msg->from->host = cpystr (curhst);
  693.   msg->return_path = mail_newaddr ();
  694.   msg->return_path->mailbox = cpystr (curusr);
  695.   msg->return_path->host = cpystr (curhst);
  696.   prompt ("To: ",line);
  697.   rfc822_parse_adrlist (&msg->to,line,curhst);
  698.   if (msg->to) {
  699.     prompt ("cc: ",line);
  700.     rfc822_parse_adrlist (&msg->cc,line,curhst);
  701.   }
  702.   else {
  703.     prompt ("Newsgroups: ",line);
  704.     if (*line) msg->newsgroups = cpystr (line);
  705.     else {
  706.       mail_free_body (&body);
  707.       mail_free_envelope (&msg);
  708.       fs_give ((void **) &text);
  709.     }
  710.   }
  711.   prompt ("Subject: ",line);
  712.   msg->subject = cpystr (line);
  713.   puts (" Msg (end with a line with only a '.'):");
  714.   body->type = TYPETEXT;
  715.   *text = '\0';
  716.   while (gets (line)) {
  717.     if (line[0] == '.') {
  718.       if (line[1] == '\0') break;
  719.       else strcat (text,".");
  720.     }
  721.     strcat (text,line);
  722.     strcat (text,"\015\012");
  723.   }
  724.   body->contents.text.data = (unsigned char *) text;
  725.   body->contents.text.size = strlen (text);
  726.   rfc822_date (line);
  727.   msg->date = (char *) fs_get (1+strlen (line));
  728.   strcpy (msg->date,line);
  729.   if (msg->to) {
  730.     puts ("Sending...");
  731.     if (stream = smtp_open (hostlist,debug)) {
  732.       if (smtp_mail (stream,"MAIL",msg,body)) puts ("[Ok]");
  733.       else printf ("[Failed - %s]\n",stream->reply);
  734.     }
  735.   }
  736.   else {
  737.     puts ("Posting...");
  738.     if (stream = nntp_open (newslist,debug)) {
  739.       if (nntp_mail (stream,msg,body)) puts ("[Ok]");
  740.       else printf ("[Failed - %s]\n",stream->reply);
  741.     }
  742.   }
  743.   if (stream) smtp_close (stream);
  744.   else puts ("[Can't open connection to any server]");
  745.   mail_free_envelope (&msg);
  746.   mail_free_body (&body);
  747. }
  748.