1 /*
2  * libEtPan! -- a mail stuff library
3  *
4  * Copyright (C) 2001, 2005 - DINH Viet Hoa
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the libEtPan! project nor the names of its
16  *    contributors may be used to endorse or promote products derived
17  *    from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * $Id: pop3driver.c,v 1.46 2010/04/05 14:43:49 hoa Exp $
34  */
35 
36 #ifdef HAVE_CONFIG_H
37 #	include <config.h>
38 #endif
39 
40 #include "pop3driver.h"
41 
42 #include <string.h>
43 #include <stdlib.h>
44 
45 #include "pop3driver_message.h"
46 #include "maildriver_tools.h"
47 #include "pop3driver_tools.h"
48 #include "mailmessage.h"
49 
50 static int pop3driver_initialize(mailsession * session);
51 
52 static void pop3driver_uninitialize(mailsession * session);
53 
54 static int pop3driver_parameters(mailsession * session,
55     int id, void * value);
56 
57 static int pop3driver_connect_stream(mailsession * session, mailstream * s);
58 
59 static int pop3driver_starttls(mailsession * session);
60 
61 static int pop3driver_login(mailsession * session,
62 			    const char * userid, const char * password);
63 
64 static int pop3driver_logout(mailsession * session);
65 
66 static int pop3driver_noop(mailsession * session);
67 
68 static int pop3driver_status_folder(mailsession * session, const char * mb,
69     uint32_t * result_messages, uint32_t * result_recent,
70     uint32_t * result_unseen);
71 
72 static int pop3driver_messages_number(mailsession * session, const char * mb,
73 				      uint32_t * result);
74 
75 static int pop3driver_remove_message(mailsession * session, uint32_t num);
76 
77 static int pop3driver_get_messages_list(mailsession * session,
78 					struct mailmessage_list ** result);
79 
80 static int pop3driver_get_message(mailsession * session,
81 				  uint32_t num, mailmessage ** result);
82 
83 static int pop3driver_get_message_by_uid(mailsession * session,
84     const char * uid, mailmessage ** result);
85 
86 static int pop3driver_login_sasl(mailsession * session,
87     const char * auth_type,
88     const char * server_fqdn,
89     const char * local_ip_port,
90     const char * remote_ip_port,
91     const char * login, const char * auth_name,
92     const char * password, const char * realm);
93 
94 static mailsession_driver local_pop3_session_driver = {
95   /* sess_name */ "pop3",
96 
97   /* sess_initialize */ pop3driver_initialize,
98   /* sess_uninitialize */ pop3driver_uninitialize,
99 
100   /* sess_parameters */ pop3driver_parameters,
101 
102   /* sess_connect_stream */ pop3driver_connect_stream,
103   /* sess_connect_path */ NULL,
104   /* sess_starttls */ pop3driver_starttls,
105   /* sess_login */ pop3driver_login,
106   /* sess_logout */ pop3driver_logout,
107   /* sess_noop */ pop3driver_noop,
108 
109   /* sess_build_folder_name */ NULL,
110   /* sess_create_folder */ NULL,
111   /* sess_delete_folder */ NULL,
112   /* sess_rename_folder */ NULL,
113   /* sess_check_folder */ NULL,
114   /* sess_examine_folder */ NULL,
115   /* sess_select_folder */ NULL,
116   /* sess_expunge_folder */ NULL,
117   /* sess_status_folder */ pop3driver_status_folder,
118   /* sess_messages_number */ pop3driver_messages_number,
119   /* sess_recent_number */ pop3driver_messages_number,
120   /* sess_unseen_number */ pop3driver_messages_number,
121   /* sess_list_folders */ NULL,
122   /* sess_lsub_folders */ NULL,
123   /* sess_subscribe_folder */ NULL,
124   /* sess_unsubscribe_folder */ NULL,
125 
126   /* sess_append_message */ NULL,
127   /* sess_append_message_flags */ NULL,
128   /* sess_copy_message */ NULL,
129   /* sess_move_message */ NULL,
130 
131   /* sess_get_message */ pop3driver_get_message,
132   /* sess_get_message_by_uid */ pop3driver_get_message_by_uid,
133 
134   /* sess_get_messages_list */ pop3driver_get_messages_list,
135   /* sess_get_envelopes_list */ maildriver_generic_get_envelopes_list,
136   /* sess_remove_message */ pop3driver_remove_message,
137 
138   /* sess_login_sasl */ pop3driver_login_sasl
139 };
140 
141 mailsession_driver * pop3_session_driver = &local_pop3_session_driver;
142 
143 static inline struct pop3_session_state_data *
get_data(mailsession * session)144 get_data(mailsession * session)
145 {
146   return session->sess_data;
147 }
148 
get_pop3_session(mailsession * session)149 static mailpop3 * get_pop3_session(mailsession * session)
150 {
151   return get_data(session)->pop3_session;
152 }
153 
pop3driver_initialize(mailsession * session)154 static int pop3driver_initialize(mailsession * session)
155 {
156   struct pop3_session_state_data * data;
157   mailpop3 * pop3;
158 
159   pop3 = mailpop3_new(0, NULL);
160   if (session == NULL)
161     goto err;
162 
163   data = malloc(sizeof(* data));
164   if (data == NULL)
165     goto free;
166 
167   data->pop3_session = pop3;
168   data->pop3_auth_type = POP3DRIVER_AUTH_TYPE_PLAIN;
169 
170   session->sess_data = data;
171 
172   return MAIL_NO_ERROR;
173 
174  free:
175   mailpop3_free(pop3);
176  err:
177   return MAIL_ERROR_MEMORY;
178 }
179 
pop3driver_uninitialize(mailsession * session)180 static void pop3driver_uninitialize(mailsession * session)
181 {
182   struct pop3_session_state_data * data;
183 
184   data = get_data(session);
185 
186   mailpop3_free(data->pop3_session);
187   free(data);
188 
189   session->sess_data = NULL;
190 }
191 
pop3driver_connect_stream(mailsession * session,mailstream * s)192 static int pop3driver_connect_stream(mailsession * session, mailstream * s)
193 {
194   int r;
195 
196   r = mailpop3_connect(get_pop3_session(session), s);
197 
198   switch (r) {
199   case MAILPOP3_NO_ERROR:
200     return MAIL_NO_ERROR_NON_AUTHENTICATED;
201 
202   default:
203     return pop3driver_pop3_error_to_mail_error(r);
204   }
205 }
206 
pop3driver_starttls(mailsession * session)207 static int pop3driver_starttls(mailsession * session)
208 {
209   int r;
210   mailpop3 * pop3;
211 
212   pop3 = get_pop3_session(session);
213 
214   r = mailpop3_socket_starttls(pop3);
215   return pop3driver_pop3_error_to_mail_error(r);
216 }
217 
pop3driver_parameters(mailsession * session,int id,void * value)218 static int pop3driver_parameters(mailsession * session,
219     int id, void * value)
220 {
221   struct pop3_session_state_data * data;
222 
223   data = get_data(session);
224 
225   switch (id) {
226   case POP3DRIVER_SET_AUTH_TYPE:
227     {
228       int * param;
229 
230       param = value;
231 
232       data->pop3_auth_type = * param;
233       return MAIL_NO_ERROR;
234     }
235     break;
236   case POP3DRIVER_CACHED_SET_SSL_CALLBACK:
237     data->pop3_ssl_callback = value;
238     break;
239   case POP3DRIVER_CACHED_SET_SSL_CALLBACK_DATA:
240     data->pop3_ssl_cb_data = value;
241     break;
242   }
243 
244   return MAIL_ERROR_INVAL;
245 }
246 
pop3driver_login(mailsession * session,const char * userid,const char * password)247 static int pop3driver_login(mailsession * session,
248 			    const char * userid, const char * password)
249 {
250   int r;
251   carray * msg_tab;
252   struct pop3_session_state_data * data;
253 
254   data = get_data(session);
255 
256   switch (data->pop3_auth_type) {
257   case POP3DRIVER_AUTH_TYPE_TRY_APOP:
258     r = mailpop3_login_apop(get_pop3_session(session), userid, password);
259     if (r != MAILPOP3_NO_ERROR)
260       r = mailpop3_login(get_pop3_session(session), userid, password);
261     break;
262 
263   case POP3DRIVER_AUTH_TYPE_APOP:
264     r = mailpop3_login_apop(get_pop3_session(session), userid, password);
265     break;
266 
267   default:
268   case POP3DRIVER_AUTH_TYPE_PLAIN:
269     r = mailpop3_login(get_pop3_session(session), userid, password);
270     break;
271   }
272 
273   if (r != MAILPOP3_NO_ERROR)
274 	  return pop3driver_pop3_error_to_mail_error(r);
275 
276   r = mailpop3_list(get_pop3_session(session), &msg_tab);
277 
278   return pop3driver_pop3_error_to_mail_error(r);
279 }
280 
pop3driver_logout(mailsession * session)281 static int pop3driver_logout(mailsession * session)
282 {
283   int r;
284 
285   r = mailpop3_quit(get_pop3_session(session));
286 
287   return pop3driver_pop3_error_to_mail_error(r);
288 }
289 
pop3driver_noop(mailsession * session)290 static int pop3driver_noop(mailsession * session)
291 {
292   int r;
293 
294   r = mailpop3_noop(get_pop3_session(session));
295 
296   return pop3driver_pop3_error_to_mail_error(r);
297 }
298 
pop3driver_status_folder(mailsession * session,const char * mb,uint32_t * result_messages,uint32_t * result_recent,uint32_t * result_unseen)299 static int pop3driver_status_folder(mailsession * session, const char * mb,
300 				    uint32_t * result_messages,
301 				    uint32_t * result_recent,
302 				    uint32_t * result_unseen)
303 {
304   uint32_t count;
305   int r;
306 
307   count = 0;
308   r = pop3driver_messages_number(session, mb, &count);
309   if (r != MAIL_NO_ERROR)
310     return r;
311 
312   * result_messages = count;
313   * result_recent = count;
314   * result_unseen = count;
315 
316   return MAIL_NO_ERROR;
317 }
318 
pop3driver_messages_number(mailsession * session,const char * mb,uint32_t * result)319 static int pop3driver_messages_number(mailsession * session, const char * mb,
320 				      uint32_t * result)
321 {
322   carray * msg_tab;
323   int r;
324 
325   r = mailpop3_list(get_pop3_session(session), &msg_tab);
326   if (r != MAILPOP3_NO_ERROR) {
327 	  return pop3driver_pop3_error_to_mail_error(r);
328   }
329 
330   * result = carray_count(msg_tab) -
331     get_pop3_session(session)->pop3_deleted_count;
332 
333   return MAIL_NO_ERROR;
334 }
335 
336 
337 /* messages operations */
338 
pop3driver_remove_message(mailsession * session,uint32_t num)339 static int pop3driver_remove_message(mailsession * session, uint32_t num)
340 {
341   mailpop3 * pop3;
342   int r;
343 
344   pop3 = get_pop3_session(session);
345 
346   r = mailpop3_dele(pop3, num);
347   switch (r) {
348   case MAILPOP3_ERROR_BAD_STATE:
349     return MAIL_ERROR_BAD_STATE;
350 
351   case MAILPOP3_ERROR_NO_SUCH_MESSAGE:
352     return MAIL_ERROR_MSG_NOT_FOUND;
353 
354   case MAILPOP3_ERROR_STREAM:
355     return MAIL_ERROR_STREAM;
356 
357   case MAILPOP3_NO_ERROR:
358     return MAIL_NO_ERROR;
359 
360   default:
361     return MAIL_ERROR_REMOVE;
362   }
363 }
364 
pop3driver_get_messages_list(mailsession * session,struct mailmessage_list ** result)365 static int pop3driver_get_messages_list(mailsession * session,
366 					struct mailmessage_list ** result)
367 {
368   mailpop3 * pop3;
369 
370   pop3 = get_pop3_session(session);
371 
372   return pop3_get_messages_list(pop3, session,
373 				pop3_message_driver, result);
374 }
375 
pop3driver_get_message(mailsession * session,uint32_t num,mailmessage ** result)376 static int pop3driver_get_message(mailsession * session,
377 				  uint32_t num, mailmessage ** result)
378 {
379   mailmessage * msg_info;
380   int r;
381 
382   msg_info = mailmessage_new();
383   if (msg_info == NULL)
384     return MAIL_ERROR_MEMORY;
385 
386   r = mailmessage_init(msg_info, session, pop3_message_driver, num, 0);
387   if (r != MAIL_NO_ERROR) {
388     mailmessage_free(msg_info);
389     return r;
390   }
391 
392   * result = msg_info;
393 
394   return MAIL_NO_ERROR;
395 }
396 
pop3driver_get_message_by_uid(mailsession * session,const char * uid,mailmessage ** result)397 static int pop3driver_get_message_by_uid(mailsession * session,
398     const char * uid, mailmessage ** result)
399 {
400   mailpop3 * pop3;
401   struct mailpop3_msg_info * msg_info;
402   int found;
403   unsigned int i;
404 
405   if (uid == NULL)
406     return MAIL_ERROR_INVAL;
407 
408   pop3 = get_pop3_session(session);
409 
410   found = 0;
411 
412   /* iterate all messages and look for uid */
413   for(i = 0 ; i < carray_count(pop3->pop3_msg_tab) ; i++) {
414     msg_info = carray_get(pop3->pop3_msg_tab, i);
415 
416     if (msg_info == NULL)
417       continue;
418 
419     if (msg_info->msg_deleted)
420       continue;
421 
422     /* uid found, stop looking */
423     if (strcmp(msg_info->msg_uidl, uid) == 0) {
424       found = 1;
425       break;
426     }
427   }
428 
429   if (!found)
430     return MAIL_ERROR_MSG_NOT_FOUND;
431 
432   return pop3driver_get_message(session, msg_info->msg_index, result);
433 }
434 
pop3driver_login_sasl(mailsession * session,const char * auth_type,const char * server_fqdn,const char * local_ip_port,const char * remote_ip_port,const char * login,const char * auth_name,const char * password,const char * realm)435 static int pop3driver_login_sasl(mailsession * session,
436     const char * auth_type,
437     const char * server_fqdn,
438     const char * local_ip_port,
439     const char * remote_ip_port,
440     const char * login, const char * auth_name,
441     const char * password, const char * realm)
442 {
443   int r;
444 
445   r = mailpop3_auth(get_pop3_session(session),
446       auth_type, server_fqdn, local_ip_port, remote_ip_port,
447       login, auth_name, password, realm);
448 
449   return pop3driver_pop3_error_to_mail_error(r);
450 }
451