pop.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629
  1. /* pop.c: client routines for talking to a POP3-protocol post-office server
  2. Copyright (C) 1991, 1993, 1996-1997, 1999, 2001-2012
  3. Free Software Foundation, Inc.
  4. Author: Jonathan Kamens <jik@security.ov.com>
  5. This file is part of GNU Emacs.
  6. GNU Emacs is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. GNU Emacs is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
  16. #ifdef HAVE_CONFIG_H
  17. #include <config.h>
  18. #else
  19. #define MAIL_USE_POP
  20. #endif
  21. #ifdef MAIL_USE_POP
  22. #include <sys/types.h>
  23. #ifdef WINDOWSNT
  24. #include "ntlib.h"
  25. #include <winsock.h>
  26. #undef SOCKET_ERROR
  27. #define RECV(s,buf,len,flags) recv (s,buf,len,flags)
  28. #define SEND(s,buf,len,flags) send (s,buf,len,flags)
  29. #define CLOSESOCKET(s) closesocket (s)
  30. #else
  31. #include <netinet/in.h>
  32. #include <sys/socket.h>
  33. #define RECV(s,buf,len,flags) read (s,buf,len)
  34. #define SEND(s,buf,len,flags) write (s,buf,len)
  35. #define CLOSESOCKET(s) close (s)
  36. #endif
  37. #include <pop.h>
  38. #ifdef sun
  39. #include <malloc.h>
  40. #endif /* sun */
  41. #ifdef HESIOD
  42. #include <hesiod.h>
  43. /*
  44. * It really shouldn't be necessary to put this declaration here, but
  45. * the version of hesiod.h that Athena has installed in release 7.2
  46. * doesn't declare this function; I don't know if the 7.3 version of
  47. * hesiod.h does.
  48. */
  49. extern struct servent *hes_getservbyname (/* char *, char * */);
  50. #endif
  51. #include <pwd.h>
  52. #include <netdb.h>
  53. #include <errno.h>
  54. #include <stdio.h>
  55. #include <string.h>
  56. #include <unistd.h>
  57. #ifdef KERBEROS
  58. # ifdef HAVE_KRB5_H
  59. # include <krb5.h>
  60. # endif
  61. # ifdef HAVE_KRB_H
  62. # include <krb.h>
  63. # else
  64. # ifdef HAVE_KERBEROSIV_KRB_H
  65. # include <kerberosIV/krb.h>
  66. # else
  67. # ifdef HAVE_KERBEROS_KRB_H
  68. # include <kerberos/krb.h>
  69. # endif
  70. # endif
  71. # endif
  72. # ifdef HAVE_COM_ERR_H
  73. # include <com_err.h>
  74. # endif
  75. #endif /* KERBEROS */
  76. #include <min-max.h>
  77. #ifdef KERBEROS
  78. #ifndef KERBEROS5
  79. extern int krb_sendauth (/* long, int, KTEXT, char *, char *, char *,
  80. u_long, MSG_DAT *, CREDENTIALS *, Key_schedule,
  81. struct sockaddr_in *, struct sockaddr_in *,
  82. char * */);
  83. extern char *krb_realmofhost (/* char * */);
  84. #endif /* ! KERBEROS5 */
  85. #endif /* KERBEROS */
  86. #ifndef WINDOWSNT
  87. #if !defined (HAVE_H_ERRNO) || !defined (HAVE_CONFIG_H)
  88. extern int h_errno;
  89. #endif
  90. #endif
  91. static int socket_connection (char *, int);
  92. static int pop_getline (popserver, char **);
  93. static int sendline (popserver, const char *);
  94. static int fullwrite (int, char *, int);
  95. static int getok (popserver);
  96. #if 0
  97. static int gettermination (popserver);
  98. #endif
  99. static void pop_trash (popserver);
  100. static char *find_crlf (char *, int);
  101. #define ERROR_MAX 160 /* a pretty arbitrary size, but needs
  102. to be bigger than the original
  103. value of 80 */
  104. #define POP_PORT 110
  105. #define POP_SERVICE "pop3" /* we don't want the POP2 port! */
  106. #ifdef KERBEROS
  107. #define KPOP_PORT 1109
  108. #define KPOP_SERVICE "kpop" /* never used: look for 20060515 to see why */
  109. #endif
  110. char pop_error[ERROR_MAX];
  111. int pop_debug = 0;
  112. /*
  113. * Function: pop_open (char *host, char *username, char *password,
  114. * int flags)
  115. *
  116. * Purpose: Establishes a connection with a post-office server, and
  117. * completes the authorization portion of the session.
  118. *
  119. * Arguments:
  120. * host The server host with which the connection should be
  121. * established. Optional. If omitted, internal
  122. * heuristics will be used to determine the server host,
  123. * if possible.
  124. * username
  125. * The username of the mail-drop to access. Optional.
  126. * If omitted, internal heuristics will be used to
  127. * determine the username, if possible.
  128. * password
  129. * The password to use for authorization. If omitted,
  130. * internal heuristics will be used to determine the
  131. * password, if possible.
  132. * flags A bit mask containing flags controlling certain
  133. * functions of the routine. Valid flags are defined in
  134. * the file pop.h
  135. *
  136. * Return value: Upon successful establishment of a connection, a
  137. * non-null popserver will be returned. Otherwise, null will be
  138. * returned, and the string variable pop_error will contain an
  139. * explanation of the error.
  140. */
  141. popserver
  142. pop_open (char *host, char *username, char *password, int flags)
  143. {
  144. int sock;
  145. popserver server;
  146. /* Determine the user name */
  147. if (! username)
  148. {
  149. username = getenv ("USER");
  150. if (! (username && *username))
  151. {
  152. username = getlogin ();
  153. if (! (username && *username))
  154. {
  155. struct passwd *passwd;
  156. passwd = getpwuid (getuid ());
  157. if (passwd && passwd->pw_name && *passwd->pw_name)
  158. {
  159. username = passwd->pw_name;
  160. }
  161. else
  162. {
  163. strcpy (pop_error, "Could not determine username");
  164. return (0);
  165. }
  166. }
  167. }
  168. }
  169. /*
  170. * Determine the mail host.
  171. */
  172. if (! host)
  173. {
  174. host = getenv ("MAILHOST");
  175. }
  176. #ifdef HESIOD
  177. if ((! host) && (! (flags & POP_NO_HESIOD)))
  178. {
  179. struct hes_postoffice *office;
  180. office = hes_getmailhost (username);
  181. if (office && office->po_type && (! strcmp (office->po_type, "POP"))
  182. && office->po_name && *office->po_name && office->po_host
  183. && *office->po_host)
  184. {
  185. host = office->po_host;
  186. username = office->po_name;
  187. }
  188. }
  189. #endif
  190. #ifdef MAILHOST
  191. if (! host)
  192. {
  193. host = MAILHOST;
  194. }
  195. #endif
  196. if (! host)
  197. {
  198. strcpy (pop_error, "Could not determine POP server");
  199. return (0);
  200. }
  201. /* Determine the password */
  202. #ifdef KERBEROS
  203. #define DONT_NEED_PASSWORD (! (flags & POP_NO_KERBEROS))
  204. #else
  205. #define DONT_NEED_PASSWORD 0
  206. #endif
  207. if ((! password) && (! DONT_NEED_PASSWORD))
  208. {
  209. if (! (flags & POP_NO_GETPASS))
  210. {
  211. password = getpass ("Enter POP password:");
  212. }
  213. if (! password)
  214. {
  215. strcpy (pop_error, "Could not determine POP password");
  216. return (0);
  217. }
  218. }
  219. if (password) /* always true, detected 20060515 */
  220. flags |= POP_NO_KERBEROS;
  221. else
  222. password = username; /* dead code, detected 20060515 */
  223. /** "kpop" service is never used: look for 20060515 to see why **/
  224. sock = socket_connection (host, flags);
  225. if (sock == -1)
  226. return (0);
  227. server = (popserver) malloc (sizeof (struct _popserver));
  228. if (! server)
  229. {
  230. strcpy (pop_error, "Out of memory in pop_open");
  231. return (0);
  232. }
  233. server->buffer = (char *) malloc (GETLINE_MIN);
  234. if (! server->buffer)
  235. {
  236. strcpy (pop_error, "Out of memory in pop_open");
  237. free ((char *) server);
  238. return (0);
  239. }
  240. server->file = sock;
  241. server->data = 0;
  242. server->buffer_index = 0;
  243. server->buffer_size = GETLINE_MIN;
  244. server->in_multi = 0;
  245. server->trash_started = 0;
  246. if (getok (server))
  247. return (0);
  248. /*
  249. * I really shouldn't use the pop_error variable like this, but....
  250. */
  251. if (strlen (username) > ERROR_MAX - 6)
  252. {
  253. pop_close (server);
  254. strcpy (pop_error,
  255. "Username too long; recompile pop.c with larger ERROR_MAX");
  256. return (0);
  257. }
  258. sprintf (pop_error, "USER %s", username);
  259. if (sendline (server, pop_error) || getok (server))
  260. {
  261. return (0);
  262. }
  263. if (strlen (password) > ERROR_MAX - 6)
  264. {
  265. pop_close (server);
  266. strcpy (pop_error,
  267. "Password too long; recompile pop.c with larger ERROR_MAX");
  268. return (0);
  269. }
  270. sprintf (pop_error, "PASS %s", password);
  271. if (sendline (server, pop_error) || getok (server))
  272. {
  273. return (0);
  274. }
  275. return (server);
  276. }
  277. /*
  278. * Function: pop_stat
  279. *
  280. * Purpose: Issue the STAT command to the server and return (in the
  281. * value parameters) the number of messages in the maildrop and
  282. * the total size of the maildrop.
  283. *
  284. * Return value: 0 on success, or non-zero with an error in pop_error
  285. * in failure.
  286. *
  287. * Side effects: On failure, may make further operations on the
  288. * connection impossible.
  289. */
  290. int
  291. pop_stat (popserver server, int *count, int *size)
  292. {
  293. char *fromserver;
  294. char *end_ptr;
  295. if (server->in_multi)
  296. {
  297. strcpy (pop_error, "In multi-line query in pop_stat");
  298. return (-1);
  299. }
  300. if (sendline (server, "STAT") || (pop_getline (server, &fromserver) < 0))
  301. return (-1);
  302. if (strncmp (fromserver, "+OK ", 4))
  303. {
  304. if (0 == strncmp (fromserver, "-ERR", 4))
  305. {
  306. strncpy (pop_error, fromserver, ERROR_MAX);
  307. pop_error[ERROR_MAX-1] = '\0';
  308. }
  309. else
  310. {
  311. strcpy (pop_error,
  312. "Unexpected response from POP server in pop_stat");
  313. pop_trash (server);
  314. }
  315. return (-1);
  316. }
  317. errno = 0;
  318. *count = strtol (&fromserver[4], &end_ptr, 10);
  319. /* Check validity of string-to-integer conversion. */
  320. if (fromserver + 4 == end_ptr || *end_ptr != ' ' || errno)
  321. {
  322. strcpy (pop_error, "Unexpected response from POP server in pop_stat");
  323. pop_trash (server);
  324. return (-1);
  325. }
  326. fromserver = end_ptr;
  327. errno = 0;
  328. *size = strtol (fromserver + 1, &end_ptr, 10);
  329. if (fromserver + 1 == end_ptr || errno)
  330. {
  331. strcpy (pop_error, "Unexpected response from POP server in pop_stat");
  332. pop_trash (server);
  333. return (-1);
  334. }
  335. return (0);
  336. }
  337. /*
  338. * Function: pop_list
  339. *
  340. * Purpose: Performs the POP "list" command and returns (in value
  341. * parameters) two malloc'd zero-terminated arrays -- one of
  342. * message IDs, and a parallel one of sizes.
  343. *
  344. * Arguments:
  345. * server The pop connection to talk to.
  346. * message The number of the one message about which to get
  347. * information, or 0 to get information about all
  348. * messages.
  349. *
  350. * Return value: 0 on success, non-zero with error in pop_error on
  351. * failure.
  352. *
  353. * Side effects: On failure, may make further operations on the
  354. * connection impossible.
  355. */
  356. int
  357. pop_list (popserver server, int message, int **IDs, int **sizes)
  358. {
  359. int how_many, i;
  360. char *fromserver;
  361. if (server->in_multi)
  362. {
  363. strcpy (pop_error, "In multi-line query in pop_list");
  364. return (-1);
  365. }
  366. if (message)
  367. how_many = 1;
  368. else
  369. {
  370. int count, size;
  371. if (pop_stat (server, &count, &size))
  372. return (-1);
  373. how_many = count;
  374. }
  375. *IDs = (int *) malloc ((how_many + 1) * sizeof (int));
  376. *sizes = (int *) malloc ((how_many + 1) * sizeof (int));
  377. if (! (*IDs && *sizes))
  378. {
  379. strcpy (pop_error, "Out of memory in pop_list");
  380. return (-1);
  381. }
  382. if (message)
  383. {
  384. sprintf (pop_error, "LIST %d", message);
  385. if (sendline (server, pop_error))
  386. {
  387. free ((char *) *IDs);
  388. free ((char *) *sizes);
  389. return (-1);
  390. }
  391. if (pop_getline (server, &fromserver) < 0)
  392. {
  393. free ((char *) *IDs);
  394. free ((char *) *sizes);
  395. return (-1);
  396. }
  397. if (strncmp (fromserver, "+OK ", 4))
  398. {
  399. if (! strncmp (fromserver, "-ERR", 4))
  400. {
  401. strncpy (pop_error, fromserver, ERROR_MAX);
  402. pop_error[ERROR_MAX-1] = '\0';
  403. }
  404. else
  405. {
  406. strcpy (pop_error,
  407. "Unexpected response from server in pop_list");
  408. pop_trash (server);
  409. }
  410. free ((char *) *IDs);
  411. free ((char *) *sizes);
  412. return (-1);
  413. }
  414. (*IDs)[0] = atoi (&fromserver[4]);
  415. fromserver = strchr (&fromserver[4], ' ');
  416. if (! fromserver)
  417. {
  418. strcpy (pop_error,
  419. "Badly formatted response from server in pop_list");
  420. pop_trash (server);
  421. free ((char *) *IDs);
  422. free ((char *) *sizes);
  423. return (-1);
  424. }
  425. (*sizes)[0] = atoi (fromserver);
  426. (*IDs)[1] = (*sizes)[1] = 0;
  427. return (0);
  428. }
  429. else
  430. {
  431. if (pop_multi_first (server, "LIST", &fromserver))
  432. {
  433. free ((char *) *IDs);
  434. free ((char *) *sizes);
  435. return (-1);
  436. }
  437. for (i = 0; i < how_many; i++)
  438. {
  439. if (pop_multi_next (server, &fromserver) <= 0)
  440. {
  441. free ((char *) *IDs);
  442. free ((char *) *sizes);
  443. return (-1);
  444. }
  445. (*IDs)[i] = atoi (fromserver);
  446. fromserver = strchr (fromserver, ' ');
  447. if (! fromserver)
  448. {
  449. strcpy (pop_error,
  450. "Badly formatted response from server in pop_list");
  451. free ((char *) *IDs);
  452. free ((char *) *sizes);
  453. pop_trash (server);
  454. return (-1);
  455. }
  456. (*sizes)[i] = atoi (fromserver);
  457. }
  458. if (pop_multi_next (server, &fromserver) < 0)
  459. {
  460. free ((char *) *IDs);
  461. free ((char *) *sizes);
  462. return (-1);
  463. }
  464. else if (fromserver)
  465. {
  466. strcpy (pop_error,
  467. "Too many response lines from server in pop_list");
  468. free ((char *) *IDs);
  469. free ((char *) *sizes);
  470. return (-1);
  471. }
  472. (*IDs)[i] = (*sizes)[i] = 0;
  473. return (0);
  474. }
  475. }
  476. /*
  477. * Function: pop_retrieve
  478. *
  479. * Purpose: Retrieve a specified message from the maildrop.
  480. *
  481. * Arguments:
  482. * server The server to retrieve from.
  483. * message The message number to retrieve.
  484. * markfrom
  485. * If true, then mark the string "From " at the beginning
  486. * of lines with '>'.
  487. * msg_buf Output parameter to which a buffer containing the
  488. * message is assigned.
  489. *
  490. * Return value: The number of bytes in msg_buf, which may contain
  491. * embedded nulls, not including its final null, or -1 on error
  492. * with pop_error set.
  493. *
  494. * Side effects: May kill connection on error.
  495. */
  496. int
  497. pop_retrieve (popserver server, int message, int markfrom, char **msg_buf)
  498. {
  499. int *IDs, *sizes, bufsize, fromcount = 0, cp = 0;
  500. char *ptr, *fromserver;
  501. int ret;
  502. if (server->in_multi)
  503. {
  504. strcpy (pop_error, "In multi-line query in pop_retrieve");
  505. return (-1);
  506. }
  507. if (pop_list (server, message, &IDs, &sizes))
  508. return (-1);
  509. if (pop_retrieve_first (server, message, &fromserver))
  510. {
  511. return (-1);
  512. }
  513. /*
  514. * The "5" below is an arbitrary constant -- I assume that if
  515. * there are "From" lines in the text to be marked, there
  516. * probably won't be more than 5 of them. If there are, I
  517. * allocate more space for them below.
  518. */
  519. bufsize = sizes[0] + (markfrom ? 5 : 0);
  520. ptr = (char *)malloc (bufsize);
  521. free ((char *) IDs);
  522. free ((char *) sizes);
  523. if (! ptr)
  524. {
  525. strcpy (pop_error, "Out of memory in pop_retrieve");
  526. pop_retrieve_flush (server);
  527. return (-1);
  528. }
  529. while ((ret = pop_retrieve_next (server, &fromserver)) >= 0)
  530. {
  531. if (! fromserver)
  532. {
  533. ptr[cp] = '\0';
  534. *msg_buf = ptr;
  535. return (cp);
  536. }
  537. if (markfrom && fromserver[0] == 'F' && fromserver[1] == 'r' &&
  538. fromserver[2] == 'o' && fromserver[3] == 'm' &&
  539. fromserver[4] == ' ')
  540. {
  541. if (++fromcount == 5)
  542. {
  543. bufsize += 5;
  544. ptr = (char *)realloc (ptr, bufsize);
  545. if (! ptr)
  546. {
  547. strcpy (pop_error, "Out of memory in pop_retrieve");
  548. pop_retrieve_flush (server);
  549. return (-1);
  550. }
  551. fromcount = 0;
  552. }
  553. ptr[cp++] = '>';
  554. }
  555. memcpy (&ptr[cp], fromserver, ret);
  556. cp += ret;
  557. ptr[cp++] = '\n';
  558. }
  559. free (ptr);
  560. return (-1);
  561. }
  562. int
  563. pop_retrieve_first (popserver server, int message, char **response)
  564. {
  565. sprintf (pop_error, "RETR %d", message);
  566. return (pop_multi_first (server, pop_error, response));
  567. }
  568. /*
  569. Returns a negative number on error, 0 to indicate that the data has
  570. all been read (i.e., the server has returned a "." termination
  571. line), or a positive number indicating the number of bytes in the
  572. returned buffer (which is null-terminated and may contain embedded
  573. nulls, but the returned bytecount doesn't include the final null).
  574. */
  575. int
  576. pop_retrieve_next (popserver server, char **line)
  577. {
  578. return (pop_multi_next (server, line));
  579. }
  580. int
  581. pop_retrieve_flush (popserver server)
  582. {
  583. return (pop_multi_flush (server));
  584. }
  585. int
  586. pop_top_first (popserver server, int message, int lines, char **response)
  587. {
  588. sprintf (pop_error, "TOP %d %d", message, lines);
  589. return (pop_multi_first (server, pop_error, response));
  590. }
  591. /*
  592. Returns a negative number on error, 0 to indicate that the data has
  593. all been read (i.e., the server has returned a "." termination
  594. line), or a positive number indicating the number of bytes in the
  595. returned buffer (which is null-terminated and may contain embedded
  596. nulls, but the returned bytecount doesn't include the final null).
  597. */
  598. int
  599. pop_top_next (popserver server, char **line)
  600. {
  601. return (pop_multi_next (server, line));
  602. }
  603. int
  604. pop_top_flush (popserver server)
  605. {
  606. return (pop_multi_flush (server));
  607. }
  608. int
  609. pop_multi_first (popserver server, const char *command, char **response)
  610. {
  611. if (server->in_multi)
  612. {
  613. strcpy (pop_error,
  614. "Already in multi-line query in pop_multi_first");
  615. return (-1);
  616. }
  617. if (sendline (server, command) || (pop_getline (server, response) < 0))
  618. {
  619. return (-1);
  620. }
  621. if (0 == strncmp (*response, "-ERR", 4))
  622. {
  623. strncpy (pop_error, *response, ERROR_MAX);
  624. pop_error[ERROR_MAX-1] = '\0';
  625. return (-1);
  626. }
  627. else if (0 == strncmp (*response, "+OK", 3))
  628. {
  629. for (*response += 3; **response == ' '; (*response)++) /* empty */;
  630. server->in_multi = 1;
  631. return (0);
  632. }
  633. else
  634. {
  635. strcpy (pop_error,
  636. "Unexpected response from server in pop_multi_first");
  637. return (-1);
  638. }
  639. }
  640. /*
  641. Read the next line of data from SERVER and place a pointer to it
  642. into LINE. Return -1 on error, 0 if there are no more lines to read
  643. (i.e., the server has returned a line containing only "."), or a
  644. positive number indicating the number of bytes in the LINE buffer
  645. (not including the final null). The data in that buffer may contain
  646. embedded nulls, but does not contain the final CRLF. When returning
  647. 0, LINE is set to null. */
  648. int
  649. pop_multi_next (popserver server, char **line)
  650. {
  651. char *fromserver;
  652. int ret;
  653. if (! server->in_multi)
  654. {
  655. strcpy (pop_error, "Not in multi-line query in pop_multi_next");
  656. return (-1);
  657. }
  658. if ((ret = pop_getline (server, &fromserver)) < 0)
  659. {
  660. return (-1);
  661. }
  662. if (fromserver[0] == '.')
  663. {
  664. if (! fromserver[1])
  665. {
  666. *line = 0;
  667. server->in_multi = 0;
  668. return (0);
  669. }
  670. else
  671. {
  672. *line = fromserver + 1;
  673. return (ret - 1);
  674. }
  675. }
  676. else
  677. {
  678. *line = fromserver;
  679. return (ret);
  680. }
  681. }
  682. int
  683. pop_multi_flush (popserver server)
  684. {
  685. char *line;
  686. int ret;
  687. if (! server->in_multi)
  688. {
  689. return (0);
  690. }
  691. while ((ret = pop_multi_next (server, &line)))
  692. {
  693. if (ret < 0)
  694. return (-1);
  695. }
  696. return (0);
  697. }
  698. /* Function: pop_delete
  699. *
  700. * Purpose: Delete a specified message.
  701. *
  702. * Arguments:
  703. * server Server from which to delete the message.
  704. * message Message to delete.
  705. *
  706. * Return value: 0 on success, non-zero with error in pop_error
  707. * otherwise.
  708. */
  709. int
  710. pop_delete (popserver server, int message)
  711. {
  712. if (server->in_multi)
  713. {
  714. strcpy (pop_error, "In multi-line query in pop_delete");
  715. return (-1);
  716. }
  717. sprintf (pop_error, "DELE %d", message);
  718. if (sendline (server, pop_error) || getok (server))
  719. return (-1);
  720. return (0);
  721. }
  722. /*
  723. * Function: pop_noop
  724. *
  725. * Purpose: Send a noop command to the server.
  726. *
  727. * Argument:
  728. * server The server to send to.
  729. *
  730. * Return value: 0 on success, non-zero with error in pop_error
  731. * otherwise.
  732. *
  733. * Side effects: Closes connection on error.
  734. */
  735. int
  736. pop_noop (popserver server)
  737. {
  738. if (server->in_multi)
  739. {
  740. strcpy (pop_error, "In multi-line query in pop_noop");
  741. return (-1);
  742. }
  743. if (sendline (server, "NOOP") || getok (server))
  744. return (-1);
  745. return (0);
  746. }
  747. /*
  748. * Function: pop_last
  749. *
  750. * Purpose: Find out the highest seen message from the server.
  751. *
  752. * Arguments:
  753. * server The server.
  754. *
  755. * Return value: If successful, the highest seen message, which is
  756. * greater than or equal to 0. Otherwise, a negative number with
  757. * the error explained in pop_error.
  758. *
  759. * Side effects: Closes the connection on error.
  760. */
  761. int
  762. pop_last (popserver server)
  763. {
  764. char *fromserver;
  765. if (server->in_multi)
  766. {
  767. strcpy (pop_error, "In multi-line query in pop_last");
  768. return (-1);
  769. }
  770. if (sendline (server, "LAST"))
  771. return (-1);
  772. if (pop_getline (server, &fromserver) < 0)
  773. return (-1);
  774. if (! strncmp (fromserver, "-ERR", 4))
  775. {
  776. strncpy (pop_error, fromserver, ERROR_MAX);
  777. pop_error[ERROR_MAX-1] = '\0';
  778. return (-1);
  779. }
  780. else if (strncmp (fromserver, "+OK ", 4))
  781. {
  782. strcpy (pop_error, "Unexpected response from server in pop_last");
  783. pop_trash (server);
  784. return (-1);
  785. }
  786. else
  787. {
  788. char *end_ptr;
  789. int count;
  790. errno = 0;
  791. count = strtol (&fromserver[4], &end_ptr, 10);
  792. if (fromserver + 4 == end_ptr || errno)
  793. {
  794. strcpy (pop_error, "Unexpected response from server in pop_last");
  795. pop_trash (server);
  796. return (-1);
  797. }
  798. return count;
  799. }
  800. }
  801. /*
  802. * Function: pop_reset
  803. *
  804. * Purpose: Reset the server to its initial connect state
  805. *
  806. * Arguments:
  807. * server The server.
  808. *
  809. * Return value: 0 for success, non-0 with error in pop_error
  810. * otherwise.
  811. *
  812. * Side effects: Closes the connection on error.
  813. */
  814. int
  815. pop_reset (popserver server)
  816. {
  817. if (pop_retrieve_flush (server))
  818. {
  819. return (-1);
  820. }
  821. if (sendline (server, "RSET") || getok (server))
  822. return (-1);
  823. return (0);
  824. }
  825. /*
  826. * Function: pop_quit
  827. *
  828. * Purpose: Quit the connection to the server,
  829. *
  830. * Arguments:
  831. * server The server to quit.
  832. *
  833. * Return value: 0 for success, non-zero otherwise with error in
  834. * pop_error.
  835. *
  836. * Side Effects: The popserver passed in is unusable after this
  837. * function is called, even if an error occurs.
  838. */
  839. int
  840. pop_quit (popserver server)
  841. {
  842. int ret = 0;
  843. if (server->file >= 0)
  844. {
  845. if (pop_retrieve_flush (server))
  846. {
  847. ret = -1;
  848. }
  849. if (sendline (server, "QUIT") || getok (server))
  850. {
  851. ret = -1;
  852. }
  853. close (server->file);
  854. }
  855. free (server->buffer);
  856. free ((char *) server);
  857. return (ret);
  858. }
  859. #ifdef WINDOWSNT
  860. static int have_winsock = 0;
  861. #endif
  862. /*
  863. * Function: socket_connection
  864. *
  865. * Purpose: Opens the network connection with the mail host, without
  866. * doing any sort of I/O with it or anything.
  867. *
  868. * Arguments:
  869. * host The host to which to connect.
  870. * flags Option flags.
  871. *
  872. * Return value: A file descriptor indicating the connection, or -1
  873. * indicating failure, in which case an error has been copied
  874. * into pop_error.
  875. */
  876. static int
  877. socket_connection (char *host, int flags)
  878. {
  879. #ifdef HAVE_GETADDRINFO
  880. struct addrinfo *res, *it;
  881. struct addrinfo hints;
  882. int ret;
  883. #else /* !HAVE_GETADDRINFO */
  884. struct hostent *hostent;
  885. #endif
  886. struct servent *servent;
  887. struct sockaddr_in addr;
  888. char found_port = 0;
  889. const char *service;
  890. int sock;
  891. char *realhost;
  892. #ifdef KERBEROS
  893. #ifdef KERBEROS5
  894. krb5_error_code rem;
  895. krb5_context kcontext = 0;
  896. krb5_auth_context auth_context = 0;
  897. krb5_ccache ccdef;
  898. krb5_principal client, server;
  899. krb5_error *err_ret;
  900. register char *cp;
  901. #else
  902. KTEXT ticket;
  903. MSG_DAT msg_data;
  904. CREDENTIALS cred;
  905. Key_schedule schedule;
  906. int rem;
  907. #endif /* KERBEROS5 */
  908. #endif /* KERBEROS */
  909. int try_count = 0;
  910. int connect_ok;
  911. #ifdef WINDOWSNT
  912. {
  913. WSADATA winsockData;
  914. if (WSAStartup (0x101, &winsockData) == 0)
  915. have_winsock = 1;
  916. }
  917. #endif
  918. memset (&addr, 0, sizeof (addr));
  919. addr.sin_family = AF_INET;
  920. /** "kpop" service is never used: look for 20060515 to see why **/
  921. #ifdef KERBEROS
  922. service = (flags & POP_NO_KERBEROS) ? POP_SERVICE : KPOP_SERVICE;
  923. #else
  924. service = POP_SERVICE;
  925. #endif
  926. #ifdef HESIOD
  927. if (! (flags & POP_NO_HESIOD))
  928. {
  929. servent = hes_getservbyname (service, "tcp");
  930. if (servent)
  931. {
  932. addr.sin_port = servent->s_port;
  933. found_port = 1;
  934. }
  935. }
  936. #endif
  937. if (! found_port)
  938. {
  939. servent = getservbyname (service, "tcp");
  940. if (servent)
  941. {
  942. addr.sin_port = servent->s_port;
  943. }
  944. else
  945. {
  946. /** "kpop" service is never used: look for 20060515 to see why **/
  947. #ifdef KERBEROS
  948. addr.sin_port = htons ((flags & POP_NO_KERBEROS) ?
  949. POP_PORT : KPOP_PORT);
  950. #else
  951. addr.sin_port = htons (POP_PORT);
  952. #endif
  953. }
  954. }
  955. #define POP_SOCKET_ERROR "Could not create socket for POP connection: "
  956. sock = socket (PF_INET, SOCK_STREAM, 0);
  957. if (sock < 0)
  958. {
  959. strcpy (pop_error, POP_SOCKET_ERROR);
  960. strncat (pop_error, strerror (errno),
  961. ERROR_MAX - sizeof (POP_SOCKET_ERROR));
  962. return (-1);
  963. }
  964. #ifdef HAVE_GETADDRINFO
  965. memset (&hints, 0, sizeof (hints));
  966. hints.ai_socktype = SOCK_STREAM;
  967. hints.ai_flags = AI_CANONNAME;
  968. hints.ai_family = AF_INET;
  969. do
  970. {
  971. ret = getaddrinfo (host, service, &hints, &res);
  972. try_count++;
  973. if (ret != 0 && (ret != EAI_AGAIN || try_count == 5))
  974. {
  975. strcpy (pop_error, "Could not determine POP server's address");
  976. return (-1);
  977. }
  978. } while (ret != 0);
  979. if (ret == 0)
  980. {
  981. it = res;
  982. while (it)
  983. {
  984. if (it->ai_addrlen == sizeof (addr))
  985. {
  986. struct sockaddr_in *in_a = (struct sockaddr_in *) it->ai_addr;
  987. memcpy (&addr.sin_addr, &in_a->sin_addr, sizeof (addr.sin_addr));
  988. if (! connect (sock, (struct sockaddr *) &addr, sizeof (addr)))
  989. break;
  990. }
  991. it = it->ai_next;
  992. }
  993. connect_ok = it != NULL;
  994. if (connect_ok)
  995. {
  996. realhost = alloca (strlen (it->ai_canonname) + 1);
  997. strcpy (realhost, it->ai_canonname);
  998. }
  999. freeaddrinfo (res);
  1000. }
  1001. #else /* !HAVE_GETADDRINFO */
  1002. do
  1003. {
  1004. hostent = gethostbyname (host);
  1005. try_count++;
  1006. if ((! hostent) && ((h_errno != TRY_AGAIN) || (try_count == 5)))
  1007. {
  1008. strcpy (pop_error, "Could not determine POP server's address");
  1009. return (-1);
  1010. }
  1011. } while (! hostent);
  1012. while (*hostent->h_addr_list)
  1013. {
  1014. memcpy (&addr.sin_addr, *hostent->h_addr_list, hostent->h_length);
  1015. if (! connect (sock, (struct sockaddr *) &addr, sizeof (addr)))
  1016. break;
  1017. hostent->h_addr_list++;
  1018. }
  1019. connect_ok = *hostent->h_addr_list != NULL;
  1020. if (! connect_ok)
  1021. {
  1022. realhost = alloca (strlen (hostent->h_name) + 1);
  1023. strcpy (realhost, hostent->h_name);
  1024. }
  1025. #endif /* !HAVE_GETADDRINFO */
  1026. #define CONNECT_ERROR "Could not connect to POP server: "
  1027. if (! connect_ok)
  1028. {
  1029. CLOSESOCKET (sock);
  1030. strcpy (pop_error, CONNECT_ERROR);
  1031. strncat (pop_error, strerror (errno),
  1032. ERROR_MAX - sizeof (CONNECT_ERROR));
  1033. return (-1);
  1034. }
  1035. #ifdef KERBEROS
  1036. #define KRB_ERROR "Kerberos error connecting to POP server: "
  1037. if (! (flags & POP_NO_KERBEROS))
  1038. {
  1039. #ifdef KERBEROS5
  1040. if ((rem = krb5_init_context (&kcontext)))
  1041. {
  1042. krb5error:
  1043. if (auth_context)
  1044. krb5_auth_con_free (kcontext, auth_context);
  1045. if (kcontext)
  1046. krb5_free_context (kcontext);
  1047. strcpy (pop_error, KRB_ERROR);
  1048. strncat (pop_error, error_message (rem),
  1049. ERROR_MAX - sizeof (KRB_ERROR));
  1050. CLOSESOCKET (sock);
  1051. return (-1);
  1052. }
  1053. if ((rem = krb5_auth_con_init (kcontext, &auth_context)))
  1054. goto krb5error;
  1055. if (rem = krb5_cc_default (kcontext, &ccdef))
  1056. goto krb5error;
  1057. if (rem = krb5_cc_get_principal (kcontext, ccdef, &client))
  1058. goto krb5error;
  1059. for (cp = realhost; *cp; cp++)
  1060. {
  1061. if (isupper (*cp))
  1062. {
  1063. *cp = tolower (*cp);
  1064. }
  1065. }
  1066. if (rem = krb5_sname_to_principal (kcontext, realhost,
  1067. POP_SERVICE, FALSE, &server))
  1068. goto krb5error;
  1069. rem = krb5_sendauth (kcontext, &auth_context,
  1070. (krb5_pointer) &sock, "KPOPV1.0", client, server,
  1071. AP_OPTS_MUTUAL_REQUIRED,
  1072. 0, /* no checksum */
  1073. 0, /* no creds, use ccache instead */
  1074. ccdef,
  1075. &err_ret,
  1076. 0, /* don't need subsession key */
  1077. 0); /* don't need reply */
  1078. krb5_free_principal (kcontext, server);
  1079. if (rem)
  1080. {
  1081. strcpy (pop_error, KRB_ERROR);
  1082. strncat (pop_error, error_message (rem),
  1083. ERROR_MAX - sizeof (KRB_ERROR));
  1084. #if defined HAVE_KRB5_ERROR_TEXT
  1085. if (err_ret && err_ret->text.length)
  1086. {
  1087. strncat (pop_error, " [server says '",
  1088. ERROR_MAX - strlen (pop_error) - 1);
  1089. strncat (pop_error, err_ret->text.data,
  1090. min (ERROR_MAX - strlen (pop_error) - 1,
  1091. err_ret->text.length));
  1092. strncat (pop_error, "']",
  1093. ERROR_MAX - strlen (pop_error) - 1);
  1094. }
  1095. #elif defined HAVE_KRB5_ERROR_E_TEXT
  1096. if (err_ret && err_ret->e_text && strlen (*err_ret->e_text))
  1097. {
  1098. strncat (pop_error, " [server says '",
  1099. ERROR_MAX - strlen (pop_error) - 1);
  1100. strncat (pop_error, *err_ret->e_text,
  1101. ERROR_MAX - strlen (pop_error) - 1);
  1102. strncat (pop_error, "']",
  1103. ERROR_MAX - strlen (pop_error) - 1);
  1104. }
  1105. #endif
  1106. if (err_ret)
  1107. krb5_free_error (kcontext, err_ret);
  1108. krb5_auth_con_free (kcontext, auth_context);
  1109. krb5_free_context (kcontext);
  1110. CLOSESOCKET (sock);
  1111. return (-1);
  1112. }
  1113. #else /* ! KERBEROS5 */
  1114. ticket = (KTEXT) malloc (sizeof (KTEXT_ST));
  1115. rem = krb_sendauth (0L, sock, ticket, "pop", realhost,
  1116. (char *) krb_realmofhost (realhost),
  1117. (unsigned long) 0, &msg_data, &cred, schedule,
  1118. (struct sockaddr_in *) 0,
  1119. (struct sockaddr_in *) 0,
  1120. "KPOPV0.1");
  1121. free ((char *) ticket);
  1122. if (rem != KSUCCESS)
  1123. {
  1124. strcpy (pop_error, KRB_ERROR);
  1125. strncat (pop_error, krb_err_txt[rem],
  1126. ERROR_MAX - sizeof (KRB_ERROR));
  1127. CLOSESOCKET (sock);
  1128. return (-1);
  1129. }
  1130. #endif /* KERBEROS5 */
  1131. }
  1132. #endif /* KERBEROS */
  1133. return (sock);
  1134. } /* socket_connection */
  1135. /*
  1136. * Function: pop_getline
  1137. *
  1138. * Purpose: Get a line of text from the connection and return a
  1139. * pointer to it. The carriage return and linefeed at the end of
  1140. * the line are stripped, but periods at the beginnings of lines
  1141. * are NOT dealt with in any special way.
  1142. *
  1143. * Arguments:
  1144. * server The server from which to get the line of text.
  1145. *
  1146. * Returns: The number of characters in the line, which is returned in
  1147. * LINE, not including the final null. A return value of 0
  1148. * indicates a blank line. A negative return value indicates an
  1149. * error (in which case the contents of LINE are undefined. In
  1150. * case of error, an error message is copied into pop_error.
  1151. *
  1152. * Notes: The line returned is overwritten with each call to pop_getline.
  1153. *
  1154. * Side effects: Closes the connection on error.
  1155. *
  1156. * THE RETURNED LINE MAY CONTAIN EMBEDDED NULLS!
  1157. */
  1158. static int
  1159. pop_getline (popserver server, char **line)
  1160. {
  1161. #define GETLINE_ERROR "Error reading from server: "
  1162. int ret;
  1163. int search_offset = 0;
  1164. if (server->data)
  1165. {
  1166. char *cp = find_crlf (server->buffer + server->buffer_index,
  1167. server->data);
  1168. if (cp)
  1169. {
  1170. int found;
  1171. int data_used;
  1172. found = server->buffer_index;
  1173. data_used = (cp + 2) - server->buffer - found;
  1174. *cp = '\0'; /* terminate the string to be returned */
  1175. server->data -= data_used;
  1176. server->buffer_index += data_used;
  1177. if (pop_debug)
  1178. /* Embedded nulls will truncate this output prematurely,
  1179. but that's OK because it's just for debugging anyway. */
  1180. fprintf (stderr, "<<< %s\n", server->buffer + found);
  1181. *line = server->buffer + found;
  1182. return (data_used - 2);
  1183. }
  1184. else
  1185. {
  1186. memmove (server->buffer, server->buffer + server->buffer_index,
  1187. server->data);
  1188. /* Record the fact that we've searched the data already in
  1189. the buffer for a CRLF, so that when we search below, we
  1190. don't have to search the same data twice. There's a "-
  1191. 1" here to account for the fact that the last character
  1192. of the data we have may be the CR of a CRLF pair, of
  1193. which we haven't read the second half yet, so we may have
  1194. to search it again when we read more data. */
  1195. search_offset = server->data - 1;
  1196. server->buffer_index = 0;
  1197. }
  1198. }
  1199. else
  1200. {
  1201. server->buffer_index = 0;
  1202. }
  1203. while (1)
  1204. {
  1205. /* There's a "- 1" here to leave room for the null that we put
  1206. at the end of the read data below. We put the null there so
  1207. that find_crlf knows where to stop when we call it. */
  1208. if (server->data == server->buffer_size - 1)
  1209. {
  1210. server->buffer_size += GETLINE_INCR;
  1211. server->buffer = (char *)realloc (server->buffer, server->buffer_size);
  1212. if (! server->buffer)
  1213. {
  1214. strcpy (pop_error, "Out of memory in pop_getline");
  1215. pop_trash (server);
  1216. return (-1);
  1217. }
  1218. }
  1219. ret = RECV (server->file, server->buffer + server->data,
  1220. server->buffer_size - server->data - 1, 0);
  1221. if (ret < 0)
  1222. {
  1223. strcpy (pop_error, GETLINE_ERROR);
  1224. strncat (pop_error, strerror (errno),
  1225. ERROR_MAX - sizeof (GETLINE_ERROR));
  1226. pop_trash (server);
  1227. return (-1);
  1228. }
  1229. else if (ret == 0)
  1230. {
  1231. strcpy (pop_error, "Unexpected EOF from server in pop_getline");
  1232. pop_trash (server);
  1233. return (-1);
  1234. }
  1235. else
  1236. {
  1237. char *cp;
  1238. server->data += ret;
  1239. server->buffer[server->data] = '\0';
  1240. cp = find_crlf (server->buffer + search_offset,
  1241. server->data - search_offset);
  1242. if (cp)
  1243. {
  1244. int data_used = (cp + 2) - server->buffer;
  1245. *cp = '\0';
  1246. server->data -= data_used;
  1247. server->buffer_index = data_used;
  1248. if (pop_debug)
  1249. fprintf (stderr, "<<< %s\n", server->buffer);
  1250. *line = server->buffer;
  1251. return (data_used - 2);
  1252. }
  1253. /* As above, the "- 1" here is to account for the fact that
  1254. we may have read a CR without its accompanying LF. */
  1255. search_offset += ret - 1;
  1256. }
  1257. }
  1258. /* NOTREACHED */
  1259. }
  1260. /*
  1261. * Function: sendline
  1262. *
  1263. * Purpose: Sends a line of text to the POP server. The line of text
  1264. * passed into this function should NOT have the carriage return
  1265. * and linefeed on the end of it. Periods at beginnings of lines
  1266. * will NOT be treated specially by this function.
  1267. *
  1268. * Arguments:
  1269. * server The server to which to send the text.
  1270. * line The line of text to send.
  1271. *
  1272. * Return value: Upon successful completion, a value of 0 will be
  1273. * returned. Otherwise, a non-zero value will be returned, and
  1274. * an error will be copied into pop_error.
  1275. *
  1276. * Side effects: Closes the connection on error.
  1277. */
  1278. static int
  1279. sendline (popserver server, const char *line)
  1280. {
  1281. #define SENDLINE_ERROR "Error writing to POP server: "
  1282. int ret;
  1283. char *buf;
  1284. /* Combine the string and the CR-LF into one buffer. Otherwise, two
  1285. reasonable network stack optimizations, Nagle's algorithm and
  1286. delayed acks, combine to delay us a fraction of a second on every
  1287. message we send. (Movemail writes line without \r\n, client
  1288. kernel sends packet, server kernel delays the ack to see if it
  1289. can combine it with data, movemail writes \r\n, client kernel
  1290. waits because it has unacked data already in its outgoing queue,
  1291. client kernel eventually times out and sends.)
  1292. This can be something like 0.2s per command, which can add up
  1293. over a few dozen messages, and is a big chunk of the time we
  1294. spend fetching mail from a server close by. */
  1295. buf = alloca (strlen (line) + 3);
  1296. strcpy (buf, line);
  1297. strcat (buf, "\r\n");
  1298. ret = fullwrite (server->file, buf, strlen (buf));
  1299. if (ret < 0)
  1300. {
  1301. pop_trash (server);
  1302. strcpy (pop_error, SENDLINE_ERROR);
  1303. strncat (pop_error, strerror (errno),
  1304. ERROR_MAX - sizeof (SENDLINE_ERROR));
  1305. return (ret);
  1306. }
  1307. if (pop_debug)
  1308. fprintf (stderr, ">>> %s\n", line);
  1309. return (0);
  1310. }
  1311. /*
  1312. * Procedure: fullwrite
  1313. *
  1314. * Purpose: Just like write, but keeps trying until the entire string
  1315. * has been written.
  1316. *
  1317. * Return value: Same as write. Pop_error is not set.
  1318. */
  1319. static int
  1320. fullwrite (int fd, char *buf, int nbytes)
  1321. {
  1322. char *cp;
  1323. int ret = 0;
  1324. cp = buf;
  1325. while (nbytes && ((ret = SEND (fd, cp, nbytes, 0)) > 0))
  1326. {
  1327. cp += ret;
  1328. nbytes -= ret;
  1329. }
  1330. return (ret);
  1331. }
  1332. /*
  1333. * Procedure getok
  1334. *
  1335. * Purpose: Reads a line from the server. If the return indicator is
  1336. * positive, return with a zero exit status. If not, return with
  1337. * a negative exit status.
  1338. *
  1339. * Arguments:
  1340. * server The server to read from.
  1341. *
  1342. * Returns: 0 for success, else for failure and puts error in pop_error.
  1343. *
  1344. * Side effects: On failure, may make the connection unusable.
  1345. */
  1346. static int
  1347. getok (popserver server)
  1348. {
  1349. char *fromline;
  1350. if (pop_getline (server, &fromline) < 0)
  1351. {
  1352. return (-1);
  1353. }
  1354. if (! strncmp (fromline, "+OK", 3))
  1355. return (0);
  1356. else if (! strncmp (fromline, "-ERR", 4))
  1357. {
  1358. strncpy (pop_error, fromline, ERROR_MAX);
  1359. pop_error[ERROR_MAX-1] = '\0';
  1360. return (-1);
  1361. }
  1362. else
  1363. {
  1364. strcpy (pop_error,
  1365. "Unexpected response from server; expecting +OK or -ERR");
  1366. pop_trash (server);
  1367. return (-1);
  1368. }
  1369. }
  1370. #if 0
  1371. /*
  1372. * Function: gettermination
  1373. *
  1374. * Purpose: Gets the next line and verifies that it is a termination
  1375. * line (nothing but a dot).
  1376. *
  1377. * Return value: 0 on success, non-zero with pop_error set on error.
  1378. *
  1379. * Side effects: Closes the connection on error.
  1380. */
  1381. static int
  1382. gettermination (server)
  1383. popserver server;
  1384. {
  1385. char *fromserver;
  1386. if (pop_getline (server, &fromserver) < 0)
  1387. return (-1);
  1388. if (strcmp (fromserver, "."))
  1389. {
  1390. strcpy (pop_error,
  1391. "Unexpected response from server in gettermination");
  1392. pop_trash (server);
  1393. return (-1);
  1394. }
  1395. return (0);
  1396. }
  1397. #endif
  1398. /*
  1399. * Function pop_close
  1400. *
  1401. * Purpose: Close a pop connection, sending a "RSET" command to try to
  1402. * preserve any changes that were made and a "QUIT" command to
  1403. * try to get the server to quit, but ignoring any responses that
  1404. * are received.
  1405. *
  1406. * Side effects: The server is unusable after this function returns.
  1407. * Changes made to the maildrop since the session was started (or
  1408. * since the last pop_reset) may be lost.
  1409. */
  1410. void
  1411. pop_close (popserver server)
  1412. {
  1413. pop_trash (server);
  1414. free ((char *) server);
  1415. return;
  1416. }
  1417. /*
  1418. * Function: pop_trash
  1419. *
  1420. * Purpose: Like pop_close or pop_quit, but doesn't deallocate the
  1421. * memory associated with the server. It is valid to call
  1422. * pop_close or pop_quit after this function has been called.
  1423. */
  1424. static void
  1425. pop_trash (popserver server)
  1426. {
  1427. if (server->file >= 0)
  1428. {
  1429. /* avoid recursion; sendline can call pop_trash */
  1430. if (server->trash_started)
  1431. return;
  1432. server->trash_started = 1;
  1433. sendline (server, "RSET");
  1434. sendline (server, "QUIT");
  1435. CLOSESOCKET (server->file);
  1436. server->file = -1;
  1437. if (server->buffer)
  1438. {
  1439. free (server->buffer);
  1440. server->buffer = 0;
  1441. }
  1442. }
  1443. #ifdef WINDOWSNT
  1444. if (have_winsock)
  1445. WSACleanup ();
  1446. #endif
  1447. }
  1448. /* Return a pointer to the first CRLF in IN_STRING, which can contain
  1449. embedded nulls and has LEN characters in it not including the final
  1450. null, or 0 if it does not contain one. */
  1451. static char *
  1452. find_crlf (char *in_string, int len)
  1453. {
  1454. while (len--)
  1455. {
  1456. if (*in_string == '\r')
  1457. {
  1458. if (*++in_string == '\n')
  1459. return (in_string - 1);
  1460. }
  1461. else
  1462. in_string++;
  1463. }
  1464. return (0);
  1465. }
  1466. #endif /* MAIL_USE_POP */