123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629 |
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #else
- #define MAIL_USE_POP
- #endif
- #ifdef MAIL_USE_POP
- #include <sys/types.h>
- #ifdef WINDOWSNT
- #include "ntlib.h"
- #include <winsock.h>
- #undef SOCKET_ERROR
- #define RECV(s,buf,len,flags) recv (s,buf,len,flags)
- #define SEND(s,buf,len,flags) send (s,buf,len,flags)
- #define CLOSESOCKET(s) closesocket (s)
- #else
- #include <netinet/in.h>
- #include <sys/socket.h>
- #define RECV(s,buf,len,flags) read (s,buf,len)
- #define SEND(s,buf,len,flags) write (s,buf,len)
- #define CLOSESOCKET(s) close (s)
- #endif
- #include <pop.h>
- #ifdef sun
- #include <malloc.h>
- #endif
- #ifdef HESIOD
- #include <hesiod.h>
- extern struct servent *hes_getservbyname ();
- #endif
- #include <pwd.h>
- #include <netdb.h>
- #include <errno.h>
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #ifdef KERBEROS
- # ifdef HAVE_KRB5_H
- # include <krb5.h>
- # endif
- # ifdef HAVE_KRB_H
- # include <krb.h>
- # else
- # ifdef HAVE_KERBEROSIV_KRB_H
- # include <kerberosIV/krb.h>
- # else
- # ifdef HAVE_KERBEROS_KRB_H
- # include <kerberos/krb.h>
- # endif
- # endif
- # endif
- # ifdef HAVE_COM_ERR_H
- # include <com_err.h>
- # endif
- #endif
- #include <min-max.h>
- #ifdef KERBEROS
- #ifndef KERBEROS5
- extern int krb_sendauth (
- );
- extern char *krb_realmofhost ();
- #endif
- #endif
- #ifndef WINDOWSNT
- #if !defined (HAVE_H_ERRNO) || !defined (HAVE_CONFIG_H)
- extern int h_errno;
- #endif
- #endif
- static int socket_connection (char *, int);
- static int pop_getline (popserver, char **);
- static int sendline (popserver, const char *);
- static int fullwrite (int, char *, int);
- static int getok (popserver);
- #if 0
- static int gettermination (popserver);
- #endif
- static void pop_trash (popserver);
- static char *find_crlf (char *, int);
- #define ERROR_MAX 160
- #define POP_PORT 110
- #define POP_SERVICE "pop3"
- #ifdef KERBEROS
- #define KPOP_PORT 1109
- #define KPOP_SERVICE "kpop"
- #endif
- char pop_error[ERROR_MAX];
- int pop_debug = 0;
- popserver
- pop_open (char *host, char *username, char *password, int flags)
- {
- int sock;
- popserver server;
-
- if (! username)
- {
- username = getenv ("USER");
- if (! (username && *username))
- {
- username = getlogin ();
- if (! (username && *username))
- {
- struct passwd *passwd;
- passwd = getpwuid (getuid ());
- if (passwd && passwd->pw_name && *passwd->pw_name)
- {
- username = passwd->pw_name;
- }
- else
- {
- strcpy (pop_error, "Could not determine username");
- return (0);
- }
- }
- }
- }
-
- if (! host)
- {
- host = getenv ("MAILHOST");
- }
- #ifdef HESIOD
- if ((! host) && (! (flags & POP_NO_HESIOD)))
- {
- struct hes_postoffice *office;
- office = hes_getmailhost (username);
- if (office && office->po_type && (! strcmp (office->po_type, "POP"))
- && office->po_name && *office->po_name && office->po_host
- && *office->po_host)
- {
- host = office->po_host;
- username = office->po_name;
- }
- }
- #endif
- #ifdef MAILHOST
- if (! host)
- {
- host = MAILHOST;
- }
- #endif
- if (! host)
- {
- strcpy (pop_error, "Could not determine POP server");
- return (0);
- }
-
- #ifdef KERBEROS
- #define DONT_NEED_PASSWORD (! (flags & POP_NO_KERBEROS))
- #else
- #define DONT_NEED_PASSWORD 0
- #endif
- if ((! password) && (! DONT_NEED_PASSWORD))
- {
- if (! (flags & POP_NO_GETPASS))
- {
- password = getpass ("Enter POP password:");
- }
- if (! password)
- {
- strcpy (pop_error, "Could not determine POP password");
- return (0);
- }
- }
- if (password)
- flags |= POP_NO_KERBEROS;
- else
- password = username;
-
- sock = socket_connection (host, flags);
- if (sock == -1)
- return (0);
- server = (popserver) malloc (sizeof (struct _popserver));
- if (! server)
- {
- strcpy (pop_error, "Out of memory in pop_open");
- return (0);
- }
- server->buffer = (char *) malloc (GETLINE_MIN);
- if (! server->buffer)
- {
- strcpy (pop_error, "Out of memory in pop_open");
- free ((char *) server);
- return (0);
- }
- server->file = sock;
- server->data = 0;
- server->buffer_index = 0;
- server->buffer_size = GETLINE_MIN;
- server->in_multi = 0;
- server->trash_started = 0;
- if (getok (server))
- return (0);
-
- if (strlen (username) > ERROR_MAX - 6)
- {
- pop_close (server);
- strcpy (pop_error,
- "Username too long; recompile pop.c with larger ERROR_MAX");
- return (0);
- }
- sprintf (pop_error, "USER %s", username);
- if (sendline (server, pop_error) || getok (server))
- {
- return (0);
- }
- if (strlen (password) > ERROR_MAX - 6)
- {
- pop_close (server);
- strcpy (pop_error,
- "Password too long; recompile pop.c with larger ERROR_MAX");
- return (0);
- }
- sprintf (pop_error, "PASS %s", password);
- if (sendline (server, pop_error) || getok (server))
- {
- return (0);
- }
- return (server);
- }
- int
- pop_stat (popserver server, int *count, int *size)
- {
- char *fromserver;
- char *end_ptr;
- if (server->in_multi)
- {
- strcpy (pop_error, "In multi-line query in pop_stat");
- return (-1);
- }
- if (sendline (server, "STAT") || (pop_getline (server, &fromserver) < 0))
- return (-1);
- if (strncmp (fromserver, "+OK ", 4))
- {
- if (0 == strncmp (fromserver, "-ERR", 4))
- {
- strncpy (pop_error, fromserver, ERROR_MAX);
- pop_error[ERROR_MAX-1] = '\0';
- }
- else
- {
- strcpy (pop_error,
- "Unexpected response from POP server in pop_stat");
- pop_trash (server);
- }
- return (-1);
- }
- errno = 0;
- *count = strtol (&fromserver[4], &end_ptr, 10);
-
- if (fromserver + 4 == end_ptr || *end_ptr != ' ' || errno)
- {
- strcpy (pop_error, "Unexpected response from POP server in pop_stat");
- pop_trash (server);
- return (-1);
- }
- fromserver = end_ptr;
- errno = 0;
- *size = strtol (fromserver + 1, &end_ptr, 10);
- if (fromserver + 1 == end_ptr || errno)
- {
- strcpy (pop_error, "Unexpected response from POP server in pop_stat");
- pop_trash (server);
- return (-1);
- }
- return (0);
- }
- int
- pop_list (popserver server, int message, int **IDs, int **sizes)
- {
- int how_many, i;
- char *fromserver;
- if (server->in_multi)
- {
- strcpy (pop_error, "In multi-line query in pop_list");
- return (-1);
- }
- if (message)
- how_many = 1;
- else
- {
- int count, size;
- if (pop_stat (server, &count, &size))
- return (-1);
- how_many = count;
- }
- *IDs = (int *) malloc ((how_many + 1) * sizeof (int));
- *sizes = (int *) malloc ((how_many + 1) * sizeof (int));
- if (! (*IDs && *sizes))
- {
- strcpy (pop_error, "Out of memory in pop_list");
- return (-1);
- }
- if (message)
- {
- sprintf (pop_error, "LIST %d", message);
- if (sendline (server, pop_error))
- {
- free ((char *) *IDs);
- free ((char *) *sizes);
- return (-1);
- }
- if (pop_getline (server, &fromserver) < 0)
- {
- free ((char *) *IDs);
- free ((char *) *sizes);
- return (-1);
- }
- if (strncmp (fromserver, "+OK ", 4))
- {
- if (! strncmp (fromserver, "-ERR", 4))
- {
- strncpy (pop_error, fromserver, ERROR_MAX);
- pop_error[ERROR_MAX-1] = '\0';
- }
- else
- {
- strcpy (pop_error,
- "Unexpected response from server in pop_list");
- pop_trash (server);
- }
- free ((char *) *IDs);
- free ((char *) *sizes);
- return (-1);
- }
- (*IDs)[0] = atoi (&fromserver[4]);
- fromserver = strchr (&fromserver[4], ' ');
- if (! fromserver)
- {
- strcpy (pop_error,
- "Badly formatted response from server in pop_list");
- pop_trash (server);
- free ((char *) *IDs);
- free ((char *) *sizes);
- return (-1);
- }
- (*sizes)[0] = atoi (fromserver);
- (*IDs)[1] = (*sizes)[1] = 0;
- return (0);
- }
- else
- {
- if (pop_multi_first (server, "LIST", &fromserver))
- {
- free ((char *) *IDs);
- free ((char *) *sizes);
- return (-1);
- }
- for (i = 0; i < how_many; i++)
- {
- if (pop_multi_next (server, &fromserver) <= 0)
- {
- free ((char *) *IDs);
- free ((char *) *sizes);
- return (-1);
- }
- (*IDs)[i] = atoi (fromserver);
- fromserver = strchr (fromserver, ' ');
- if (! fromserver)
- {
- strcpy (pop_error,
- "Badly formatted response from server in pop_list");
- free ((char *) *IDs);
- free ((char *) *sizes);
- pop_trash (server);
- return (-1);
- }
- (*sizes)[i] = atoi (fromserver);
- }
- if (pop_multi_next (server, &fromserver) < 0)
- {
- free ((char *) *IDs);
- free ((char *) *sizes);
- return (-1);
- }
- else if (fromserver)
- {
- strcpy (pop_error,
- "Too many response lines from server in pop_list");
- free ((char *) *IDs);
- free ((char *) *sizes);
- return (-1);
- }
- (*IDs)[i] = (*sizes)[i] = 0;
- return (0);
- }
- }
- int
- pop_retrieve (popserver server, int message, int markfrom, char **msg_buf)
- {
- int *IDs, *sizes, bufsize, fromcount = 0, cp = 0;
- char *ptr, *fromserver;
- int ret;
- if (server->in_multi)
- {
- strcpy (pop_error, "In multi-line query in pop_retrieve");
- return (-1);
- }
- if (pop_list (server, message, &IDs, &sizes))
- return (-1);
- if (pop_retrieve_first (server, message, &fromserver))
- {
- return (-1);
- }
-
- bufsize = sizes[0] + (markfrom ? 5 : 0);
- ptr = (char *)malloc (bufsize);
- free ((char *) IDs);
- free ((char *) sizes);
- if (! ptr)
- {
- strcpy (pop_error, "Out of memory in pop_retrieve");
- pop_retrieve_flush (server);
- return (-1);
- }
- while ((ret = pop_retrieve_next (server, &fromserver)) >= 0)
- {
- if (! fromserver)
- {
- ptr[cp] = '\0';
- *msg_buf = ptr;
- return (cp);
- }
- if (markfrom && fromserver[0] == 'F' && fromserver[1] == 'r' &&
- fromserver[2] == 'o' && fromserver[3] == 'm' &&
- fromserver[4] == ' ')
- {
- if (++fromcount == 5)
- {
- bufsize += 5;
- ptr = (char *)realloc (ptr, bufsize);
- if (! ptr)
- {
- strcpy (pop_error, "Out of memory in pop_retrieve");
- pop_retrieve_flush (server);
- return (-1);
- }
- fromcount = 0;
- }
- ptr[cp++] = '>';
- }
- memcpy (&ptr[cp], fromserver, ret);
- cp += ret;
- ptr[cp++] = '\n';
- }
- free (ptr);
- return (-1);
- }
- int
- pop_retrieve_first (popserver server, int message, char **response)
- {
- sprintf (pop_error, "RETR %d", message);
- return (pop_multi_first (server, pop_error, response));
- }
- int
- pop_retrieve_next (popserver server, char **line)
- {
- return (pop_multi_next (server, line));
- }
- int
- pop_retrieve_flush (popserver server)
- {
- return (pop_multi_flush (server));
- }
- int
- pop_top_first (popserver server, int message, int lines, char **response)
- {
- sprintf (pop_error, "TOP %d %d", message, lines);
- return (pop_multi_first (server, pop_error, response));
- }
- int
- pop_top_next (popserver server, char **line)
- {
- return (pop_multi_next (server, line));
- }
- int
- pop_top_flush (popserver server)
- {
- return (pop_multi_flush (server));
- }
- int
- pop_multi_first (popserver server, const char *command, char **response)
- {
- if (server->in_multi)
- {
- strcpy (pop_error,
- "Already in multi-line query in pop_multi_first");
- return (-1);
- }
- if (sendline (server, command) || (pop_getline (server, response) < 0))
- {
- return (-1);
- }
- if (0 == strncmp (*response, "-ERR", 4))
- {
- strncpy (pop_error, *response, ERROR_MAX);
- pop_error[ERROR_MAX-1] = '\0';
- return (-1);
- }
- else if (0 == strncmp (*response, "+OK", 3))
- {
- for (*response += 3; **response == ' '; (*response)++) ;
- server->in_multi = 1;
- return (0);
- }
- else
- {
- strcpy (pop_error,
- "Unexpected response from server in pop_multi_first");
- return (-1);
- }
- }
- int
- pop_multi_next (popserver server, char **line)
- {
- char *fromserver;
- int ret;
- if (! server->in_multi)
- {
- strcpy (pop_error, "Not in multi-line query in pop_multi_next");
- return (-1);
- }
- if ((ret = pop_getline (server, &fromserver)) < 0)
- {
- return (-1);
- }
- if (fromserver[0] == '.')
- {
- if (! fromserver[1])
- {
- *line = 0;
- server->in_multi = 0;
- return (0);
- }
- else
- {
- *line = fromserver + 1;
- return (ret - 1);
- }
- }
- else
- {
- *line = fromserver;
- return (ret);
- }
- }
- int
- pop_multi_flush (popserver server)
- {
- char *line;
- int ret;
- if (! server->in_multi)
- {
- return (0);
- }
- while ((ret = pop_multi_next (server, &line)))
- {
- if (ret < 0)
- return (-1);
- }
- return (0);
- }
- int
- pop_delete (popserver server, int message)
- {
- if (server->in_multi)
- {
- strcpy (pop_error, "In multi-line query in pop_delete");
- return (-1);
- }
- sprintf (pop_error, "DELE %d", message);
- if (sendline (server, pop_error) || getok (server))
- return (-1);
- return (0);
- }
- int
- pop_noop (popserver server)
- {
- if (server->in_multi)
- {
- strcpy (pop_error, "In multi-line query in pop_noop");
- return (-1);
- }
- if (sendline (server, "NOOP") || getok (server))
- return (-1);
- return (0);
- }
- int
- pop_last (popserver server)
- {
- char *fromserver;
- if (server->in_multi)
- {
- strcpy (pop_error, "In multi-line query in pop_last");
- return (-1);
- }
- if (sendline (server, "LAST"))
- return (-1);
- if (pop_getline (server, &fromserver) < 0)
- return (-1);
- if (! strncmp (fromserver, "-ERR", 4))
- {
- strncpy (pop_error, fromserver, ERROR_MAX);
- pop_error[ERROR_MAX-1] = '\0';
- return (-1);
- }
- else if (strncmp (fromserver, "+OK ", 4))
- {
- strcpy (pop_error, "Unexpected response from server in pop_last");
- pop_trash (server);
- return (-1);
- }
- else
- {
- char *end_ptr;
- int count;
- errno = 0;
- count = strtol (&fromserver[4], &end_ptr, 10);
- if (fromserver + 4 == end_ptr || errno)
- {
- strcpy (pop_error, "Unexpected response from server in pop_last");
- pop_trash (server);
- return (-1);
- }
- return count;
- }
- }
- int
- pop_reset (popserver server)
- {
- if (pop_retrieve_flush (server))
- {
- return (-1);
- }
- if (sendline (server, "RSET") || getok (server))
- return (-1);
- return (0);
- }
- int
- pop_quit (popserver server)
- {
- int ret = 0;
- if (server->file >= 0)
- {
- if (pop_retrieve_flush (server))
- {
- ret = -1;
- }
- if (sendline (server, "QUIT") || getok (server))
- {
- ret = -1;
- }
- close (server->file);
- }
- free (server->buffer);
- free ((char *) server);
- return (ret);
- }
- #ifdef WINDOWSNT
- static int have_winsock = 0;
- #endif
- static int
- socket_connection (char *host, int flags)
- {
- #ifdef HAVE_GETADDRINFO
- struct addrinfo *res, *it;
- struct addrinfo hints;
- int ret;
- #else
- struct hostent *hostent;
- #endif
- struct servent *servent;
- struct sockaddr_in addr;
- char found_port = 0;
- const char *service;
- int sock;
- char *realhost;
- #ifdef KERBEROS
- #ifdef KERBEROS5
- krb5_error_code rem;
- krb5_context kcontext = 0;
- krb5_auth_context auth_context = 0;
- krb5_ccache ccdef;
- krb5_principal client, server;
- krb5_error *err_ret;
- register char *cp;
- #else
- KTEXT ticket;
- MSG_DAT msg_data;
- CREDENTIALS cred;
- Key_schedule schedule;
- int rem;
- #endif
- #endif
- int try_count = 0;
- int connect_ok;
- #ifdef WINDOWSNT
- {
- WSADATA winsockData;
- if (WSAStartup (0x101, &winsockData) == 0)
- have_winsock = 1;
- }
- #endif
- memset (&addr, 0, sizeof (addr));
- addr.sin_family = AF_INET;
-
- #ifdef KERBEROS
- service = (flags & POP_NO_KERBEROS) ? POP_SERVICE : KPOP_SERVICE;
- #else
- service = POP_SERVICE;
- #endif
- #ifdef HESIOD
- if (! (flags & POP_NO_HESIOD))
- {
- servent = hes_getservbyname (service, "tcp");
- if (servent)
- {
- addr.sin_port = servent->s_port;
- found_port = 1;
- }
- }
- #endif
- if (! found_port)
- {
- servent = getservbyname (service, "tcp");
- if (servent)
- {
- addr.sin_port = servent->s_port;
- }
- else
- {
-
- #ifdef KERBEROS
- addr.sin_port = htons ((flags & POP_NO_KERBEROS) ?
- POP_PORT : KPOP_PORT);
- #else
- addr.sin_port = htons (POP_PORT);
- #endif
- }
- }
- #define POP_SOCKET_ERROR "Could not create socket for POP connection: "
- sock = socket (PF_INET, SOCK_STREAM, 0);
- if (sock < 0)
- {
- strcpy (pop_error, POP_SOCKET_ERROR);
- strncat (pop_error, strerror (errno),
- ERROR_MAX - sizeof (POP_SOCKET_ERROR));
- return (-1);
- }
- #ifdef HAVE_GETADDRINFO
- memset (&hints, 0, sizeof (hints));
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_CANONNAME;
- hints.ai_family = AF_INET;
- do
- {
- ret = getaddrinfo (host, service, &hints, &res);
- try_count++;
- if (ret != 0 && (ret != EAI_AGAIN || try_count == 5))
- {
- strcpy (pop_error, "Could not determine POP server's address");
- return (-1);
- }
- } while (ret != 0);
- if (ret == 0)
- {
- it = res;
- while (it)
- {
- if (it->ai_addrlen == sizeof (addr))
- {
- struct sockaddr_in *in_a = (struct sockaddr_in *) it->ai_addr;
- memcpy (&addr.sin_addr, &in_a->sin_addr, sizeof (addr.sin_addr));
- if (! connect (sock, (struct sockaddr *) &addr, sizeof (addr)))
- break;
- }
- it = it->ai_next;
- }
- connect_ok = it != NULL;
- if (connect_ok)
- {
- realhost = alloca (strlen (it->ai_canonname) + 1);
- strcpy (realhost, it->ai_canonname);
- }
- freeaddrinfo (res);
- }
- #else
- do
- {
- hostent = gethostbyname (host);
- try_count++;
- if ((! hostent) && ((h_errno != TRY_AGAIN) || (try_count == 5)))
- {
- strcpy (pop_error, "Could not determine POP server's address");
- return (-1);
- }
- } while (! hostent);
- while (*hostent->h_addr_list)
- {
- memcpy (&addr.sin_addr, *hostent->h_addr_list, hostent->h_length);
- if (! connect (sock, (struct sockaddr *) &addr, sizeof (addr)))
- break;
- hostent->h_addr_list++;
- }
- connect_ok = *hostent->h_addr_list != NULL;
- if (! connect_ok)
- {
- realhost = alloca (strlen (hostent->h_name) + 1);
- strcpy (realhost, hostent->h_name);
- }
- #endif
- #define CONNECT_ERROR "Could not connect to POP server: "
- if (! connect_ok)
- {
- CLOSESOCKET (sock);
- strcpy (pop_error, CONNECT_ERROR);
- strncat (pop_error, strerror (errno),
- ERROR_MAX - sizeof (CONNECT_ERROR));
- return (-1);
- }
- #ifdef KERBEROS
- #define KRB_ERROR "Kerberos error connecting to POP server: "
- if (! (flags & POP_NO_KERBEROS))
- {
- #ifdef KERBEROS5
- if ((rem = krb5_init_context (&kcontext)))
- {
- krb5error:
- if (auth_context)
- krb5_auth_con_free (kcontext, auth_context);
- if (kcontext)
- krb5_free_context (kcontext);
- strcpy (pop_error, KRB_ERROR);
- strncat (pop_error, error_message (rem),
- ERROR_MAX - sizeof (KRB_ERROR));
- CLOSESOCKET (sock);
- return (-1);
- }
- if ((rem = krb5_auth_con_init (kcontext, &auth_context)))
- goto krb5error;
- if (rem = krb5_cc_default (kcontext, &ccdef))
- goto krb5error;
- if (rem = krb5_cc_get_principal (kcontext, ccdef, &client))
- goto krb5error;
- for (cp = realhost; *cp; cp++)
- {
- if (isupper (*cp))
- {
- *cp = tolower (*cp);
- }
- }
- if (rem = krb5_sname_to_principal (kcontext, realhost,
- POP_SERVICE, FALSE, &server))
- goto krb5error;
- rem = krb5_sendauth (kcontext, &auth_context,
- (krb5_pointer) &sock, "KPOPV1.0", client, server,
- AP_OPTS_MUTUAL_REQUIRED,
- 0,
- 0,
- ccdef,
- &err_ret,
- 0,
- 0);
- krb5_free_principal (kcontext, server);
- if (rem)
- {
- strcpy (pop_error, KRB_ERROR);
- strncat (pop_error, error_message (rem),
- ERROR_MAX - sizeof (KRB_ERROR));
- #if defined HAVE_KRB5_ERROR_TEXT
- if (err_ret && err_ret->text.length)
- {
- strncat (pop_error, " [server says '",
- ERROR_MAX - strlen (pop_error) - 1);
- strncat (pop_error, err_ret->text.data,
- min (ERROR_MAX - strlen (pop_error) - 1,
- err_ret->text.length));
- strncat (pop_error, "']",
- ERROR_MAX - strlen (pop_error) - 1);
- }
- #elif defined HAVE_KRB5_ERROR_E_TEXT
- if (err_ret && err_ret->e_text && strlen (*err_ret->e_text))
- {
- strncat (pop_error, " [server says '",
- ERROR_MAX - strlen (pop_error) - 1);
- strncat (pop_error, *err_ret->e_text,
- ERROR_MAX - strlen (pop_error) - 1);
- strncat (pop_error, "']",
- ERROR_MAX - strlen (pop_error) - 1);
- }
- #endif
- if (err_ret)
- krb5_free_error (kcontext, err_ret);
- krb5_auth_con_free (kcontext, auth_context);
- krb5_free_context (kcontext);
- CLOSESOCKET (sock);
- return (-1);
- }
- #else
- ticket = (KTEXT) malloc (sizeof (KTEXT_ST));
- rem = krb_sendauth (0L, sock, ticket, "pop", realhost,
- (char *) krb_realmofhost (realhost),
- (unsigned long) 0, &msg_data, &cred, schedule,
- (struct sockaddr_in *) 0,
- (struct sockaddr_in *) 0,
- "KPOPV0.1");
- free ((char *) ticket);
- if (rem != KSUCCESS)
- {
- strcpy (pop_error, KRB_ERROR);
- strncat (pop_error, krb_err_txt[rem],
- ERROR_MAX - sizeof (KRB_ERROR));
- CLOSESOCKET (sock);
- return (-1);
- }
- #endif
- }
- #endif
- return (sock);
- }
- static int
- pop_getline (popserver server, char **line)
- {
- #define GETLINE_ERROR "Error reading from server: "
- int ret;
- int search_offset = 0;
- if (server->data)
- {
- char *cp = find_crlf (server->buffer + server->buffer_index,
- server->data);
- if (cp)
- {
- int found;
- int data_used;
- found = server->buffer_index;
- data_used = (cp + 2) - server->buffer - found;
- *cp = '\0';
- server->data -= data_used;
- server->buffer_index += data_used;
- if (pop_debug)
-
- fprintf (stderr, "<<< %s\n", server->buffer + found);
- *line = server->buffer + found;
- return (data_used - 2);
- }
- else
- {
- memmove (server->buffer, server->buffer + server->buffer_index,
- server->data);
-
- search_offset = server->data - 1;
- server->buffer_index = 0;
- }
- }
- else
- {
- server->buffer_index = 0;
- }
- while (1)
- {
-
- if (server->data == server->buffer_size - 1)
- {
- server->buffer_size += GETLINE_INCR;
- server->buffer = (char *)realloc (server->buffer, server->buffer_size);
- if (! server->buffer)
- {
- strcpy (pop_error, "Out of memory in pop_getline");
- pop_trash (server);
- return (-1);
- }
- }
- ret = RECV (server->file, server->buffer + server->data,
- server->buffer_size - server->data - 1, 0);
- if (ret < 0)
- {
- strcpy (pop_error, GETLINE_ERROR);
- strncat (pop_error, strerror (errno),
- ERROR_MAX - sizeof (GETLINE_ERROR));
- pop_trash (server);
- return (-1);
- }
- else if (ret == 0)
- {
- strcpy (pop_error, "Unexpected EOF from server in pop_getline");
- pop_trash (server);
- return (-1);
- }
- else
- {
- char *cp;
- server->data += ret;
- server->buffer[server->data] = '\0';
- cp = find_crlf (server->buffer + search_offset,
- server->data - search_offset);
- if (cp)
- {
- int data_used = (cp + 2) - server->buffer;
- *cp = '\0';
- server->data -= data_used;
- server->buffer_index = data_used;
- if (pop_debug)
- fprintf (stderr, "<<< %s\n", server->buffer);
- *line = server->buffer;
- return (data_used - 2);
- }
-
- search_offset += ret - 1;
- }
- }
-
- }
- static int
- sendline (popserver server, const char *line)
- {
- #define SENDLINE_ERROR "Error writing to POP server: "
- int ret;
- char *buf;
-
- buf = alloca (strlen (line) + 3);
- strcpy (buf, line);
- strcat (buf, "\r\n");
- ret = fullwrite (server->file, buf, strlen (buf));
- if (ret < 0)
- {
- pop_trash (server);
- strcpy (pop_error, SENDLINE_ERROR);
- strncat (pop_error, strerror (errno),
- ERROR_MAX - sizeof (SENDLINE_ERROR));
- return (ret);
- }
- if (pop_debug)
- fprintf (stderr, ">>> %s\n", line);
- return (0);
- }
- static int
- fullwrite (int fd, char *buf, int nbytes)
- {
- char *cp;
- int ret = 0;
- cp = buf;
- while (nbytes && ((ret = SEND (fd, cp, nbytes, 0)) > 0))
- {
- cp += ret;
- nbytes -= ret;
- }
- return (ret);
- }
- static int
- getok (popserver server)
- {
- char *fromline;
- if (pop_getline (server, &fromline) < 0)
- {
- return (-1);
- }
- if (! strncmp (fromline, "+OK", 3))
- return (0);
- else if (! strncmp (fromline, "-ERR", 4))
- {
- strncpy (pop_error, fromline, ERROR_MAX);
- pop_error[ERROR_MAX-1] = '\0';
- return (-1);
- }
- else
- {
- strcpy (pop_error,
- "Unexpected response from server; expecting +OK or -ERR");
- pop_trash (server);
- return (-1);
- }
- }
- #if 0
- static int
- gettermination (server)
- popserver server;
- {
- char *fromserver;
- if (pop_getline (server, &fromserver) < 0)
- return (-1);
- if (strcmp (fromserver, "."))
- {
- strcpy (pop_error,
- "Unexpected response from server in gettermination");
- pop_trash (server);
- return (-1);
- }
- return (0);
- }
- #endif
- void
- pop_close (popserver server)
- {
- pop_trash (server);
- free ((char *) server);
- return;
- }
- static void
- pop_trash (popserver server)
- {
- if (server->file >= 0)
- {
-
- if (server->trash_started)
- return;
- server->trash_started = 1;
- sendline (server, "RSET");
- sendline (server, "QUIT");
- CLOSESOCKET (server->file);
- server->file = -1;
- if (server->buffer)
- {
- free (server->buffer);
- server->buffer = 0;
- }
- }
- #ifdef WINDOWSNT
- if (have_winsock)
- WSACleanup ();
- #endif
- }
- static char *
- find_crlf (char *in_string, int len)
- {
- while (len--)
- {
- if (*in_string == '\r')
- {
- if (*++in_string == '\n')
- return (in_string - 1);
- }
- else
- in_string++;
- }
- return (0);
- }
- #endif
|