home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / pine3.07 / c-client / os_dos.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-14  |  13.1 KB  |  502 lines

  1. /*
  2.  * Program:    Operating-system dependent routines -- MS-DOS (Novell) version
  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:    11 April 1989
  13.  * Last Edited:    14 May 1992
  14.  *
  15.  * Copyright 1992 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. /* TCP input buffer -- must be large enough to prevent overflow */
  37.  
  38. #define BUFLEN 8192
  39.  
  40.  
  41. /* TCP I/O stream (must be before osdep.h is included) */
  42.  
  43. #define TCPSTREAM struct tcp_stream
  44. TCPSTREAM {
  45.   char *host;            /* host name */
  46.   char *localhost;        /* local host name */
  47.   int tcps;            /* tcp socket */
  48.   long ictr;            /* input counter */
  49.   char *iptr;            /* input pointer */
  50.   char ibuf[BUFLEN];        /* input buffer */
  51. };
  52.  
  53.  
  54. /* Private function prototypes */
  55.  
  56. #include <time.h>
  57. #include <sys\types.h>
  58. #include <sys\timeb.h>
  59. #include <sys\socket.h>
  60. #include <netinet\in.h>
  61. #include <netdb.h>
  62. #include "osdep.h"
  63. #include "mail.h"
  64. #include "misc.h"
  65.  
  66. /* Global data */
  67.  
  68. unsigned long rndm = 0xfeed;    /* initial `random' number */
  69.  
  70. /* Write current time in RFC 822 format
  71.  * Accepts: destination string
  72.  */
  73.  
  74. char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  75. char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  76.         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  77.  
  78. void rfc822_date (char *date)
  79. {
  80.   time_t ti = time (0);
  81.   struct tm *t;
  82.   tzset ();            /* initialize timezone stuff */
  83.   t = localtime (&ti);        /* output local time */
  84.   sprintf (date,"%s, %d %s %d %02d:%02d:%02d %s",
  85.        days[t->tm_wday],t->tm_mday,months[t->tm_mon],t->tm_year+1900,
  86.        t->tm_hour,t->tm_min,t->tm_sec,tzname[t->tm_isdst]);
  87. }
  88.  
  89. /* Get a block of free storage
  90.  * Accepts: size of desired block
  91.  * Returns: free storage block
  92.  */
  93.  
  94. void *fs_get (size_t size)
  95. {
  96.   void *block = malloc (size);
  97.   if (!block) fatal ("Out of free storage");
  98.   return (block);
  99. }
  100.  
  101.  
  102. /* Resize a block of free storage
  103.  * Accepts: ** pointer to current block
  104.  *        new size
  105.  */
  106.  
  107. void fs_resize (void **block,size_t size)
  108. {
  109.   if (!(*block = realloc (*block,size))) fatal ("Can't resize free storage");
  110. }
  111.  
  112.  
  113. /* Return a block of free storage
  114.  * Accepts: ** pointer to free storage block
  115.  */
  116.  
  117. void fs_give (void **block)
  118. {
  119.   free (*block);
  120.   *block = NIL;
  121. }
  122.  
  123.  
  124. /* Report a fatal error
  125.  * Accepts: string to output
  126.  */
  127.  
  128. void fatal (char *string)
  129. {
  130.   mm_fatal (string);        /* pass the string */
  131.   abort ();            /* die horribly */
  132. }
  133.  
  134. /* Copy string with CRLF newlines
  135.  * Accepts: destination string
  136.  *        pointer to size of destination string
  137.  *        source string
  138.  *        length of source string
  139.  */
  140.  
  141. char *strcrlfcpy (char **dst,unsigned long *dstl,char *src,unsigned long srcl)
  142. {
  143.   long i,j;
  144.   char *d = src;
  145.                 /* count number of LF's in source string(s) */
  146.   for (i = srcl,j = 0; j < srcl; j++) if (*d++ == '\012') i++;
  147.   if (i > *dstl) {        /* resize if not enough space */
  148.     fs_give ((void **) dst);    /* fs_resize does an unnecessary copy */
  149.     *dst = (char *) fs_get ((*dstl = i) + 1);
  150.   }
  151.   d = *dst;            /* destination string */
  152.                 /* copy strings, inserting CR's before LF's */
  153.   while (srcl--) switch (*src) {
  154.   case '\015':            /* unlikely carriage return */
  155.     *d++ = *src++;        /* copy it and any succeeding linefeed */
  156.     if (srcl && *src == '\012') {
  157.       *d++ = *src++;
  158.       srcl--;
  159.     }
  160.     break;
  161.   case '\012':            /* line feed? */
  162.     *d++ ='\015';        /* yes, prepend a CR, drop into default case */
  163.   default:            /* ordinary chararacter */
  164.     *d++ = *src++;        /* just copy character */
  165.     break;
  166.   }
  167.   *d = '\0';            /* tie off destination */
  168.   return *dst;            /* return destination */
  169. }
  170.  
  171.  
  172. /* Length of string after strcrlflen applied
  173.  * Accepts: source string
  174.  *        length of source string
  175.  */
  176.  
  177. unsigned long strcrlflen (char *src,unsigned long srcl)
  178. {
  179.   long i = srcl;        /* look for LF's */
  180.   while (srcl--) switch (*src++) {
  181.   case '\015':            /* unlikely carriage return */
  182.     if (srcl && *src == '\012') { src++; srcl--; }
  183.     break;
  184.   case '\012':            /* line feed? */
  185.     i++;
  186.   default:            /* ordinary chararacter */
  187.     break;
  188.   }
  189.   return i;
  190. }
  191.  
  192. /* Server log in (dummy place holder)
  193.  * Accepts: user name string
  194.  *        password string
  195.  *        optional place to return home directory
  196.  * Returns: T if password validated, NIL otherwise
  197.  */
  198.  
  199. long server_login (char *user,char *pass,char **home)
  200. {
  201.   return NIL;
  202. }
  203.  
  204. /* TCP/IP open
  205.  * Accepts: host name
  206.  *        contact port number
  207.  * Returns: TCP/IP stream if success else NIL
  208.  */
  209.  
  210. TCPSTREAM *tcp_open (char *host,long port)
  211. {
  212.   TCPSTREAM *stream = NIL;
  213.   struct sockaddr_in sin;
  214.   struct hostent *host_name;
  215.   int sock;
  216.   long adr,i,j,k,l;
  217.   char *s;
  218.   char tmp[MAILTMPLEN];
  219.   char *hostname = cpystr (host);
  220.                 /* set default gets routine */
  221.   if (!mailgets) mailgets = mm_gets;
  222.   /* The domain literal form is used (rather than simply the dotted decimal
  223.      as with other Unix programs) because it has to be a valid "host name"
  224.      in mailsystem terminology. */
  225.   sin.sin_family = AF_INET;    /* family is always Internet */
  226.                 /* look like domain literal? */
  227.   if (host[0] == '[' && host[(strlen (host))-1] == ']') {
  228.     strcpy (tmp,host+1);    /* yes, copy number part */
  229.     tmp[strlen (tmp)-1] = '\0';
  230.     if ((sin.sin_addr.s_addr == inet_addr (tmp)) == -1) {
  231.       sprintf (tmp,"Bad format domain-literal: %.80s",host);
  232.       mm_log (tmp,ERROR);
  233.       fs_give ((void **) hostname);
  234.       return NIL;
  235.     }
  236.   }
  237.   else {            /* lookup host name */
  238.     if ((sin.sin_addr.s_addr = rhost (&hostname)) == -1) {
  239.       sprintf (tmp,"Host not found: %s",host);
  240.       mm_log (tmp,ERROR);
  241.       fs_give ((void **) hostname);
  242.       return NIL;
  243.     }
  244.   }
  245.  
  246.                 /* copy port number in network format */
  247.   if (!(sin.sin_port = htons (port))) fatal ("Bad port argument to tcp_open");
  248.                 /* get a TCP stream */
  249.   if ((sock = socket (sin.sin_family,SOCK_STREAM,0)) < 0) {
  250.     sprintf (tmp,"Unable to create TCP socket (%d)",errno);
  251.     mm_log (tmp,ERROR);
  252.     fs_give ((void **) hostname);
  253.     return NIL;
  254.   }
  255.                 /* open connection */
  256.   if (connect (sock,(struct sockaddr *) &sin,sizeof (sin)) < 0) {
  257.     switch (errno) {        /* analyze error */
  258.     case ECONNREFUSED: s = "Refused"; break;
  259.     case ENO_RCB: s = "Insufficient system resources"; break;
  260.     case ETIMEDOUT: s = "Timed out"; break;
  261.     default: s = "Unknown error"; break;
  262.     }
  263.     sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",hostname,port,s,errno);
  264.     mm_log (tmp,ERROR);
  265.     fs_give ((void **) hostname);
  266.     soclose (sock);
  267.     return NIL;
  268.   }
  269.                 /* create TCP/IP stream */
  270.   stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
  271.   stream->host = hostname;    /* official host name */
  272.   adr = getmyipaddr ();        /* get local IP address */
  273.   i = adr >> 24; j = (adr >> 16) & 0xff; k = (adr >> 8) & 0xff; l = adr & 0xff;
  274.   sprintf (tmp,"[%ld.%ld.%ld.%ld]",i,j,k,l);
  275.   stream->localhost = cpystr (tmp);
  276.   stream->tcps = sock;        /* init socket */
  277.   stream->ictr = 0;        /* init input counter */
  278.   return stream;        /* return success */
  279. }
  280.   
  281. /* TCP/IP authenticated open
  282.  * Accepts: host name
  283.  *        service name
  284.  * Returns: TCP/IP stream if success else NIL
  285.  */
  286.  
  287. TCPSTREAM *tcp_aopen (char *host,char *service)
  288. {
  289.   return NIL;            /* always NIL on DOS */
  290. }
  291.  
  292. /* TCP/IP receive line
  293.  * Accepts: TCP/IP stream
  294.  * Returns: text line string or NIL if failure
  295.  */
  296.  
  297. char *tcp_getline (TCPSTREAM *stream)
  298. {
  299.   long n,m;
  300.   char *st;
  301.   char *ret;
  302.   char *stp;
  303.   char tmp[2];
  304.   fd_set fds;
  305.   FD_ZERO (&fds);        /* initialize selection vector */
  306.   if (stream->tcps < 0) return NIL;
  307.   while (stream->ictr < 1) {    /* if nothing in the buffer */
  308.     FD_SET (stream->tcps,&fds);/* set bit in selection vector */
  309.                 /* block and read */
  310.     if ((select (stream->tcps+1,&fds,0,0,0) < 0) ||
  311.     ((stream->ictr = soread (stream->tcps,stream->ibuf,BUFLEN)) < 1)) {
  312.       soclose (stream->tcps);    /* nuke the socket */
  313.       stream->tcps = -1;
  314.       return NIL;
  315.     }
  316.     stream->iptr = stream->ibuf;/* point at TCP buffer */
  317.   }
  318.   st = stream->iptr;        /* save start of string */
  319.   n = 0;            /* init string count */
  320.   while (stream->ictr--) {    /* look for end of line */
  321.                 /* saw the trailing CR? */
  322.     if (stream->iptr++[0] == '\015') {
  323.       ret = (char *) fs_get (n+1);
  324.       memcpy (ret,st,n);    /* copy into a free storage string */
  325.       ret[n] = '\0';        /* tie off string with null */
  326.                 /* eat the line feed */
  327.       tcp_getbuffer (stream,(unsigned long) 1,tmp);
  328.       return ret;        /* return it to caller */
  329.     }
  330.     ++n;            /* else count and try next character */
  331.   }
  332.   stp = (char *) fs_get (n);    /* copy first part of string */
  333.   memcpy (stp,st,n);
  334.                 /* recurse to get remainder */
  335.   if (st = tcp_getline (stream)) {
  336.                 /* build total string */
  337.     ret = (char *) fs_get (n+1+(m = strlen (st)));
  338.     memcpy (ret,stp,n);        /* copy first part */
  339.     memcpy (ret+n,st,m);    /* and second part */
  340.     ret[n+m] = '\0';        /* tie off string with null */
  341.     fs_give ((void **) &st);    /* flush partial string */
  342.     fs_give ((void **) &stp);    /* flush initial fragment */
  343.   }
  344.   else ret = stp;        /* return the fragment */
  345.   return ret;
  346. }
  347.  
  348. /* TCP/IP receive buffer
  349.  * Accepts: TCP/IP stream
  350.  *        size in bytes
  351.  *        buffer to read into
  352.  * Returns: T if success, NIL otherwise
  353.  */
  354.  
  355. long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
  356. {
  357.   unsigned long n;
  358.   char *bufptr = buffer;
  359.   fd_set fds;
  360.   FD_ZERO (&fds);        /* initialize selection vector */
  361.   if (stream->tcps < 0) return NIL;
  362.   while (size > 0) {        /* until request satisfied */
  363.     while (stream->ictr < 1) {    /* if nothing in the buffer */
  364.       FD_SET (stream->tcps,&fds);
  365.                 /* block and read */
  366.       if ((select (stream->tcps+1,&fds,0,0,0) < 0) ||
  367.       ((stream->ictr = soread (stream->tcps,stream->ibuf,BUFLEN)) < 1)) {
  368.     soclose (stream->tcps);    /* nuke the socket */
  369.     stream->tcps = -1;
  370.     return NIL;
  371.       }
  372.                 /* point at TCP buffer */
  373.       stream->iptr = stream->ibuf;
  374.     }
  375.     n = min (size,stream->ictr);/* number of bytes to transfer */
  376.                 /* do the copy */
  377.     memcpy (bufptr,stream->iptr,n);
  378.     bufptr += n;        /* update pointer */
  379.     stream->iptr +=n;
  380.     size -= n;            /* update # of bytes to do */
  381.     stream->ictr -=n;
  382.   }
  383.   bufptr[0] = '\0';        /* tie off string */
  384.   return T;
  385. }
  386.  
  387. /* TCP/IP send string as record
  388.  * Accepts: TCP/IP stream
  389.  * Returns: T if success else NIL
  390.  */
  391.  
  392. long tcp_soutr (TCPSTREAM *stream,char *string)
  393. {
  394.   long i;
  395.   unsigned long size = strlen (string);
  396.   fd_set fds;
  397.   FD_ZERO (&fds);        /* initialize selection vector */
  398.   if (stream->tcps < 0) return NIL;
  399.   while (size > 0) {        /* until request satisfied */
  400.     FD_SET (stream->tcps,&fds);/* set bit in selection vector */
  401.     if ((select (stream->tcps+1,0,&fds,0,0) < 0) ||
  402.     ((i = sowrite (stream->tcps,string,size)) < 0)) {
  403.       soclose (stream->tcps);    /* nuke the socket */
  404.       stream->tcps = -1;
  405.       return NIL;
  406.     }
  407.     size -= i;            /* count this size */
  408.     string += i;
  409.   }
  410.   return T;            /* all done */
  411. }
  412.  
  413.  
  414. /* TCP/IP close
  415.  * Accepts: TCP/IP stream
  416.  */
  417.  
  418. void tcp_close (TCPSTREAM *stream)
  419. {
  420.                 /* nuke the socket */
  421.   if (stream->tcps >= 0) soclose (stream->tcps);
  422.   stream->tcps = -1;
  423.                 /* flush host names */
  424.   fs_give ((void **) &stream->host);
  425.   fs_give ((void **) &stream->localhost);
  426.   fs_give ((void **) &stream);    /* flush the stream */
  427. }
  428.  
  429. /* TCP/IP get host name
  430.  * Accepts: TCP/IP stream
  431.  * Returns: host name for this stream
  432.  */
  433.  
  434. char *tcp_host (TCPSTREAM *stream)
  435. {
  436.   return stream->host;        /* return host name */
  437. }
  438.  
  439.  
  440. /* TCP/IP get local host name
  441.  * Accepts: TCP/IP stream
  442.  * Returns: local host name
  443.  */
  444.  
  445. char *tcp_localhost (TCPSTREAM *stream)
  446. {
  447.   return stream->localhost;    /* return local host name */
  448. }
  449.  
  450. /* These functions are only used by rfc822.c for calculating cookies.  So this
  451.  * is good enough.  If anything better is needed fancier functions will be
  452.  * needed.
  453.  */
  454.  
  455.  
  456. /* Return host ID
  457.  */
  458.  
  459. unsigned long gethostid ()
  460. {
  461.   return (unsigned long) getmyipaddr ();
  462. }
  463.  
  464.  
  465. /* Return random number
  466.  */
  467.  
  468. long random ()
  469. {
  470.   return rndm *= 0xdae0;
  471. }
  472.  
  473.  
  474. /* Return `process ID'
  475.  */
  476.  
  477. long getpid ()
  478. {
  479.   return 1;
  480. }
  481.  
  482.  
  483. /* These two are used for pattern matching in misc.c, but are actually never
  484.  * called in DOS.
  485.  */
  486.  
  487.  
  488. /* Dummy re_comp -- always return NIL */
  489.  
  490. char *re_comp (char *s)
  491. {
  492.   return NIL;
  493. }
  494.  
  495.  
  496. /* Dummy re_exec -- always return T */
  497.  
  498. long re_exec (char *s)
  499. {
  500.   return T;
  501. }
  502.