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: nntpdriver_tools.c,v 1.22 2008/02/20 22:15:50 hoa Exp $
34  */
35 
36 #ifdef HAVE_CONFIG_H
37 #	include <config.h>
38 #endif
39 
40 #include "nntpdriver_tools.h"
41 
42 #include "mail.h"
43 #include "nntpdriver.h"
44 #include "nntpdriver_cached.h"
45 #include "newsnntp.h"
46 #include "maildriver_types.h"
47 #include "generic_cache.h"
48 #include "imfcache.h"
49 #include "mailmessage.h"
50 #include "mail_cache_db.h"
51 
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <fcntl.h>
55 #ifdef HAVE_UNISTD_H
56 #	include <unistd.h>
57 #endif
58 #include <string.h>
59 #include <stdlib.h>
60 
nntpdriver_nntp_error_to_mail_error(int error)61 int nntpdriver_nntp_error_to_mail_error(int error)
62 {
63   switch (error) {
64   case NEWSNNTP_NO_ERROR:
65     return MAIL_NO_ERROR;
66 
67   case NEWSNNTP_ERROR_STREAM:
68     return MAIL_ERROR_STREAM;
69 
70   case NEWSNNTP_ERROR_UNEXPECTED:
71     return MAIL_ERROR_UNKNOWN;
72 
73   case NEWSNNTP_ERROR_NO_NEWSGROUP_SELECTED:
74     return MAIL_ERROR_FOLDER_NOT_FOUND;
75 
76   case NEWSNNTP_ERROR_NO_ARTICLE_SELECTED:
77   case NEWSNNTP_ERROR_INVALID_ARTICLE_NUMBER:
78   case NEWSNNTP_ERROR_ARTICLE_NOT_FOUND:
79     return MAIL_ERROR_MSG_NOT_FOUND;
80 
81   case NEWSNNTP_ERROR_UNEXPECTED_RESPONSE:
82   case NEWSNNTP_ERROR_INVALID_RESPONSE:
83     return MAIL_ERROR_PARSE;
84 
85   case NEWSNNTP_ERROR_NO_SUCH_NEWS_GROUP:
86     return MAIL_ERROR_FOLDER_NOT_FOUND;
87 
88   case NEWSNNTP_ERROR_POSTING_NOT_ALLOWED:
89     return MAIL_ERROR_READONLY;
90 
91   case NEWSNNTP_ERROR_POSTING_FAILED:
92     return MAIL_ERROR_APPEND;
93 
94   case NEWSNNTP_ERROR_PROGRAM_ERROR:
95     return MAIL_ERROR_PROGRAM_ERROR;
96 
97   case NEWSNNTP_ERROR_NO_PERMISSION:
98     return MAIL_ERROR_NO_PERMISSION;
99 
100   case NEWSNNTP_ERROR_COMMAND_NOT_UNDERSTOOD:
101   case NEWSNNTP_ERROR_COMMAND_NOT_SUPPORTED:
102     return MAIL_ERROR_COMMAND_NOT_SUPPORTED;
103 
104   case NEWSNNTP_ERROR_CONNECTION_REFUSED:
105     return MAIL_ERROR_CONNECT;
106 
107   case NEWSNNTP_ERROR_MEMORY:
108     return MAIL_ERROR_MEMORY;
109 
110   case NEWSNNTP_ERROR_AUTHENTICATION_REJECTED:
111     return MAIL_ERROR_LOGIN;
112 
113   case NEWSNNTP_ERROR_BAD_STATE:
114   case NEWSNNTP_ERROR_AUTHENTICATION_OUT_OF_SEQUENCE:
115     return MAIL_ERROR_BAD_STATE;
116 
117   case NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME:
118   case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD:
119   default:
120     return MAIL_ERROR_INVAL;
121   }
122 }
123 
124 static inline struct nntp_session_state_data *
session_get_data(mailsession * session)125 session_get_data(mailsession * session)
126 {
127   return session->sess_data;
128 }
129 
session_get_nntp_session(mailsession * session)130 static inline newsnntp * session_get_nntp_session(mailsession * session)
131 {
132   return session_get_data(session)->nntp_session;
133 }
134 
135 static inline struct nntp_cached_session_state_data *
cached_session_get_data(mailsession * session)136 cached_session_get_data(mailsession * session)
137 {
138   return session->sess_data;
139 }
140 
cached_session_get_ancestor(mailsession * session)141 static inline mailsession * cached_session_get_ancestor(mailsession * session)
142 {
143   return cached_session_get_data(session)->nntp_ancestor;
144 }
145 
146 static inline struct nntp_session_state_data *
cached_session_get_ancestor_data(mailsession * session)147 cached_session_get_ancestor_data(mailsession * session)
148 {
149   return session_get_data(cached_session_get_ancestor(session));
150 }
151 
cached_session_get_nntp_session(mailsession * session)152 static inline newsnntp * cached_session_get_nntp_session(mailsession * session)
153 {
154   return session_get_nntp_session(cached_session_get_ancestor(session));
155 }
156 
157 
nntpdriver_authenticate_password(mailsession * session)158 int nntpdriver_authenticate_password(mailsession * session)
159 {
160   struct nntp_session_state_data * data;
161   int r;
162 
163   data = session_get_data(session);
164 
165   if (data->nntp_password == NULL)
166     return MAIL_ERROR_LOGIN;
167 
168   r = newsnntp_authinfo_password(session_get_nntp_session(session),
169       data->nntp_password);
170 
171   return nntpdriver_nntp_error_to_mail_error(r);
172 }
173 
nntpdriver_mode_reader(mailsession * session)174 int nntpdriver_mode_reader(mailsession * session)
175 {
176   int done;
177   int r;
178 
179   done = FALSE;
180 
181   do {
182     r = newsnntp_mode_reader(session_get_nntp_session(session));
183 
184     switch (r) {
185     case NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME:
186       r = nntpdriver_authenticate_user(session);
187       if (r != MAIL_NO_ERROR)
188         return r;
189       break;
190 
191     case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD:
192       r = nntpdriver_authenticate_password(session);
193       if (r != MAIL_NO_ERROR)
194         return r;
195       break;
196 
197     case NEWSNNTP_NO_ERROR:
198       done = TRUE;
199       break;
200 
201     default:
202       done = TRUE;
203       break;
204     }
205   }
206   while (!done);
207 
208   return MAIL_NO_ERROR;
209 }
210 
nntpdriver_authenticate_user(mailsession * session)211 int nntpdriver_authenticate_user(mailsession * session)
212 {
213   struct nntp_session_state_data * data;
214   int r;
215 
216   data = session_get_data(session);
217 
218   if (data->nntp_userid == NULL)
219     return MAIL_ERROR_LOGIN;
220 
221   r = newsnntp_authinfo_username(session_get_nntp_session(session),
222       data->nntp_userid);
223 
224   switch (r) {
225   case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD:
226     return nntpdriver_authenticate_password(session);
227 
228   default:
229     return nntpdriver_nntp_error_to_mail_error(r);
230   }
231 }
232 
nntpdriver_article(mailsession * session,uint32_t indx,char ** result,size_t * result_len)233 int nntpdriver_article(mailsession * session, uint32_t indx,
234 		       char ** result,
235 		       size_t * result_len)
236 {
237   char * msg_content;
238   size_t msg_length;
239   int r;
240   int done;
241 
242   done = FALSE;
243   do {
244     r = newsnntp_article(session_get_nntp_session(session),
245         indx, &msg_content, &msg_length);
246 
247     switch (r) {
248     case NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME:
249       r = nntpdriver_authenticate_user(session);
250       if (r != MAIL_NO_ERROR)
251 	return r;
252       break;
253 
254     case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD:
255       r = nntpdriver_authenticate_password(session);
256       if (r != MAIL_NO_ERROR)
257 	return r;
258       break;
259 
260     case NEWSNNTP_NO_ERROR:
261       done = TRUE;
262       break;
263 
264     default:
265       return nntpdriver_nntp_error_to_mail_error(r);
266     }
267   }
268   while (!done);
269 
270   * result = msg_content;
271   * result_len = msg_length;
272 
273   return MAIL_NO_ERROR;
274 }
275 
nntpdriver_head(mailsession * session,uint32_t indx,char ** result,size_t * result_len)276 int nntpdriver_head(mailsession * session, uint32_t indx,
277 		    char ** result,
278 		    size_t * result_len)
279 {
280   char * headers;
281   size_t headers_length;
282   int r;
283   int done;
284 
285   done = FALSE;
286   do {
287     r = newsnntp_head(session_get_nntp_session(session),
288         indx, &headers, &headers_length);
289 
290     switch (r) {
291     case NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME:
292       r = nntpdriver_authenticate_user(session);
293       if (r != MAIL_NO_ERROR)
294 	return r;
295       break;
296 
297     case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD:
298       r = nntpdriver_authenticate_password(session);
299       if (r != MAIL_NO_ERROR)
300 	return r;
301       break;
302 
303     case NEWSNNTP_NO_ERROR:
304       done = TRUE;
305       break;
306 
307     default:
308       return nntpdriver_nntp_error_to_mail_error(r);
309     }
310   }
311   while (!done);
312 
313   * result = headers;
314   * result_len = headers_length;
315 
316   return MAIL_NO_ERROR;
317 }
318 
nntpdriver_size(mailsession * session,uint32_t indx,size_t * result)319 int nntpdriver_size(mailsession * session, uint32_t indx,
320 		    size_t * result)
321 {
322   newsnntp * nntp;
323   struct newsnntp_xover_resp_item * item;
324   int r;
325   int done;
326 
327   nntp = session_get_nntp_session(session);
328 
329   done = FALSE;
330   do {
331     r = newsnntp_xover_single(nntp, indx, &item);
332     switch (r) {
333     case NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME:
334       r = nntpdriver_authenticate_user(session);
335       if (r != MAIL_NO_ERROR)
336 	return r;
337       break;
338 
339     case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD:
340       r = nntpdriver_authenticate_password(session);
341       if (r != MAIL_NO_ERROR)
342 	return r;
343       break;
344 
345     case NEWSNNTP_NO_ERROR:
346       done = TRUE;
347       break;
348 
349     default:
350       return nntpdriver_nntp_error_to_mail_error(r);
351     }
352   }
353   while (!done);
354 
355   * result = item->ovr_size;
356 
357   xover_resp_item_free(item);
358 
359   return MAIL_NO_ERROR;
360 }
361 
362 int
nntpdriver_get_cached_flags(struct mail_cache_db * cache_db,MMAPString * mmapstr,uint32_t num,struct mail_flags ** result)363 nntpdriver_get_cached_flags(struct mail_cache_db * cache_db,
364     MMAPString * mmapstr,
365     uint32_t num,
366     struct mail_flags ** result)
367 {
368   int r;
369   char keyname[PATH_MAX];
370   struct mail_flags * flags;
371   int res;
372 
373   snprintf(keyname, PATH_MAX, "%u-flags", num);
374 
375   r = generic_cache_flags_read(cache_db, mmapstr, keyname, &flags);
376   if (r != MAIL_NO_ERROR) {
377     res = r;
378     goto err;
379   }
380 
381   * result = flags;
382 
383   return MAIL_NO_ERROR;
384 
385  err:
386   return res;
387 }
388 
389 int
nntpdriver_write_cached_flags(struct mail_cache_db * cache_db,MMAPString * mmapstr,uint32_t num,struct mail_flags * flags)390 nntpdriver_write_cached_flags(struct mail_cache_db * cache_db,
391     MMAPString * mmapstr,
392     uint32_t num,
393     struct mail_flags * flags)
394 {
395   int r;
396   char keyname[PATH_MAX];
397   int res;
398 
399   snprintf(keyname, PATH_MAX, "%u-flags", num);
400 
401   r = generic_cache_flags_write(cache_db, mmapstr, keyname, flags);
402   if (r != MAIL_NO_ERROR) {
403     res = r;
404     goto err;
405   }
406 
407   return MAIL_NO_ERROR;
408 
409  err:
410   return res;
411 }
412 
413 
nntpdriver_select_folder(mailsession * session,const char * mb)414 int nntpdriver_select_folder(mailsession * session, const char * mb)
415 {
416   int r;
417   struct newsnntp_group_info * info;
418   newsnntp * nntp_session;
419   struct nntp_session_state_data * data;
420   char * new_name;
421   int done;
422 
423   data = session_get_data(session);
424 
425   if (!data->nntp_mode_reader) {
426     r = nntpdriver_mode_reader(session);
427     if (r != MAIL_NO_ERROR)
428       return r;
429 
430     data->nntp_mode_reader = TRUE;
431   }
432 
433   if (data->nntp_group_name != NULL)
434     if (strcmp(data->nntp_group_name, mb) == 0)
435       return MAIL_NO_ERROR;
436 
437   nntp_session = session_get_nntp_session(session);
438 
439   done = FALSE;
440   do {
441     r = newsnntp_group(nntp_session, mb, &info);
442 
443     switch (r) {
444     case NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME:
445       r = nntpdriver_authenticate_user(session);
446       if (r != MAIL_NO_ERROR)
447 	return r;
448       break;
449 
450     case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD:
451       r = nntpdriver_authenticate_password(session);
452       if (r != MAIL_NO_ERROR)
453 	return r;
454       break;
455 
456     case NEWSNNTP_NO_ERROR:
457       done = TRUE;
458       break;
459 
460     default:
461       return nntpdriver_nntp_error_to_mail_error(r);
462     }
463 
464   }
465   while (!done);
466 
467   new_name = strdup(mb);
468   if (new_name == NULL)
469     return MAIL_ERROR_MEMORY;
470 
471   if (data->nntp_group_name != NULL)
472     free(data->nntp_group_name);
473   data->nntp_group_name = new_name;
474   if (data->nntp_group_info != NULL)
475     newsnntp_group_free(data->nntp_group_info);
476   data->nntp_group_info = info;
477 
478   return MAIL_NO_ERROR;
479 }
480 
481 
nntp_get_messages_list(mailsession * nntp_session,mailsession * session,mailmessage_driver * driver,struct mailmessage_list ** result)482 int nntp_get_messages_list(mailsession * nntp_session,
483 			   mailsession * session,
484 			   mailmessage_driver * driver,
485 			   struct mailmessage_list ** result)
486 {
487   carray * tab;
488   struct mailmessage_list * env_list;
489   uint32_t i;
490   int res;
491   int r;
492   struct nntp_session_state_data * data;
493   struct newsnntp_group_info * group_info;
494   uint32_t max;
495   unsigned int cur;
496 
497   data = session_get_data(nntp_session);
498 
499   if (data->nntp_group_name == NULL) {
500     res = MAIL_ERROR_BAD_STATE;
501     goto err;
502   }
503 
504   r = nntpdriver_select_folder(nntp_session, data->nntp_group_name);
505   if (r != MAIL_NO_ERROR) {
506     res = r;
507     goto err;
508   }
509 
510   group_info = data->nntp_group_info;
511 
512   if (group_info == NULL) {
513     res = MAIL_ERROR_BAD_STATE;
514     goto err;
515   }
516 
517   max = group_info->grp_first;
518   if (data->nntp_max_articles != 0) {
519     if (group_info->grp_last - data->nntp_max_articles + 1 > max)
520       max = group_info->grp_last - data->nntp_max_articles + 1;
521   }
522 
523   tab = carray_new(128);
524   if (tab == NULL) {
525     res = MAIL_ERROR_MEMORY;
526     goto err;
527   }
528 
529   for(i = max ; i <= group_info->grp_last ; i++) {
530     mailmessage * msg;
531 
532     msg = mailmessage_new();
533     if (msg == NULL) {
534       res = MAIL_ERROR_MEMORY;
535       goto free_list;
536     }
537 
538     r = mailmessage_init(msg, session, driver, i, 0);
539     if (r != MAIL_NO_ERROR) {
540       mailmessage_free(msg);
541       res = r;
542       goto free_list;
543     }
544 
545     r = carray_add(tab, msg, NULL);
546     if (r < 0) {
547       mailmessage_free(msg);
548       res = MAIL_ERROR_MEMORY;
549       goto free_list;
550     }
551   }
552 
553   env_list = mailmessage_list_new(tab);
554   if (env_list == NULL) {
555     res = MAIL_ERROR_MEMORY;
556     goto free_list;
557   }
558 
559   * result = env_list;
560 
561   return MAIL_NO_ERROR;
562 
563  free_list:
564   for(cur = 0 ; cur < carray_count(tab) ; cur ++)
565     mailmessage_free(carray_get(tab, cur));
566   carray_free(tab);
567  err:
568   return res;
569 }
570