home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / imap-3.0 / non-ANSI / ipopd / ipop3d.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-06  |  13.0 KB  |  494 lines

  1. /*
  2.  * Program:    IPOP3D - IMAP2 to POP3 conversion server
  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:    1 November 1990
  13.  * Last Edited:    6 April 1993
  14.  *
  15.  * Copyright 1993 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made
  24.  * available "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35.  
  36.  
  37. /* Parameter files */
  38.  
  39. #include "mail.h"
  40. #include "osdep.h"
  41. #include <stdio.h>
  42. #include <ctype.h>
  43. #include <pwd.h>
  44. #include "misc.h"
  45.  
  46.  
  47. /* Size of temporary buffers */
  48. #define TMPLEN 1024
  49.  
  50.  
  51. /* Server states */
  52.  
  53. #define AUTHORIZATION 0
  54. #define TRANSACTION 1
  55. #define UPDATE 2
  56.  
  57. /* Global storage */
  58.  
  59. char *version = "3.2(9)";    /* server version */
  60. int state = AUTHORIZATION;    /* server state */
  61. MAILSTREAM *stream = NIL;    /* mailbox stream */
  62. long nmsgs = 0;            /* current number of messages */
  63. long last = 0;            /* highest message accessed */
  64. long il = 0;            /* initial last message */
  65. char *host = NIL;        /* remote host name */
  66. char *user = NIL;        /* user name */
  67. char *pass = NIL;        /* password */
  68. long *msg = NIL;        /* message translation vector */
  69.  
  70.  
  71. /* Drivers we use */
  72.  
  73. extern DRIVER imapdriver,tenexdriver,mhdriver,mboxdriver,bezerkdriver;
  74.  
  75.  
  76. /* Function prototypes */
  77.  
  78. void main  ();
  79. int login  ();
  80. void blat  ();
  81.  
  82. extern char *crypt  ();
  83.  
  84. /* Main program */
  85.  
  86. void main (argc,argv)
  87.     int argc;
  88.     char *argv[];
  89. {
  90.   long i,j,k;
  91.   char *s,*t;
  92.   char tmp[TMPLEN];
  93.   mail_link (&imapdriver);    /* install the IMAP driver */
  94.   mail_link (&tenexdriver);    /* install the Tenex mail driver */
  95.   mail_link (&mhdriver);    /* install the mh mail driver */
  96.   mail_link (&mboxdriver);    /* install the mbox mail driver */
  97.   mail_link (&bezerkdriver);    /* install the Berkeley mail driver */
  98.   printf ("+OK POP3 %s w/IMAP2 client (Comments to MRC@CAC.Washington.EDU)\015\012"
  99.       ,version);
  100.   fflush (stdout);        /* dump output buffer */
  101.                 /* command processing loop */
  102.   while ((state != UPDATE) && fgets (tmp,TMPLEN-1,stdin)) {
  103.                 /* find end of line */
  104.     if (!strchr (tmp,'\012')) puts ("-ERR Command line too long\015");
  105.     else if (!(s = strtok (tmp," \015\012"))) puts ("-ERR Null command\015");
  106.     else {            /* dispatch based on command */
  107.       ucase (s);        /* canonicalize case */
  108.                 /* snarf argument */
  109.       t = strtok (NIL,"\015\012");
  110.                 /* QUIT command always valid */
  111.       if (!strcmp (s,"QUIT")) state = UPDATE;
  112.       else switch (state) {    /* else dispatch based on state */
  113.       case AUTHORIZATION:    /* waiting to get logged in */
  114.     if (!strcmp (s,"USER")) {
  115.       fs_give ((void **) &host);
  116.       fs_give ((void **) &user);
  117.       if (t && *t) {    /* if user name given */
  118.                 /* remote user name? */
  119.         if (s = strchr (t,':')) {
  120.           *s++ = '\0';    /* tie off host name */
  121.           host = cpystr (t);/* copy host name */
  122.           user = cpystr (s);/* copy user name */
  123.         }
  124.                 /* local user name */
  125.         else user = cpystr (t);
  126.         puts ("+OK User name accepted, password please\015");
  127.       }
  128.       else puts ("-ERR Missing username argument\015");
  129.     }
  130.     else if (user && *user && !strcmp (s,"PASS"))
  131.       state = login (t,argc,argv);
  132.                 /* (chuckle) */
  133.     else if (!strcmp (s,"RPOP")) puts ("-ERR Nice try, bunkie\015");
  134.     else puts ("-ERR Unknown command in AUTHORIZATION state\015");
  135.     break;
  136.  
  137.       case TRANSACTION:        /* logged in */
  138.     if (!strcmp (s,"STAT")) {
  139.       for (i = 1,j = 0,k = 0; i <= nmsgs; i++)
  140.         if (msg[i] > 0) {    /* message still exists? */
  141.           j++;        /* count one more undeleted message */
  142.           k += mail_elt (stream,msg[i])->rfc822_size;
  143.         }
  144.       printf ("+OK %d %d\015\012",j,k);
  145.     }
  146.     else if (!strcmp (s,"LIST")) {
  147.       if (t && *t) {    /* argument do single message */
  148.         if (((i = atoi (t)) > 0) && (i <= nmsgs) && (msg[i] >0))
  149.           printf ("+OK %d %d\015\012",i,
  150.               mail_elt(stream,msg[i])->rfc822_size);
  151.         else puts ("-ERR No such message\015");
  152.       }
  153.       else {        /* entire mailbox */
  154.         puts ("+OK Mailbox scan listing follows\015");
  155.         for (i = 1,j = 0,k = 0; i <= nmsgs; i++) if (msg[i] > 0)
  156.           printf ("%d %d\015\012",i,mail_elt (stream,msg[i])->rfc822_size);
  157.         puts (".\015");    /* end of list */
  158.       }
  159.     }
  160.     else if (!strcmp (s,"RETR")) {
  161.       if (t && *t) {    /* must have an argument */
  162.         if (((i = atoi (t)) > 0) && (i <= nmsgs) && (msg[i] > 0)) {
  163.                 /* update highest message accessed */
  164.           if (i > last) last = i;
  165.           printf ("+OK %d octets\015\012",
  166.               mail_elt (stream,msg[i])->rfc822_size);
  167.                 /* output message */
  168.           blat (mail_fetchheader (stream,msg[i]),-1);
  169.           blat (mail_fetchtext (stream,msg[i]),-1);
  170.           puts (".\015");    /* end of list */
  171.         }
  172.         else puts ("-ERR No such message\015");
  173.       }
  174.       else puts ("-ERR Missing message number argument\015");
  175.     }
  176.     else if (!strcmp (s,"DELE")) {
  177.       if (t && *t) {    /* must have an argument */
  178.         if (((i = atoi (t)) > 0) && (i <= nmsgs) && (msg[i] > 0)) {
  179.                 /* update highest message accessed */
  180.           if (i > last) last = i;
  181.                 /* delete message */
  182.           sprintf (tmp,"%d",msg[i]);
  183.           mail_setflag (stream,tmp,"\\Deleted");
  184.           msg[i] = -msg[i];    /* note that we deleted this message */
  185.           puts ("+OK Message deleted\015");
  186.         }
  187.         else puts ("-ERR No such message\015");
  188.       }
  189.       else puts ("-ERR Missing message number argument\015");
  190.     }
  191.  
  192.     else if (!strcmp (s,"NOOP")) puts ("+OK No-op to you too!\015");
  193.     else if (!strcmp (s,"LAST")) printf ("+OK %d\015\012",last);
  194.     else if (!strcmp (s,"RSET")) {
  195.       if (nmsgs) {        /* undelete and unmark all of our messages */
  196.         for (i = 1; i <= nmsgs; i++) {
  197.                 /* ugly and inefficient, but trustworthy */
  198.           if (msg[i] < 0) {
  199.         sprintf (tmp,"%d",msg[i] = -msg[i]);
  200.         mail_clearflag (stream,tmp,i <= il ? "\\Deleted" :
  201.                   "\\Deleted \\Seen");
  202.           }
  203.           else if (i > il) {
  204.         sprintf (tmp,"%d",msg[i]);
  205.         mail_clearflag (stream,tmp,"\\Seen");
  206.           }
  207.         }
  208.         last = il;
  209.       }
  210.       puts ("+OK Reset state\015");
  211.     }
  212.     else if (!strcmp (s,"TOP")) {
  213.       if (t && *t) {    /* must have an argument */
  214.         if (((i = strtol (t,&t,10)) > 0) && (i <= nmsgs) && t && *t &&
  215.         ((j = atoi (t)) >= 0) && (msg[i] > 0)) {
  216.                 /* update highest message accessed */
  217.           if (i > last) last = i;
  218.           puts ("+OK Top of message follows\015");
  219.                 /* output message */
  220.           blat (mail_fetchheader (stream,msg[i]),-1);
  221.           blat (mail_fetchtext (stream,msg[i]),j);
  222.           puts (".\015");    /* end of list */
  223.         }
  224.         else puts ("-ERR Bad argument or no such message\015");
  225.       }
  226.       else puts ("-ERR Missing message number argument\015");
  227.     }
  228.     else if (!strcmp (s,"XTND")) puts ("-ERR Sorry I can't do that\015");
  229.     else puts ("-ERR Unknown command in TRANSACTION state\015");
  230.     break;
  231.       default:
  232.         puts ("-ERR Server in unknown state\015");
  233.     break;
  234.       }
  235.     }
  236.     fflush (stdout);        /* make sure output finished */
  237.   }
  238.                 /* expunge mailbox if a stream open */
  239.   if (stream && nmsgs) mail_expunge (stream);
  240.                 /* clean up the stream */
  241.   if (stream) mail_close (stream);
  242.   puts ("+OK Sayonara\015");    /* "now it's time to say sayonara..." */
  243.   fflush (stdout);        /* make sure output finished */
  244.   exit (0);            /* all done */
  245. }
  246.  
  247. /* Parse PASS command
  248.  * Accepts: pointer to command argument
  249.  * Returns: new state
  250.  */
  251.  
  252. int login (t,argc,argv)
  253.     char *t;
  254.     int argc;
  255.     char *argv[];
  256. {
  257.   long i,j;
  258.   char tmp[TMPLEN];
  259.   struct passwd *pwd = getpwnam ("nobody");
  260.   MESSAGECACHE *elt;
  261.   fs_give ((void **) &pass);    /* flush old passowrd */
  262.   if (!(t && *t)) {        /* if no password given */
  263.     puts ("-ERR Missing password argument\015");
  264.     return AUTHORIZATION;
  265.   }
  266.   pass = cpystr (t);        /* copy password argument */
  267.   if (host) {            /* remote; build remote INBOX */
  268.     sprintf (tmp,"{%s}INBOX",host);
  269.     if (pwd) {            /* try to become someone harmless */
  270.       setgid (pwd->pw_gid);    /* set group ID */
  271.       setuid (pwd->pw_uid);    /* and user ID */
  272.     }
  273.   }
  274.                 /* local; attempt login, select INBOX */
  275.   else if (server_login (user,pass,NIL,argc,argv)) strcpy (tmp,"INBOX");
  276.   else {
  277.     puts ("-ERR Bad login\015");/* vague error message to confuse crackers */
  278.     return AUTHORIZATION;
  279.   }
  280.   nmsgs = 0;            /* no messages yet */
  281.   if (msg) fs_give ((void **) &msg);
  282.                 /* if mailbox non-empty */
  283.   if ((stream = mail_open (stream,tmp,NIL)) && (j = stream->nmsgs)) {
  284.     sprintf (tmp,"1:%d",j);    /* fetch fast information for all messages */
  285.     mail_fetchfast (stream,tmp);
  286.     msg = (long *) fs_get ((stream->nmsgs + 1) * sizeof (long));
  287.     for (i = 1; i <= j; i++) if (!(elt = mail_elt (stream,i))->deleted) {
  288.       msg[++nmsgs] = i;        /* note the presence of this message */
  289.       if (elt->seen) il = last = nmsgs;
  290.     }
  291.   }
  292.   printf ("+OK Mailbox open, %d messages\015\012",nmsgs);
  293.   return TRANSACTION;
  294. }
  295.  
  296. /* Blat a string with dot checking
  297.  * Accepts: string
  298.  *        maximum number of lines if greater than zero
  299.  * This routine is uglier and kludgier than it should be, just to be robust
  300.  * in the case of a Tenex-format message which doesn't end in a newline.
  301.  */
  302.  
  303. void blat (text,lines)
  304.     char *text;
  305.     long lines;
  306. {
  307.   char c = *text++;
  308.   char d = *text++;
  309.   char e;
  310.                 /* no-op if zero lines or empty string */
  311.   if (!(lines && c && d)) return;
  312.   if (c == '.') putchar ('.');    /* double string-leading dot if necessary */
  313.   while (e = *text++) {        /* copy loop */
  314.     putchar (c);        /* output character */
  315.     if (c == '\012') {        /* end of line? */
  316.       if (!--lines) return;    /* count down another line, return if done */
  317.                 /* double leading dot as necessary */
  318.       if (d == '.') putchar ('.');
  319.     }
  320.     c = d; d = e;        /* move to next character */
  321.   }
  322.   puts ("\015");        /* output newline instead of last 2 chars */
  323. }
  324.  
  325. /* Co-routines from MAIL library */
  326.  
  327.  
  328. /* Message matches a search
  329.  * Accepts: IMAP2 stream
  330.  *        message number
  331.  */
  332.  
  333. void mm_searched (stream,msgno)
  334.     MAILSTREAM *stream;
  335.     long msgno;
  336. {
  337.   /* Never called */
  338. }
  339.  
  340.  
  341. /* Message exists (mailbox)
  342.     i.e. there are that many messages in the mailbox;
  343.  * Accepts: IMAP2 stream
  344.  *        message number
  345.  */
  346.  
  347. void mm_exists (stream,number)
  348.     MAILSTREAM *stream;
  349.     long number;
  350. {
  351.   /* Can't use this mechanism.  POP has no means of notifying the client of
  352.      new mail during the session. */
  353. }
  354.  
  355.  
  356. /* Message expunged
  357.  * Accepts: IMAP2 stream
  358.  *        message number
  359.  */
  360.  
  361. void mm_expunged (stream,number)
  362.     MAILSTREAM *stream;
  363.     long number;
  364. {
  365.   /* This isn't used */
  366. }
  367.  
  368.  
  369. /* Mailbox found
  370.  * Accepts: Mailbox name
  371.  */
  372.  
  373. void mm_mailbox (string)
  374.     char *string;
  375. {
  376.   /* This isn't used */
  377. }
  378.  
  379.  
  380. /* BBoard found
  381.  * Accepts: BBoard name
  382.  */
  383.  
  384. void mm_bboard (string)
  385.     char *string;
  386. {
  387.   /* This isn't used */
  388. }
  389.  
  390. /* Notification event
  391.  * Accepts: IMAP2 stream
  392.  *        string to log
  393.  *        error flag
  394.  */
  395.  
  396. void mm_notify (stream,string,errflg)
  397.     MAILSTREAM *stream;
  398.     char *string;
  399.     long errflg;
  400. {
  401.   mm_log (string,errflg);    /* just do mm_log action */
  402. }
  403.  
  404.  
  405. /* Log an event for the user to see
  406.  * Accepts: string to log
  407.  *        error flag
  408.  */
  409.  
  410. void mm_log (string,errflg)
  411.     char *string;
  412.     long errflg;
  413. {
  414.   /* Not doing anything here for now */
  415. }
  416.  
  417.  
  418. /* Log an event to debugging telemetry
  419.  * Accepts: string to log
  420.  */
  421.  
  422. void mm_dlog (string)
  423.     char *string;
  424. {
  425.   /* Not doing anything here for now */
  426. }
  427.  
  428.  
  429. /* Get user name and password for this host
  430.  * Accepts: host name
  431.  *        where to return user name
  432.  *        where to return password
  433.  *        trial count
  434.  */
  435.  
  436. void mm_login (host,username,password,trial)
  437.     char *host;
  438.     char *username;
  439.     char *password;
  440.     long trial;
  441. {
  442.   strcpy (username,user);    /* set user name */
  443.   strcpy (password,pass);    /* and password */
  444. }
  445.  
  446. /* About to enter critical code
  447.  * Accepts: stream
  448.  */
  449.  
  450. void mm_critical (stream)
  451.     MAILSTREAM *stream;
  452. {
  453.   /* Not doing anything here for now */
  454. }
  455.  
  456.  
  457. /* About to exit critical code
  458.  * Accepts: stream
  459.  */
  460.  
  461. void mm_nocritical (stream)
  462.     MAILSTREAM *stream;
  463. {
  464.   /* Not doing anything here for now */
  465. }
  466.  
  467.  
  468. /* Disk error found
  469.  * Accepts: stream
  470.  *        system error code
  471.  *        flag indicating that mailbox may be clobbered
  472.  * Returns: abort flag
  473.  */
  474.  
  475. long mm_diskerror (stream,errcode,serious)
  476.     MAILSTREAM *stream;
  477.     long errcode;
  478.     long serious;
  479. {
  480.   sleep (5);            /* can't do much better than this! */
  481.   return NIL;
  482. }
  483.  
  484.  
  485. /* Log a fatal error event
  486.  * Accepts: string to log
  487.  */
  488.  
  489. void mm_fatal (string)
  490.     char *string;
  491. {
  492.   mm_log (string,ERROR);    /* shouldn't happen normally */
  493. }
  494.