2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
26 * $TOG: POP3Server.C /main/8 1998/11/10 17:09:21 mgreess $
28 * RESTRICTED CONFIDENTIAL INFORMATION:
30 * The information in this document is subject to special
31 * restrictions in a confidential disclosure agreement between
32 * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
33 * document outside HP, IBM, Sun, USL, SCO, or Univel without
34 * Sun's specific written approval. This document and all copies
35 * and derivative works thereof must be returned or destroyed at
38 * Copyright 1993, 1995, 1995 Sun Microsystems, Inc. All rights reserved.
43 * Common Desktop Environment
45 * (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
46 * (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
47 * (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
48 * (c) Copyright 1993, 1994, 1995 Novell, Inc.
49 * (c) Copyright 1995 Digital Equipment Corp.
50 * (c) Copyright 1995 Fujitsu Limited
51 * (c) Copyright 1995 Hitachi, Ltd.
54 * RESTRICTED RIGHTS LEGEND
56 *Use, duplication, or disclosure by the U.S. Government is subject to
57 *restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in
58 *Technical Data and Computer Software clause in DFARS 252.227-7013. Rights
59 *for non-DOD U.S. Government Departments and Agencies are as set forth in
60 *FAR 52.227-19(c)(1,2).
62 *Hewlett-Packard Company, 3000 Hanover Street, Palo Alto, CA 94304 U.S.A.
63 *International Business Machines Corp., Route 100, Somers, NY 10589 U.S.A.
64 *Sun Microsystems, Inc., 2550 Garcia Avenue, Mountain View, CA 94043 U.S.A.
65 *Novell, Inc., 190 River Road, Summit, NJ 07901 U.S.A.
66 *Digital Equipment Corp., 111 Powdermill Road, Maynard, MA 01754, U.S.A.
67 *Fujitsu Limited, 1015, Kamikodanaka Nakahara-Ku, Kawasaki 211, Japan
68 *Hitachi, Ltd., 6, Kanda Surugadai 4-Chome, Chiyoda-ku, Tokyo 101, Japan
76 #include <sys/param.h>
79 #include <DtMail/DtMail.hh>
80 #include <DtMail/DtMailError.hh>
81 #include <DtMail/DtMailServer.hh>
82 #include <DtMail/DtVirtArray.hh>
83 #include <DtMail/IO.hh>
85 POP3Server::POP3Server(
87 DtMail::Session *session,
88 DtMail::MailBox *mailbox,
89 DtMailAppendCallback append_mailbox_cb,
90 void *append_mailbox_cb_data)
91 : DtMailServer(folder, session, mailbox,
92 append_mailbox_cb, append_mailbox_cb_data)
96 _uidlist_current = NULL;
100 POP3Server::~POP3Server()
103 uidlist_destroy(_uidlist_old);
106 if (_uidlist_current)
107 uidlist_destroy(_uidlist_current);
108 _uidlist_current = NULL;
116 // Delete a given message.
119 POP3Server::ptrans_delete(int msg)
121 if (_uidlist_current)
124 uidliststr = uidlist_find(_uidlist_current, msg, NULL);
125 _uidlist_current->remove(uidliststr);
128 return do_transaction("DELE %d", msg);
132 // Request nth message.
135 POP3Server::ptrans_retrieve_start(int msg, int *lenp)
138 char buf[DTMAS_POPBUFSIZE+1];
141 ok = do_send("RETR %d", msg);
142 if (DTME_NoError != ok) return ok;
143 ok = ptrans_parse_response(buf);
144 if (DTME_NoError != ok) return ok;
146 // Look for "nnn octets" -- there may or may not be preceding cruft.
147 if ((cp = strstr(buf, " octets")) == (char *)NULL)
151 while (--cp > buf && isdigit(*cp))
159 // Apply for connection authorization.
162 POP3Server::ptrans_authorize(char*)
164 static char *pname = "POP3Server::ptrans_authorize";
167 ok = do_transaction("USER %s", _username);
168 if (DTME_NoError != ok) return DTME_MailServerAccess_AuthorizationFailed;
170 ok = do_transaction("PASS %s", _password);
171 if (DTME_NoError != ok) return DTME_MailServerAccess_AuthorizationFailed;
178 // Get range of messages to be fetched.
181 POP3Server::ptrans_fldstate_read(int *countp, int *newp)
183 static char *pname = "POP3Server::ptrans_fldstate_read";
185 char buf[DTMAS_POPBUFSIZE+1];
187 /* get the total message count */
188 ok = do_send("STAT");
189 if (DTME_NoError != ok) return ok;
190 ok = ptrans_parse_response(buf);
191 if (DTME_NoError != ok) return ok;
193 sscanf(buf, "%d %*d", countp);
196 * Newer, RFC-1725-conformant POP servers may not have the LAST command.
197 * We work as hard as possible to hide this ugliness, but it makes
198 * counting new messages intrinsically quadratic in the worst case.
203 ok = do_send("LAST");
204 if (DTME_NoError != ok) return ok;
205 ok = ptrans_parse_response(buf);
206 if (DTME_NoError == ok)
210 if (sscanf(buf, "%d", &last) == 0)
211 _logger.logError(DTM_FALSE, "Protocol Error getting range");
213 if (0 == _retrieveerrors) _lastretrieved = last;
215 *newp = (*countp - _lastretrieved);
219 if (NULL == _uidlist_old)
221 _uidlist_old = uidlist_create();
222 uidlist_read(_uidlist_old);
225 if (NULL == _uidlist_current)
226 _uidlist_current = uidlist_create();
228 /* grab the mailbox's UID list */
229 ok = do_transaction("UIDL");
230 if (DTME_NoError != ok)
235 char curuidstr[DTMAS_IDSIZE+1];
239 while (SockGets(buf, sizeof(buf), _sockfp))
241 if (buf[strlen(buf)-1] == '\n')
242 buf[strlen(buf)-1] = '\0';
243 if (buf[strlen(buf)-1] == '\r')
244 buf[strlen(buf)-1] = '\r';
247 _logger.logError(DTM_FALSE, "%s< %s", proto_name(), buf);
251 else if (sscanf(buf, "%d %s", &curmsg, curuidstr) == 2)
253 char *uidliststr = NULL;
255 _uidlist_current->append(strdup(buf));
257 uidliststr = uidlist_find(_uidlist_old, -1, curuidstr);
270 // Capture the sizes of all messages.
273 POP3Server::ptrans_msgsizes(int, int *sizes)
275 static char *pname = "POP3Server::ptrans_msgsizes";
276 char buf[DTMAS_POPBUFSIZE+1];
279 ok = do_transaction("LIST");
280 if (DTME_NoError != ok) return ok;
282 while (SockGets(buf, sizeof(buf), _sockfp))
286 if (buf[strlen(buf)-1] == '\n')
287 buf[strlen(buf)-1] = '\0';
288 if (buf[strlen(buf)-1] == '\r')
289 buf[strlen(buf)-1] = '\r';
292 _logger.logError(DTM_FALSE, "%s< %s", proto_name(), buf);
296 else if (sscanf(buf, "%d %d", &curmsg, &cursize) == 2)
297 sizes[curmsg-1] = cursize;
299 sizes[curmsg-1] = -1;
306 // Is the given message old?
309 POP3Server::ptrans_msgisold(int msg)
311 if (NULL == _uidlist_old)
312 return (msg <= _lastretrieved);
315 char curuidstr[DTMAS_IDSIZE+1];
317 char *uidliststr = NULL;
319 uidliststr = uidlist_find(_uidlist_current, msg, NULL);
320 if (sscanf(uidliststr, "%d %s", &curmsg, curuidstr) == 2)
321 uidliststr = uidlist_find(_uidlist_old, -1, curuidstr);
325 if (NULL != uidliststr)
333 // parse command response.
336 POP3Server::ptrans_parse_response (char *argbuf)
339 char buf[DTMAS_POPBUFSIZE+1];
342 if (SockGets(buf, sizeof(buf), _sockfp))
344 if (buf[strlen(buf)-1] == '\n')
345 buf[strlen(buf)-1] = '\0';
346 if (buf[strlen(buf)-1] == '\r')
347 buf[strlen(buf)-1] = '\r';
350 _logger.logError(DTM_FALSE, "%s< %s", proto_name(), buf);
353 if (*bufp == '+' || *bufp == '-')
356 return DTME_MailServerAccess_ProtocolViolation;
358 while (isalpha(*bufp)) bufp++;
361 if (strcmp(buf,"+OK") == 0)
365 else if (strcmp(buf,"-ERR") == 0)
367 _logger.logError(DTM_FALSE, "Protocol Error reading response");
368 ok = DTME_MailServerAccess_Error;
372 _logger.logError(DTM_FALSE, "Protocol Violation reading response");
373 ok = DTME_MailServerAccess_ProtocolViolation;
381 _logger.logError(DTM_FALSE, "Socket Error reading response");
382 ok = DTME_MailServerAccess_SocketIOError;
389 // Retrieve messages using POP3.
392 POP3Server::retrieve_messages(DtMailEnv &error)
394 DtMailServer::retrieve_messages(error);
396 uidlist_destroy(_uidlist_old);
397 _uidlist_old = _uidlist_current;
398 uidlist_write(_uidlist_old);
399 _uidlist_current = NULL;
403 POP3Server::uidlist_create()
405 DtVirtArray<char*> *uidlist = new DtVirtArray<char*>(25);
410 POP3Server::uidlist_destroy(DtVirtArray<char*> *uidlist)
415 if (NULL == uidlist) return;
417 for (i=0, nuidliststr=uidlist->length(); i<nuidliststr; i++)
419 uidliststr = (*uidlist)[i];
420 if (NULL != uidliststr)
427 POP3Server::uidlist_find(
428 DtVirtArray<char*> *uidlist,
435 if (msg < 0 && NULL == uidstr) return NULL;
437 for (i=0, nuidliststr=uidlist->length(); i<nuidliststr; i++)
440 char curuidstr[DTMAS_IDSIZE+1];
442 uidliststr = (*uidlist)[i];
443 if (sscanf(uidliststr, "%d %s", &curmsg, curuidstr) == 2)
445 if ((msg < 0 || msg == curmsg) &&
446 (uidstr == NULL || 0 == strcasecmp(uidstr, curuidstr)))
454 POP3Server::uidlist_read(DtVirtArray<char*> *uidlist)
456 static char *pname = "POP3Server::uidlist_read";
460 if (NULL == uidlist) return;
462 if (NULL == _uidlist_file)
464 char *path = new char[MAXPATHLEN+1];
465 sprintf(path, "+/.%s@%s.uidlist", _folder, _servername);
467 _uidlist_file = _session->expandPath(error, (const char*) path);
468 if (NULL == _uidlist_file && error.isSet())
472 "%s: Failed to find uidlist file %s\n",
480 if (NULL != (fp = fopen(_uidlist_file, "r")))
482 char uidliststr[DTMAS_POPBUFSIZE+1];
483 char curuidstr[DTMAS_IDSIZE+1];
486 while (NULL != fgets(uidliststr, DTMAS_POPBUFSIZE, fp))
487 if (sscanf(uidliststr, "%d %s", &curmsg, curuidstr) == 2)
488 uidlist->append(strdup(uidliststr));
494 POP3Server::uidlist_write(DtVirtArray<char*> *uidlist)
500 if (NULL == uidlist || NULL == _uidlist_file) return;
502 if (NULL != (fp = fopen(_uidlist_file, "w")))
504 for (i=0, nuidliststr=uidlist->length(); i<nuidliststr; i++)
506 uidliststr = (*uidlist)[i];
507 fprintf(fp, "%s\n", uidliststr);