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