libetpan - fdik
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2607 lines
67 KiB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
  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. * $Id: mailimap.c,v 1.51 2011/07/10 23:10:12 hoa Exp $
  33. */
  34. #ifdef HAVE_CONFIG_H
  35. # include <config.h>
  36. #endif
  37. #include "mailimap.h"
  38. #include "mailimap_parser.h"
  39. #include "mailimap_sender.h"
  40. #include "mailimap_extension.h"
  41. #include "mail.h"
  42. #include "condstore.h"
  43. #include "condstore_private.h"
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #ifdef USE_SASL
  48. #include <sasl/sasl.h>
  49. #include <sasl/saslutil.h>
  50. #endif
  51. #include "mailsasl.h"
  52. #ifdef DEBUG
  53. #include "mailimap_print.h"
  54. #endif
  55. /*
  56. RFC 2060 : IMAP4rev1
  57. draft-crispin-imapv-15
  58. RFC 2222 : Simple Authentication and Security Layer
  59. 2061 IMAP4 Compatibility with IMAP2bis. M. Crispin. December 1996.
  60. (Format: TXT=5867 bytes) (Obsoletes RFC1730) (Status: INFORMATIONAL)
  61. 2062 Internet Message Access Protocol - Obsolete Syntax. M. Crispin.
  62. December 1996. (Format: TXT=14222 bytes) (Status: INFORMATIONAL)
  63. 2086 IMAP4 ACL extension. J. Myers. January 1997. (Format: TXT=13925
  64. bytes) (Status: PROPOSED STANDARD)
  65. 2087 IMAP4 QUOTA extension. J. Myers. January 1997. (Format: TXT=8542
  66. bytes) (Status: PROPOSED STANDARD)
  67. 2088 IMAP4 non-synchronizing literals. J. Myers. January 1997.
  68. (Format: TXT=4052 bytes) (Status: PROPOSED STANDARD)
  69. 2177 IMAP4 IDLE command. B. Leiba. June 1997. (Format: TXT=6770 bytes)
  70. (Status: PROPOSED STANDARD)
  71. 2180 IMAP4 Multi-Accessed Mailbox Practice. M. Gahrns. July 1997.
  72. (Format: TXT=24750 bytes) (Status: INFORMATIONAL)
  73. 2192 IMAP URL Scheme. C. Newman. September 1997. (Format: TXT=31426
  74. bytes) (Status: PROPOSED STANDARD)
  75. 2193 IMAP4 Mailbox Referrals. M. Gahrns. September 1997. (Format:
  76. TXT=16248 bytes) (Status: PROPOSED STANDARD)
  77. 2195 IMAP/POP AUTHorize Extension for Simple Challenge/Response. J.
  78. Klensin, R. Catoe, P. Krumviede. September 1997. (Format: TXT=10468
  79. bytes) (Obsoletes RFC2095) (Status: PROPOSED STANDARD)
  80. 2221 IMAP4 Login Referrals. M. Gahrns. October 1997. (Format: TXT=9251
  81. bytes) (Status: PROPOSED STANDARD)
  82. 2342 IMAP4 Namespace. M. Gahrns, C. Newman. May 1998. (Format:
  83. TXT=19489 bytes) (Status: PROPOSED STANDARD)
  84. 2359 IMAP4 UIDPLUS extension. J. Myers. June 1998. (Format: TXT=10862
  85. bytes) (Status: PROPOSED STANDARD)
  86. 2595 Using TLS with IMAP, POP3 and ACAP. C. Newman. June 1999.
  87. (Format: TXT=32440 bytes) (Status: PROPOSED STANDARD)
  88. 2683 IMAP4 Implementation Recommendations. B. Leiba. September 1999.
  89. (Format: TXT=56300 bytes) (Status: INFORMATIONAL)
  90. 2971 IMAP4 ID extension. T. Showalter. October 2000. (Format:
  91. TXT=14670 bytes) (Status: PROPOSED STANDARD)
  92. http://www.ietf.org/ids.by.wg/imapext.html
  93. */
  94. static inline void imap_logger(mailstream * s, int log_type,
  95. const char * str, size_t size, void * context);
  96. static int parse_greeting(mailimap * session,
  97. struct mailimap_greeting ** result);
  98. /* struct mailimap_response_info * */
  99. static void resp_text_store(mailimap * session,
  100. struct mailimap_resp_text *
  101. resp_text)
  102. {
  103. struct mailimap_resp_text_code * resp_text_code;
  104. resp_text_code = resp_text->rsp_code;
  105. if (resp_text_code != NULL) {
  106. switch (resp_text_code->rc_type) {
  107. case MAILIMAP_RESP_TEXT_CODE_ALERT:
  108. if (session->imap_response_info) {
  109. if (session->imap_response_info->rsp_alert != NULL)
  110. free(session->imap_response_info->rsp_alert);
  111. session->imap_response_info->rsp_alert = strdup(resp_text->rsp_text);
  112. }
  113. break;
  114. case MAILIMAP_RESP_TEXT_CODE_BADCHARSET:
  115. if (session->imap_response_info) {
  116. if (session->imap_response_info->rsp_badcharset != NULL) {
  117. clist_foreach(resp_text_code->rc_data.rc_badcharset,
  118. (clist_func) mailimap_astring_free, NULL);
  119. clist_free(resp_text_code->rc_data.rc_badcharset);
  120. }
  121. session->imap_response_info->rsp_badcharset =
  122. resp_text_code->rc_data.rc_badcharset;
  123. resp_text_code->rc_data.rc_badcharset = NULL;
  124. }
  125. break;
  126. case MAILIMAP_RESP_TEXT_CODE_CAPABILITY_DATA:
  127. if (session->imap_connection_info) {
  128. if (session->imap_connection_info->imap_capability != NULL)
  129. mailimap_capability_data_free(session->imap_connection_info->imap_capability);
  130. session->imap_connection_info->imap_capability =
  131. resp_text_code->rc_data.rc_cap_data;
  132. /* detach before free */
  133. resp_text_code->rc_data.rc_cap_data = NULL;
  134. }
  135. break;
  136. case MAILIMAP_RESP_TEXT_CODE_PARSE:
  137. if (session->imap_response_info) {
  138. if (session->imap_response_info->rsp_parse != NULL)
  139. free(session->imap_response_info->rsp_parse);
  140. session->imap_response_info->rsp_parse = strdup(resp_text->rsp_text);
  141. }
  142. break;
  143. case MAILIMAP_RESP_TEXT_CODE_PERMANENTFLAGS:
  144. if (session->imap_selection_info) {
  145. if (session->imap_selection_info->sel_perm_flags != NULL) {
  146. clist_foreach(session->imap_selection_info->sel_perm_flags,
  147. (clist_func) mailimap_flag_perm_free, NULL);
  148. clist_free(session->imap_selection_info->sel_perm_flags);
  149. }
  150. session->imap_selection_info->sel_perm_flags =
  151. resp_text_code->rc_data.rc_perm_flags;
  152. /* detach before free */
  153. resp_text_code->rc_data.rc_perm_flags = NULL;
  154. }
  155. break;
  156. case MAILIMAP_RESP_TEXT_CODE_READ_ONLY:
  157. if (session->imap_selection_info)
  158. session->imap_selection_info->sel_perm = MAILIMAP_MAILBOX_READONLY;
  159. break;
  160. case MAILIMAP_RESP_TEXT_CODE_READ_WRITE:
  161. if (session->imap_selection_info)
  162. session->imap_selection_info->sel_perm = MAILIMAP_MAILBOX_READWRITE;
  163. break;
  164. case MAILIMAP_RESP_TEXT_CODE_TRY_CREATE:
  165. if (session->imap_response_info)
  166. session->imap_response_info->rsp_trycreate = TRUE;
  167. break;
  168. case MAILIMAP_RESP_TEXT_CODE_UIDNEXT:
  169. if (session->imap_selection_info)
  170. session->imap_selection_info->sel_uidnext =
  171. resp_text_code->rc_data.rc_uidnext;
  172. break;
  173. case MAILIMAP_RESP_TEXT_CODE_UIDVALIDITY:
  174. if (session->imap_selection_info)
  175. session->imap_selection_info->sel_uidvalidity =
  176. resp_text_code->rc_data.rc_uidvalidity;
  177. break;
  178. case MAILIMAP_RESP_TEXT_CODE_UNSEEN:
  179. if (session->imap_selection_info)
  180. session->imap_selection_info->sel_first_unseen =
  181. resp_text_code->rc_data.rc_first_unseen;
  182. break;
  183. case MAILIMAP_RESP_TEXT_CODE_OTHER:
  184. if (session->imap_response_info) {
  185. if (session->imap_response_info->rsp_atom != NULL)
  186. free(session->imap_response_info->rsp_atom);
  187. if (session->imap_response_info->rsp_value != NULL)
  188. free(session->imap_response_info->rsp_value);
  189. session->imap_response_info->rsp_atom =
  190. resp_text_code->rc_data.rc_atom.atom_name;
  191. resp_text_code->rc_data.rc_atom.atom_name = NULL;
  192. session->imap_response_info->rsp_value =
  193. resp_text_code->rc_data.rc_atom.atom_value;
  194. resp_text_code->rc_data.rc_atom.atom_value = NULL;
  195. }
  196. break;
  197. case MAILIMAP_RESP_TEXT_CODE_EXTENSION:
  198. mailimap_extension_data_store(session, &(resp_text_code->rc_data.rc_ext_data));
  199. break;
  200. }
  201. }
  202. }
  203. static void resp_cond_state_store(mailimap * session,
  204. struct mailimap_resp_cond_state * resp_cond_state)
  205. {
  206. resp_text_store(session, resp_cond_state->rsp_text);
  207. }
  208. static void mailbox_data_store(mailimap * session,
  209. struct mailimap_mailbox_data * mb_data)
  210. {
  211. int r;
  212. switch (mb_data->mbd_type) {
  213. case MAILIMAP_MAILBOX_DATA_FLAGS:
  214. if (session->imap_selection_info) {
  215. if (session->imap_selection_info->sel_flags != NULL)
  216. mailimap_flag_list_free(session->imap_selection_info->sel_flags);
  217. session->imap_selection_info->sel_flags = mb_data->mbd_data.mbd_flags;
  218. mb_data->mbd_data.mbd_flags = NULL;
  219. }
  220. break;
  221. case MAILIMAP_MAILBOX_DATA_LIST:
  222. if (session->imap_response_info) {
  223. r = clist_append(session->imap_response_info->rsp_mailbox_list,
  224. mb_data->mbd_data.mbd_list);
  225. if (r == 0)
  226. mb_data->mbd_data.mbd_list = NULL;
  227. else {
  228. /* TODO must handle error case */
  229. }
  230. }
  231. break;
  232. case MAILIMAP_MAILBOX_DATA_LSUB:
  233. if (session->imap_response_info) {
  234. r = clist_append(session->imap_response_info->rsp_mailbox_lsub,
  235. mb_data->mbd_data.mbd_lsub);
  236. if (r == 0)
  237. mb_data->mbd_data.mbd_lsub = NULL;
  238. else {
  239. /* TODO must handle error case */
  240. }
  241. }
  242. break;
  243. case MAILIMAP_MAILBOX_DATA_SEARCH:
  244. if (session->imap_response_info) {
  245. if (session->imap_response_info->rsp_search_result != NULL) {
  246. if (mb_data->mbd_data.mbd_search != NULL) {
  247. clist_concat(session->imap_response_info->rsp_search_result,
  248. mb_data->mbd_data.mbd_search);
  249. clist_free(mb_data->mbd_data.mbd_search);
  250. mb_data->mbd_data.mbd_search = NULL;
  251. }
  252. }
  253. else {
  254. if (mb_data->mbd_data.mbd_search != NULL) {
  255. session->imap_response_info->rsp_search_result =
  256. mb_data->mbd_data.mbd_search;
  257. mb_data->mbd_data.mbd_search = NULL;
  258. }
  259. }
  260. }
  261. break;
  262. case MAILIMAP_MAILBOX_DATA_STATUS:
  263. if (session->imap_response_info) {
  264. if (session->imap_response_info->rsp_status != NULL)
  265. mailimap_mailbox_data_status_free(session->imap_response_info->rsp_status);
  266. session->imap_response_info->rsp_status = mb_data->mbd_data.mbd_status;
  267. #if 0
  268. if (session->imap_selection_info != NULL) {
  269. clistiter * cur;
  270. for(cur = clist_begin(mb_data->status->status_info_list)
  271. ; cur != NULL ; cur = clist_next(cur)) {
  272. struct mailimap_status_info * info;
  273. info = clist_content(cur);
  274. switch (info->att) {
  275. case MAILIMAP_STATUS_ATT_MESSAGES:
  276. session->imap_selection_info->exists = info->value;
  277. break;
  278. case MAILIMAP_STATUS_ATT_RECENT:
  279. session->imap_selection_info->recent = info->value;
  280. break;
  281. case MAILIMAP_STATUS_ATT_UIDNEXT:
  282. session->imap_selection_info->uidnext = info->value;
  283. break;
  284. case MAILIMAP_STATUS_ATT_UIDVALIDITY:
  285. session->imap_selection_info->uidvalidity = info->value;
  286. break;
  287. case MAILIMAP_STATUS_ATT_UNSEEN:
  288. session->imap_selection_info->unseen = info->value;
  289. break;
  290. }
  291. }
  292. }
  293. #endif
  294. #if 0
  295. mailimap_mailbox_data_status_free(mb_data->status);
  296. #endif
  297. mb_data->mbd_data.mbd_status = NULL;
  298. }
  299. break;
  300. case MAILIMAP_MAILBOX_DATA_EXISTS:
  301. if (session->imap_selection_info) {
  302. session->imap_selection_info->sel_exists = mb_data->mbd_data.mbd_exists;
  303. session->imap_selection_info->sel_has_exists = 1;
  304. }
  305. break;
  306. case MAILIMAP_MAILBOX_DATA_RECENT:
  307. if (session->imap_selection_info) {
  308. session->imap_selection_info->sel_recent = mb_data->mbd_data.mbd_recent;
  309. session->imap_selection_info->sel_has_recent = 1;
  310. }
  311. break;
  312. case MAILIMAP_MAILBOX_DATA_EXTENSION_DATA:
  313. mailimap_extension_data_store(session, &mb_data->mbd_data.mbd_extension);
  314. break;
  315. }
  316. }
  317. static void
  318. message_data_store(mailimap * session,
  319. struct mailimap_message_data * msg_data)
  320. {
  321. uint32_t * expunged;
  322. int r;
  323. switch (msg_data->mdt_type) {
  324. case MAILIMAP_MESSAGE_DATA_EXPUNGE:
  325. if (session->imap_response_info) {
  326. expunged = mailimap_number_alloc_new(msg_data->mdt_number);
  327. if (expunged != NULL) {
  328. r = clist_append(session->imap_response_info->rsp_expunged, expunged);
  329. if (r == 0) {
  330. /* do nothing */
  331. }
  332. else {
  333. /* TODO : must handle error case */
  334. mailimap_number_alloc_free(expunged);
  335. }
  336. if (session->imap_selection_info != NULL)
  337. session->imap_selection_info->sel_exists --;
  338. }
  339. }
  340. break;
  341. case MAILIMAP_MESSAGE_DATA_FETCH:
  342. r = clist_append(session->imap_response_info->rsp_fetch_list,
  343. msg_data->mdt_msg_att);
  344. if (r == 0) {
  345. msg_data->mdt_msg_att->att_number = msg_data->mdt_number;
  346. msg_data->mdt_msg_att = NULL;
  347. }
  348. else {
  349. /* TODO : must handle error case */
  350. }
  351. break;
  352. }
  353. }
  354. static void
  355. cont_req_or_resp_data_store(mailimap * session,
  356. struct mailimap_cont_req_or_resp_data * cont_req_or_resp_data)
  357. {
  358. if (cont_req_or_resp_data->rsp_type == MAILIMAP_RESP_RESP_DATA) {
  359. struct mailimap_response_data * resp_data;
  360. resp_data = cont_req_or_resp_data->rsp_data.rsp_resp_data;
  361. switch (resp_data->rsp_type) {
  362. case MAILIMAP_RESP_DATA_TYPE_COND_STATE:
  363. resp_cond_state_store(session, resp_data->rsp_data.rsp_cond_state);
  364. break;
  365. case MAILIMAP_RESP_DATA_TYPE_MAILBOX_DATA:
  366. mailbox_data_store(session, resp_data->rsp_data.rsp_mailbox_data);
  367. break;
  368. case MAILIMAP_RESP_DATA_TYPE_MESSAGE_DATA:
  369. message_data_store(session, resp_data->rsp_data.rsp_message_data);
  370. break;
  371. case MAILIMAP_RESP_DATA_TYPE_CAPABILITY_DATA:
  372. if (session->imap_connection_info) {
  373. if (session->imap_connection_info->imap_capability != NULL)
  374. mailimap_capability_data_free(session->imap_connection_info->imap_capability);
  375. session->imap_connection_info->imap_capability = resp_data->rsp_data.rsp_capability_data;
  376. resp_data->rsp_data.rsp_capability_data = NULL;
  377. }
  378. break;
  379. case MAILIMAP_RESP_DATA_TYPE_EXTENSION_DATA:
  380. mailimap_extension_data_store(session, &(resp_data->rsp_data.rsp_extension_data));
  381. break;
  382. }
  383. }
  384. }
  385. static void response_tagged_store(mailimap * session,
  386. struct mailimap_response_tagged * tagged)
  387. {
  388. resp_cond_state_store(session, tagged->rsp_cond_state);
  389. }
  390. static void resp_cond_bye_store(mailimap * session,
  391. struct mailimap_resp_cond_bye * resp_cond_bye)
  392. {
  393. resp_text_store(session, resp_cond_bye->rsp_text);
  394. }
  395. static void response_fatal_store(mailimap * session,
  396. struct mailimap_response_fatal * fatal)
  397. {
  398. resp_cond_bye_store(session, fatal->rsp_bye);
  399. }
  400. static void response_done_store(mailimap * session,
  401. struct mailimap_response_done * resp_done)
  402. {
  403. switch(resp_done->rsp_type) {
  404. case MAILIMAP_RESP_DONE_TYPE_TAGGED:
  405. response_tagged_store(session, resp_done->rsp_data.rsp_tagged);
  406. break;
  407. case MAILIMAP_RESP_DONE_TYPE_FATAL:
  408. response_fatal_store(session, resp_done->rsp_data.rsp_fatal);
  409. break;
  410. }
  411. }
  412. static void
  413. response_store(mailimap * session,
  414. struct mailimap_response * response)
  415. {
  416. clistiter * cur;
  417. if (session->imap_response_info) {
  418. mailimap_response_info_free(session->imap_response_info);
  419. session->imap_response_info = NULL;
  420. }
  421. session->imap_response_info = mailimap_response_info_new();
  422. if (session->imap_response_info == NULL) {
  423. /* ignored error */
  424. return;
  425. }
  426. if (response->rsp_cont_req_or_resp_data_list != NULL) {
  427. for(cur = clist_begin(response->rsp_cont_req_or_resp_data_list) ;
  428. cur != NULL ; cur = clist_next(cur)) {
  429. struct mailimap_cont_req_or_resp_data * cont_req_or_resp_data;
  430. cont_req_or_resp_data = clist_content(cur);
  431. cont_req_or_resp_data_store(session, cont_req_or_resp_data);
  432. }
  433. }
  434. response_done_store(session, response->rsp_resp_done);
  435. }
  436. static void resp_cond_auth_store(mailimap * session,
  437. struct mailimap_resp_cond_auth * cond_auth)
  438. {
  439. resp_text_store(session, cond_auth->rsp_text);
  440. }
  441. static void greeting_store(mailimap * session,
  442. struct mailimap_greeting * greeting)
  443. {
  444. switch (greeting->gr_type) {
  445. case MAILIMAP_GREETING_RESP_COND_AUTH:
  446. resp_cond_auth_store(session, greeting->gr_data.gr_auth);
  447. break;
  448. case MAILIMAP_GREETING_RESP_COND_BYE:
  449. resp_cond_bye_store(session, greeting->gr_data.gr_bye);
  450. break;
  451. }
  452. }
  453. LIBETPAN_EXPORT
  454. int mailimap_connect(mailimap * session, mailstream * s)
  455. {
  456. struct mailimap_greeting * greeting;
  457. int r;
  458. int auth_type;
  459. struct mailimap_connection_info * connection_info;
  460. if (session->imap_state != MAILIMAP_STATE_DISCONNECTED)
  461. return MAILIMAP_ERROR_BAD_STATE;
  462. session->imap_stream = s;
  463. mailstream_set_logger(s, imap_logger, session);
  464. if (session->imap_connection_info)
  465. mailimap_connection_info_free(session->imap_connection_info);
  466. connection_info = mailimap_connection_info_new();
  467. if (connection_info != NULL)
  468. session->imap_connection_info = connection_info;
  469. if (mailimap_read_line(session) == NULL) {
  470. return MAILIMAP_ERROR_STREAM;
  471. }
  472. r = parse_greeting(session, &greeting);
  473. if (r != MAILIMAP_NO_ERROR) {
  474. return r;
  475. }
  476. auth_type = greeting->gr_data.gr_auth->rsp_type;
  477. mailimap_greeting_free(greeting);
  478. switch (auth_type) {
  479. case MAILIMAP_RESP_COND_AUTH_PREAUTH:
  480. session->imap_state = MAILIMAP_STATE_AUTHENTICATED;
  481. return MAILIMAP_NO_ERROR_AUTHENTICATED;
  482. default:
  483. session->imap_state = MAILIMAP_STATE_NON_AUTHENTICATED;
  484. return MAILIMAP_NO_ERROR_NON_AUTHENTICATED;
  485. }
  486. }
  487. /* ********************************************************************** */
  488. LIBETPAN_EXPORT
  489. int mailimap_append(mailimap * session, const char * mailbox,
  490. struct mailimap_flag_list * flag_list,
  491. struct mailimap_date_time * date_time,
  492. const char * literal, size_t literal_size)
  493. {
  494. struct mailimap_response * response;
  495. int r;
  496. int error_code;
  497. struct mailimap_continue_req * cont_req;
  498. size_t indx;
  499. size_t fixed_literal_size;
  500. if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
  501. (session->imap_state != MAILIMAP_STATE_SELECTED))
  502. return MAILIMAP_ERROR_BAD_STATE;
  503. r = mailimap_send_current_tag(session);
  504. if (r != MAILIMAP_NO_ERROR)
  505. return r;
  506. fixed_literal_size = mailstream_get_data_crlf_size(literal, literal_size);
  507. r = mailimap_append_send(session->imap_stream, mailbox, flag_list, date_time,
  508. fixed_literal_size);
  509. if (r != MAILIMAP_NO_ERROR)
  510. return r;
  511. if (mailstream_flush(session->imap_stream) == -1)
  512. return MAILIMAP_ERROR_STREAM;
  513. if (mailimap_read_line(session) == NULL)
  514. return MAILIMAP_ERROR_STREAM;
  515. indx = 0;
  516. r = mailimap_continue_req_parse(session->imap_stream,
  517. session->imap_stream_buffer,
  518. &indx, &cont_req,
  519. session->imap_progr_rate, session->imap_progr_fun);
  520. if (r == MAILIMAP_NO_ERROR)
  521. mailimap_continue_req_free(cont_req);
  522. if (r == MAILIMAP_ERROR_PARSE) {
  523. r = mailimap_parse_response(session, &response);
  524. if (r != MAILIMAP_NO_ERROR)
  525. return r;
  526. mailimap_response_free(response);
  527. return MAILIMAP_ERROR_APPEND;
  528. }
  529. if (session->imap_body_progress_fun != NULL) {
  530. r = mailimap_literal_data_send_with_context(session->imap_stream, literal, literal_size,
  531. session->imap_body_progress_fun,
  532. session->imap_progress_context);
  533. }
  534. else {
  535. r = mailimap_literal_data_send(session->imap_stream, literal, literal_size,
  536. session->imap_progr_rate, session->imap_progr_fun);
  537. }
  538. if (r != MAILIMAP_NO_ERROR)
  539. return r;
  540. r = mailimap_crlf_send(session->imap_stream);
  541. if (r != MAILIMAP_NO_ERROR)
  542. return r;
  543. if (mailstream_flush(session->imap_stream) == -1)
  544. return MAILIMAP_ERROR_STREAM;
  545. if (mailimap_read_line(session) == NULL)
  546. return MAILIMAP_ERROR_STREAM;
  547. r = mailimap_parse_response(session, &response);
  548. if (r != MAILIMAP_NO_ERROR)
  549. return r;
  550. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  551. mailimap_response_free(response);
  552. switch (error_code) {
  553. case MAILIMAP_RESP_COND_STATE_OK:
  554. return MAILIMAP_NO_ERROR;
  555. default:
  556. return MAILIMAP_ERROR_APPEND;
  557. }
  558. }
  559. LIBETPAN_EXPORT
  560. int mailimap_noop(mailimap * session)
  561. {
  562. struct mailimap_response * response;
  563. int r;
  564. int error_code;
  565. r = mailimap_send_current_tag(session);
  566. if (r != MAILIMAP_NO_ERROR)
  567. return r;
  568. r = mailimap_noop_send(session->imap_stream);
  569. if (r != MAILIMAP_NO_ERROR)
  570. return r;
  571. r = mailimap_crlf_send(session->imap_stream);
  572. if (r != MAILIMAP_NO_ERROR)
  573. return r;
  574. if (mailstream_flush(session->imap_stream) == -1)
  575. return MAILIMAP_ERROR_STREAM;
  576. if (mailimap_read_line(session) == NULL)
  577. return MAILIMAP_ERROR_STREAM;
  578. r = mailimap_parse_response(session, &response);
  579. if (r != MAILIMAP_NO_ERROR)
  580. return r;
  581. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  582. mailimap_response_free(response);
  583. switch (error_code) {
  584. case MAILIMAP_RESP_COND_STATE_OK:
  585. return MAILIMAP_NO_ERROR;
  586. default:
  587. return MAILIMAP_ERROR_NOOP;
  588. }
  589. }
  590. LIBETPAN_EXPORT
  591. int mailimap_logout(mailimap * session)
  592. {
  593. struct mailimap_response * response;
  594. int r;
  595. int error_code;
  596. int res;
  597. r = mailimap_send_current_tag(session);
  598. if (r != MAILIMAP_NO_ERROR) {
  599. res = r;
  600. goto close;
  601. }
  602. r = mailimap_logout_send(session->imap_stream);
  603. if (r != MAILIMAP_NO_ERROR) {
  604. res = r;
  605. goto close;
  606. }
  607. r = mailimap_crlf_send(session->imap_stream);
  608. if (r != MAILIMAP_NO_ERROR) {
  609. res = r;
  610. goto close;
  611. }
  612. if (mailstream_flush(session->imap_stream) == -1) {
  613. res = MAILIMAP_ERROR_STREAM;
  614. goto close;
  615. }
  616. if (mailimap_read_line(session) == NULL) {
  617. res = MAILIMAP_ERROR_STREAM;
  618. goto close;
  619. }
  620. r = mailimap_parse_response(session, &response);
  621. if (r != MAILIMAP_NO_ERROR) {
  622. res = r;
  623. goto close;
  624. }
  625. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  626. mailimap_response_free(response);
  627. switch (error_code) {
  628. case MAILIMAP_RESP_COND_STATE_OK:
  629. if (session->imap_connection_info) {
  630. mailimap_connection_info_free(session->imap_connection_info);
  631. session->imap_connection_info = NULL;
  632. }
  633. res = MAILIMAP_NO_ERROR;
  634. goto close;
  635. default:
  636. res = MAILIMAP_ERROR_LOGOUT;
  637. goto close;
  638. }
  639. close:
  640. mailstream_close(session->imap_stream);
  641. session->imap_stream = NULL;
  642. session->imap_state = MAILIMAP_STATE_DISCONNECTED;
  643. return res;
  644. }
  645. /* send the results back to the caller */
  646. /* duplicate the result */
  647. static struct mailimap_capability *
  648. mailimap_capability_dup(struct mailimap_capability * orig_cap)
  649. {
  650. struct mailimap_capability * cap;
  651. char * auth_type;
  652. char * name;
  653. name = NULL;
  654. auth_type = NULL;
  655. switch (orig_cap->cap_type) {
  656. case MAILIMAP_CAPABILITY_NAME:
  657. name = strdup(orig_cap->cap_data.cap_name);
  658. if (name == NULL)
  659. goto err;
  660. break;
  661. case MAILIMAP_CAPABILITY_AUTH_TYPE:
  662. auth_type = strdup(orig_cap->cap_data.cap_auth_type);
  663. if (auth_type == NULL)
  664. goto err;
  665. break;
  666. }
  667. cap = mailimap_capability_new(orig_cap->cap_type, auth_type, name);
  668. if (cap == NULL)
  669. goto free;
  670. return cap;
  671. free:
  672. if (name != NULL)
  673. free(name);
  674. if (auth_type != NULL)
  675. free(auth_type);
  676. err:
  677. return NULL;
  678. }
  679. static struct mailimap_capability_data *
  680. mailimap_capability_data_dup(struct mailimap_capability_data * orig_cap_data)
  681. {
  682. struct mailimap_capability_data * cap_data;
  683. struct mailimap_capability * cap_dup;
  684. clist * list;
  685. clistiter * cur;
  686. int r;
  687. list = clist_new();
  688. if (list == NULL)
  689. goto err;
  690. for(cur = clist_begin(orig_cap_data->cap_list) ;
  691. cur != NULL ; cur = clist_next(cur)) {
  692. struct mailimap_capability * cap;
  693. cap = clist_content(cur);
  694. cap_dup = mailimap_capability_dup(cap);
  695. if (cap_dup == NULL)
  696. goto list;
  697. r = clist_append(list, cap_dup);
  698. if (r < 0) {
  699. mailimap_capability_free(cap_dup);
  700. goto list;
  701. }
  702. }
  703. cap_data = mailimap_capability_data_new(list);
  704. if (cap_data == NULL)
  705. goto list;
  706. return cap_data;
  707. list:
  708. clist_foreach(list, (clist_func) mailimap_capability_free, NULL);
  709. clist_free(list);
  710. err:
  711. return NULL;
  712. }
  713. LIBETPAN_EXPORT
  714. int mailimap_capability(mailimap * session,
  715. struct mailimap_capability_data ** result)
  716. {
  717. struct mailimap_response * response;
  718. int r;
  719. int error_code;
  720. struct mailimap_capability_data * cap_data;
  721. r = mailimap_send_current_tag(session);
  722. if (r != MAILIMAP_NO_ERROR)
  723. return r;
  724. r = mailimap_capability_send(session->imap_stream);
  725. if (r != MAILIMAP_NO_ERROR)
  726. return r;
  727. r = mailimap_crlf_send(session->imap_stream);
  728. if (r != MAILIMAP_NO_ERROR)
  729. return r;
  730. if (mailstream_flush(session->imap_stream) == -1)
  731. return MAILIMAP_ERROR_STREAM;
  732. if (mailimap_read_line(session) == NULL)
  733. return MAILIMAP_ERROR_STREAM;
  734. r = mailimap_parse_response(session, &response);
  735. if (r != MAILIMAP_NO_ERROR)
  736. return r;
  737. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  738. mailimap_response_free(response);
  739. switch (error_code) {
  740. case MAILIMAP_RESP_COND_STATE_OK:
  741. cap_data =
  742. mailimap_capability_data_dup(session->imap_connection_info->imap_capability);
  743. if (cap_data == NULL)
  744. return MAILIMAP_ERROR_MEMORY;
  745. * result = cap_data;
  746. return MAILIMAP_NO_ERROR;
  747. default:
  748. return MAILIMAP_ERROR_CAPABILITY;
  749. }
  750. }
  751. LIBETPAN_EXPORT
  752. int mailimap_check(mailimap * session)
  753. {
  754. struct mailimap_response * response;
  755. int r;
  756. int error_code;
  757. if (session->imap_state != MAILIMAP_STATE_SELECTED)
  758. return MAILIMAP_ERROR_BAD_STATE;
  759. r = mailimap_send_current_tag(session);
  760. if (r != MAILIMAP_NO_ERROR)
  761. return r;
  762. r = mailimap_check_send(session->imap_stream);
  763. if (r != MAILIMAP_NO_ERROR)
  764. return r;
  765. r = mailimap_crlf_send(session->imap_stream);
  766. if (r != MAILIMAP_NO_ERROR)
  767. return r;
  768. if (mailstream_flush(session->imap_stream) == -1)
  769. return MAILIMAP_ERROR_STREAM;
  770. if (mailimap_read_line(session) == NULL)
  771. return MAILIMAP_ERROR_STREAM;
  772. r = mailimap_parse_response(session, &response);
  773. if (r != MAILIMAP_NO_ERROR)
  774. return r;
  775. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  776. mailimap_response_free(response);
  777. switch (error_code) {
  778. case MAILIMAP_RESP_COND_STATE_OK:
  779. return MAILIMAP_NO_ERROR;
  780. default:
  781. return MAILIMAP_ERROR_CHECK;
  782. }
  783. }
  784. LIBETPAN_EXPORT
  785. int mailimap_close(mailimap * session)
  786. {
  787. struct mailimap_response * response;
  788. int r;
  789. int error_code;
  790. if (session->imap_state != MAILIMAP_STATE_SELECTED)
  791. return MAILIMAP_ERROR_BAD_STATE;
  792. r = mailimap_send_current_tag(session);
  793. if (r != MAILIMAP_NO_ERROR)
  794. return r;
  795. r = mailimap_close_send(session->imap_stream);
  796. if (r != MAILIMAP_NO_ERROR)
  797. return r;
  798. r = mailimap_crlf_send(session->imap_stream);
  799. if (r != MAILIMAP_NO_ERROR)
  800. return r;
  801. if (mailstream_flush(session->imap_stream) == -1)
  802. return MAILIMAP_ERROR_STREAM;
  803. if (mailimap_read_line(session) == NULL)
  804. return MAILIMAP_ERROR_STREAM;
  805. r = mailimap_parse_response(session, &response);
  806. if (r != MAILIMAP_NO_ERROR)
  807. return r;
  808. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  809. mailimap_response_free(response);
  810. switch (error_code) {
  811. case MAILIMAP_RESP_COND_STATE_OK:
  812. /* leave selected state */
  813. mailimap_selection_info_free(session->imap_selection_info);
  814. session->imap_selection_info = NULL;
  815. session->imap_state = MAILIMAP_STATE_AUTHENTICATED;
  816. return MAILIMAP_NO_ERROR;
  817. default:
  818. return MAILIMAP_ERROR_CLOSE;
  819. }
  820. }
  821. LIBETPAN_EXPORT
  822. int mailimap_expunge(mailimap * session)
  823. {
  824. struct mailimap_response * response;
  825. int r;
  826. int error_code;
  827. if (session->imap_state != MAILIMAP_STATE_SELECTED)
  828. return MAILIMAP_ERROR_BAD_STATE;
  829. r = mailimap_send_current_tag(session);
  830. if (r != MAILIMAP_NO_ERROR)
  831. return r;
  832. r = mailimap_expunge_send(session->imap_stream);
  833. if (r != MAILIMAP_NO_ERROR)
  834. return r;
  835. r = mailimap_crlf_send(session->imap_stream);
  836. if (r != MAILIMAP_NO_ERROR)
  837. return r;
  838. if (mailstream_flush(session->imap_stream) == -1)
  839. return MAILIMAP_ERROR_STREAM;
  840. if (mailimap_read_line(session) == NULL)
  841. return MAILIMAP_ERROR_STREAM;
  842. r = mailimap_parse_response(session, &response);
  843. if (r != MAILIMAP_NO_ERROR)
  844. return r;
  845. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  846. mailimap_response_free(response);
  847. switch (error_code) {
  848. case MAILIMAP_RESP_COND_STATE_OK:
  849. return MAILIMAP_NO_ERROR;
  850. default:
  851. return MAILIMAP_ERROR_EXPUNGE;
  852. }
  853. }
  854. LIBETPAN_EXPORT
  855. int mailimap_copy(mailimap * session, struct mailimap_set * set,
  856. const char * mb)
  857. {
  858. struct mailimap_response * response;
  859. int r;
  860. int error_code;
  861. if (session->imap_state != MAILIMAP_STATE_SELECTED)
  862. return MAILIMAP_ERROR_BAD_STATE;
  863. r = mailimap_send_current_tag(session);
  864. if (r != MAILIMAP_NO_ERROR)
  865. return r;
  866. r = mailimap_copy_send(session->imap_stream, set, mb);
  867. if (r != MAILIMAP_NO_ERROR)
  868. return r;
  869. r = mailimap_crlf_send(session->imap_stream);
  870. if (r != MAILIMAP_NO_ERROR)
  871. return r;
  872. if (mailstream_flush(session->imap_stream) == -1)
  873. return MAILIMAP_ERROR_STREAM;
  874. if (mailimap_read_line(session) == NULL)
  875. return MAILIMAP_ERROR_STREAM;
  876. r = mailimap_parse_response(session, &response);
  877. if (r != MAILIMAP_NO_ERROR)
  878. return r;
  879. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  880. mailimap_response_free(response);
  881. switch (error_code) {
  882. case MAILIMAP_RESP_COND_STATE_OK:
  883. return MAILIMAP_NO_ERROR;
  884. default:
  885. return MAILIMAP_ERROR_COPY;
  886. }
  887. }
  888. LIBETPAN_EXPORT
  889. int mailimap_uid_copy(mailimap * session, struct mailimap_set * set,
  890. const char * mb)
  891. {
  892. struct mailimap_response * response;
  893. int r;
  894. int error_code;
  895. if (session->imap_state != MAILIMAP_STATE_SELECTED)
  896. return MAILIMAP_ERROR_BAD_STATE;
  897. r = mailimap_send_current_tag(session);
  898. if (r != MAILIMAP_NO_ERROR)
  899. return r;
  900. r = mailimap_uid_copy_send(session->imap_stream, set, mb);
  901. if (r != MAILIMAP_NO_ERROR)
  902. return r;
  903. r = mailimap_crlf_send(session->imap_stream);
  904. if (r != MAILIMAP_NO_ERROR)
  905. return r;
  906. if (mailstream_flush(session->imap_stream) == -1)
  907. return MAILIMAP_ERROR_STREAM;
  908. if (mailimap_read_line(session) == NULL)
  909. return MAILIMAP_ERROR_STREAM;
  910. r = mailimap_parse_response(session, &response);
  911. if (r != MAILIMAP_NO_ERROR)
  912. return r;
  913. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  914. mailimap_response_free(response);
  915. switch (error_code) {
  916. case MAILIMAP_RESP_COND_STATE_OK:
  917. return MAILIMAP_NO_ERROR;
  918. default:
  919. return MAILIMAP_ERROR_UID_COPY;
  920. }
  921. }
  922. LIBETPAN_EXPORT
  923. int mailimap_create(mailimap * session, const char * mb)
  924. {
  925. struct mailimap_response * response;
  926. int r;
  927. int error_code;
  928. if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
  929. (session->imap_state != MAILIMAP_STATE_SELECTED))
  930. return MAILIMAP_ERROR_BAD_STATE;
  931. r = mailimap_send_current_tag(session);
  932. if (r != MAILIMAP_NO_ERROR)
  933. return r;
  934. r = mailimap_create_send(session->imap_stream, mb);
  935. if (r != MAILIMAP_NO_ERROR)
  936. return r;
  937. r = mailimap_crlf_send(session->imap_stream);
  938. if (r != MAILIMAP_NO_ERROR)
  939. return r;
  940. if (mailstream_flush(session->imap_stream) == -1)
  941. return MAILIMAP_ERROR_STREAM;
  942. if (mailimap_read_line(session) == NULL)
  943. return MAILIMAP_ERROR_STREAM;
  944. r = mailimap_parse_response(session, &response);
  945. if (r != MAILIMAP_NO_ERROR)
  946. return r;
  947. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  948. mailimap_response_free(response);
  949. switch (error_code) {
  950. case MAILIMAP_RESP_COND_STATE_OK:
  951. return MAILIMAP_NO_ERROR;
  952. default:
  953. return MAILIMAP_ERROR_CREATE;
  954. }
  955. }
  956. LIBETPAN_EXPORT
  957. int mailimap_delete(mailimap * session, const char * mb)
  958. {
  959. struct mailimap_response * response;
  960. int r;
  961. int error_code;
  962. if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
  963. (session->imap_state != MAILIMAP_STATE_SELECTED))
  964. return MAILIMAP_ERROR_BAD_STATE;
  965. r = mailimap_send_current_tag(session);
  966. if (r != MAILIMAP_NO_ERROR)
  967. return r;
  968. r = mailimap_delete_send(session->imap_stream, mb);
  969. if (r != MAILIMAP_NO_ERROR)
  970. return r;
  971. r = mailimap_crlf_send(session->imap_stream);
  972. if (r != MAILIMAP_NO_ERROR)
  973. return r;
  974. if (mailstream_flush(session->imap_stream) == -1)
  975. return MAILIMAP_ERROR_STREAM;
  976. if (mailimap_read_line(session) == NULL)
  977. return MAILIMAP_ERROR_STREAM;
  978. r = mailimap_parse_response(session, &response);
  979. if (r != MAILIMAP_NO_ERROR)
  980. return r;
  981. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  982. mailimap_response_free(response);
  983. switch (error_code) {
  984. case MAILIMAP_RESP_COND_STATE_OK:
  985. return MAILIMAP_NO_ERROR;
  986. default:
  987. return MAILIMAP_ERROR_DELETE;
  988. }
  989. }
  990. #if 0
  991. LIBETPAN_EXPORT
  992. int mailimap_examine(mailimap * session, const char * mb)
  993. {
  994. struct mailimap_response * response;
  995. int r;
  996. int error_code;
  997. if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
  998. (session->imap_state != MAILIMAP_STATE_SELECTED))
  999. return MAILIMAP_ERROR_BAD_STATE;
  1000. r = mailimap_send_current_tag(session);
  1001. if (r != MAILIMAP_NO_ERROR)
  1002. return r;
  1003. r = mailimap_examine_send(session->imap_stream, mb);
  1004. if (r != MAILIMAP_NO_ERROR)
  1005. return r;
  1006. r = mailimap_crlf_send(session->imap_stream);
  1007. if (r != MAILIMAP_NO_ERROR)
  1008. return r;
  1009. if (mailstream_flush(session->imap_stream) == -1)
  1010. return MAILIMAP_ERROR_STREAM;
  1011. if (mailimap_read_line(session) == NULL)
  1012. return MAILIMAP_ERROR_STREAM;
  1013. if (session->imap_selection_info != NULL)
  1014. mailimap_selection_info_free(session->imap_selection_info);
  1015. session->imap_selection_info = mailimap_selection_info_new();
  1016. r = mailimap_parse_response(session, &response);
  1017. if (r != MAILIMAP_NO_ERROR)
  1018. return r;
  1019. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  1020. mailimap_response_free(response);
  1021. switch (error_code) {
  1022. case MAILIMAP_RESP_COND_STATE_OK:
  1023. session->imap_state = MAILIMAP_STATE_SELECTED;
  1024. return MAILIMAP_NO_ERROR;
  1025. default:
  1026. mailimap_selection_info_free(session->imap_selection_info);
  1027. session->imap_selection_info = NULL;
  1028. session->imap_state = MAILIMAP_STATE_AUTHENTICATED;
  1029. return MAILIMAP_ERROR_EXAMINE;
  1030. }
  1031. }
  1032. #else
  1033. LIBETPAN_EXPORT
  1034. int mailimap_examine(mailimap * session, const char * mb)
  1035. {
  1036. uint64_t dummy;
  1037. return mailimap_examine_condstore_optional(session, mb, 0, &dummy);
  1038. }
  1039. #endif
  1040. LIBETPAN_EXPORT
  1041. int
  1042. mailimap_fetch(mailimap * session, struct mailimap_set * set,
  1043. struct mailimap_fetch_type * fetch_type, clist ** result)
  1044. {
  1045. #if 0
  1046. struct mailimap_response * response;
  1047. int r;
  1048. int error_code;
  1049. if (session->imap_state != MAILIMAP_STATE_SELECTED)
  1050. return MAILIMAP_ERROR_BAD_STATE;
  1051. r = mailimap_send_current_tag(session);
  1052. if (r != MAILIMAP_NO_ERROR)
  1053. return r;
  1054. r = mailimap_fetch_send(session->imap_stream, set, fetch_type);
  1055. if (r != MAILIMAP_NO_ERROR)
  1056. return r;
  1057. r = mailimap_crlf_send(session->imap_stream);
  1058. if (r != MAILIMAP_NO_ERROR)
  1059. return r;
  1060. if (mailstream_flush(session->imap_stream) == -1)
  1061. return MAILIMAP_ERROR_STREAM;
  1062. if (mailimap_read_line(session) == NULL)
  1063. return MAILIMAP_ERROR_STREAM;
  1064. r = mailimap_parse_response(session, &response);
  1065. if (r != MAILIMAP_NO_ERROR)
  1066. return r;
  1067. * result = session->imap_response_info->rsp_fetch_list;
  1068. session->imap_response_info->rsp_fetch_list = NULL;
  1069. if (clist_count(* result) == 0) {
  1070. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  1071. }
  1072. else {
  1073. error_code = MAILIMAP_RESP_COND_STATE_OK;
  1074. }
  1075. mailimap_response_free(response);
  1076. switch (error_code) {
  1077. case MAILIMAP_RESP_COND_STATE_OK:
  1078. return MAILIMAP_NO_ERROR;
  1079. default:
  1080. mailimap_fetch_list_free(* result);
  1081. return MAILIMAP_ERROR_FETCH;
  1082. }
  1083. #else
  1084. return mailimap_fetch_changedsince(session, set, fetch_type, 0, result);
  1085. #endif
  1086. }
  1087. LIBETPAN_EXPORT
  1088. void mailimap_fetch_list_free(clist * fetch_list)
  1089. {
  1090. clist_foreach(fetch_list, (clist_func) mailimap_msg_att_free, NULL);
  1091. clist_free(fetch_list);
  1092. }
  1093. LIBETPAN_EXPORT
  1094. int
  1095. mailimap_uid_fetch(mailimap * session,
  1096. struct mailimap_set * set,
  1097. struct mailimap_fetch_type * fetch_type, clist ** result)
  1098. {
  1099. #if 0
  1100. struct mailimap_response * response;
  1101. int r;
  1102. int error_code;
  1103. if (session->imap_state != MAILIMAP_STATE_SELECTED)
  1104. return MAILIMAP_ERROR_BAD_STATE;
  1105. r = mailimap_send_current_tag(session);
  1106. if (r != MAILIMAP_NO_ERROR)
  1107. return r;
  1108. r = mailimap_uid_fetch_send(session->imap_stream, set, fetch_type);
  1109. if (r != MAILIMAP_NO_ERROR)
  1110. return r;
  1111. r = mailimap_crlf_send(session->imap_stream);
  1112. if (r != MAILIMAP_NO_ERROR)
  1113. return r;
  1114. if (mailstream_flush(session->imap_stream) == -1)
  1115. return MAILIMAP_ERROR_STREAM;
  1116. if (mailimap_read_line(session) == NULL)
  1117. return MAILIMAP_ERROR_STREAM;
  1118. r = mailimap_parse_response(session, &response);
  1119. if (r != MAILIMAP_NO_ERROR) {
  1120. return r;
  1121. }
  1122. * result = session->imap_response_info->rsp_fetch_list;
  1123. session->imap_response_info->rsp_fetch_list = NULL;
  1124. if (clist_count(* result) == 0) {
  1125. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  1126. }
  1127. else {
  1128. error_code = MAILIMAP_RESP_COND_STATE_OK;
  1129. }
  1130. mailimap_response_free(response);
  1131. switch (error_code) {
  1132. case MAILIMAP_RESP_COND_STATE_OK:
  1133. return MAILIMAP_NO_ERROR;
  1134. default:
  1135. mailimap_fetch_list_free(* result);
  1136. * result = NULL;
  1137. return MAILIMAP_ERROR_UID_FETCH;
  1138. }
  1139. #else
  1140. return mailimap_uid_fetch_changedsince(session, set, fetch_type, 0, result);
  1141. #endif
  1142. }
  1143. LIBETPAN_EXPORT
  1144. int mailimap_list(mailimap * session, const char * mb,
  1145. const char * list_mb, clist ** result)
  1146. {
  1147. struct mailimap_response * response;
  1148. int r;
  1149. int error_code;
  1150. if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
  1151. (session->imap_state != MAILIMAP_STATE_SELECTED))
  1152. return MAILIMAP_ERROR_BAD_STATE;
  1153. r = mailimap_send_current_tag(session);
  1154. if (r != MAILIMAP_NO_ERROR)
  1155. return r;
  1156. r = mailimap_list_send(session->imap_stream, mb, list_mb);
  1157. if (r != MAILIMAP_NO_ERROR)
  1158. return r;
  1159. r = mailimap_crlf_send(session->imap_stream);
  1160. if (r != MAILIMAP_NO_ERROR)
  1161. return r;
  1162. if (mailstream_flush(session->imap_stream) == -1)
  1163. return MAILIMAP_ERROR_STREAM;
  1164. if (mailimap_read_line(session) == NULL)
  1165. return MAILIMAP_ERROR_STREAM;
  1166. r = mailimap_parse_response(session, &response);
  1167. if (r != MAILIMAP_NO_ERROR)
  1168. return r;
  1169. * result = session->imap_response_info->rsp_mailbox_list;
  1170. session->imap_response_info->rsp_mailbox_list = NULL;
  1171. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  1172. mailimap_response_free(response);
  1173. switch (error_code) {
  1174. case MAILIMAP_RESP_COND_STATE_OK:
  1175. return MAILIMAP_NO_ERROR;
  1176. default:
  1177. return MAILIMAP_ERROR_LIST;
  1178. }
  1179. }
  1180. LIBETPAN_EXPORT
  1181. int mailimap_login(mailimap * session,
  1182. const char * userid, const char * password)
  1183. {
  1184. struct mailimap_response * response;
  1185. int r;
  1186. int error_code;
  1187. if (session->imap_state != MAILIMAP_STATE_NON_AUTHENTICATED)
  1188. return MAILIMAP_ERROR_BAD_STATE;
  1189. mailstream_set_privacy(session->imap_stream, 0);
  1190. r = mailimap_send_current_tag(session);
  1191. if (r != MAILIMAP_NO_ERROR) {
  1192. mailstream_set_privacy(session->imap_stream, 1);
  1193. return r;
  1194. }
  1195. r = mailimap_login_send(session->imap_stream, userid, password);
  1196. if (r != MAILIMAP_NO_ERROR) {
  1197. mailstream_set_privacy(session->imap_stream, 1);
  1198. return r;
  1199. }
  1200. r = mailimap_crlf_send(session->imap_stream);
  1201. if (r != MAILIMAP_NO_ERROR) {
  1202. mailstream_set_privacy(session->imap_stream, 1);
  1203. return r;
  1204. }
  1205. if (mailstream_flush(session->imap_stream) == -1) {
  1206. mailstream_set_privacy(session->imap_stream, 1);
  1207. return MAILIMAP_ERROR_STREAM;
  1208. }
  1209. mailstream_set_privacy(session->imap_stream, 1);
  1210. if (mailimap_read_line(session) == NULL)
  1211. return MAILIMAP_ERROR_STREAM;
  1212. r = mailimap_parse_response(session, &response);
  1213. if (r != MAILIMAP_NO_ERROR)
  1214. return r;
  1215. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  1216. mailimap_response_free(response);
  1217. switch (error_code) {
  1218. case MAILIMAP_RESP_COND_STATE_OK:
  1219. session->imap_state = MAILIMAP_STATE_AUTHENTICATED;
  1220. return MAILIMAP_NO_ERROR;
  1221. default:
  1222. return MAILIMAP_ERROR_LOGIN;
  1223. }
  1224. }
  1225. #ifdef USE_SASL
  1226. static int sasl_getsimple(void * context, int id,
  1227. const char ** result, unsigned * len)
  1228. {
  1229. mailimap * session;
  1230. session = context;
  1231. switch (id) {
  1232. case SASL_CB_USER:
  1233. if (result != NULL)
  1234. * result = session->imap_sasl.sasl_login;
  1235. if (len != NULL)
  1236. * len = (unsigned) strlen(session->imap_sasl.sasl_login);
  1237. return SASL_OK;
  1238. case SASL_CB_AUTHNAME:
  1239. if (result != NULL)
  1240. * result = session->imap_sasl.sasl_auth_name;
  1241. if (len != NULL)
  1242. * len = (unsigned) strlen(session->imap_sasl.sasl_auth_name);
  1243. return SASL_OK;
  1244. }
  1245. return SASL_FAIL;
  1246. }
  1247. static int sasl_getsecret(sasl_conn_t * conn, void * context, int id,
  1248. sasl_secret_t ** psecret)
  1249. {
  1250. mailimap * session;
  1251. session = context;
  1252. switch (id) {
  1253. case SASL_CB_PASS:
  1254. if (psecret != NULL)
  1255. * psecret = session->imap_sasl.sasl_secret;
  1256. return SASL_OK;
  1257. }
  1258. return SASL_FAIL;
  1259. }
  1260. static int sasl_getrealm(void * context, int id,
  1261. const char ** availrealms,
  1262. const char ** result)
  1263. {
  1264. mailimap * session;
  1265. session = context;
  1266. switch (id) {
  1267. case SASL_CB_GETREALM:
  1268. if (result != NULL)
  1269. * result = session->imap_sasl.sasl_realm;
  1270. return SASL_OK;
  1271. }
  1272. return SASL_FAIL;
  1273. }
  1274. #endif
  1275. LIBETPAN_EXPORT
  1276. int mailimap_authenticate(mailimap * session, const char * auth_type,
  1277. const char * server_fqdn,
  1278. const char * local_ip_port,
  1279. const char * remote_ip_port,
  1280. const char * login, const char * auth_name,
  1281. const char * password, const char * realm)
  1282. {
  1283. #ifdef USE_SASL
  1284. struct mailimap_response * response;
  1285. int r;
  1286. int error_code;
  1287. size_t indx;
  1288. sasl_callback_t sasl_callback[5];
  1289. const char * sasl_out;
  1290. unsigned sasl_out_len;
  1291. const char * mechusing;
  1292. sasl_secret_t * secret;
  1293. int res;
  1294. size_t len;
  1295. if (session->imap_state != MAILIMAP_STATE_NON_AUTHENTICATED) {
  1296. res = MAILIMAP_ERROR_BAD_STATE;
  1297. goto err;
  1298. }
  1299. sasl_callback[0].id = SASL_CB_GETREALM;
  1300. sasl_callback[0].proc = (int(*)(void)) sasl_getrealm;
  1301. sasl_callback[0].context = session;
  1302. sasl_callback[1].id = SASL_CB_USER;
  1303. sasl_callback[1].proc = (int(*)(void)) sasl_getsimple;
  1304. sasl_callback[1].context = session;
  1305. sasl_callback[2].id = SASL_CB_AUTHNAME;
  1306. sasl_callback[2].proc = (int(*)(void)) sasl_getsimple;
  1307. sasl_callback[2].context = session;
  1308. sasl_callback[3].id = SASL_CB_PASS;
  1309. sasl_callback[3].proc = (int(*)(void)) sasl_getsecret;
  1310. sasl_callback[3].context = session;
  1311. sasl_callback[4].id = SASL_CB_LIST_END;
  1312. sasl_callback[4].proc = NULL;
  1313. sasl_callback[4].context = NULL;
  1314. len = strlen(password);
  1315. secret = malloc(sizeof(* secret) + len);
  1316. if (secret == NULL) {
  1317. res = MAILIMAP_ERROR_MEMORY;
  1318. goto err;
  1319. }
  1320. secret->len = len;
  1321. memcpy(secret->data, password, len + 1);
  1322. session->imap_sasl.sasl_server_fqdn = server_fqdn;
  1323. session->imap_sasl.sasl_login = login;
  1324. session->imap_sasl.sasl_auth_name = auth_name;
  1325. session->imap_sasl.sasl_password = password;
  1326. session->imap_sasl.sasl_realm = realm;
  1327. session->imap_sasl.sasl_secret = secret;
  1328. /* init SASL */
  1329. if (session->imap_sasl.sasl_conn != NULL) {
  1330. sasl_dispose((sasl_conn_t **) &session->imap_sasl.sasl_conn);
  1331. session->imap_sasl.sasl_conn = NULL;
  1332. }
  1333. else {
  1334. mailsasl_ref();
  1335. }
  1336. r = sasl_client_new("imap", server_fqdn,
  1337. local_ip_port, remote_ip_port, sasl_callback, 0,
  1338. (sasl_conn_t **) &session->imap_sasl.sasl_conn);
  1339. if (r != SASL_OK) {
  1340. res = MAILIMAP_ERROR_LOGIN;
  1341. goto free_secret;
  1342. }
  1343. r = sasl_client_start(session->imap_sasl.sasl_conn,
  1344. auth_type, NULL, &sasl_out, &sasl_out_len, &mechusing);
  1345. if ((r != SASL_CONTINUE) && (r != SASL_OK)) {
  1346. res = MAILIMAP_ERROR_LOGIN;
  1347. goto free_sasl_conn;
  1348. }
  1349. mailstream_set_privacy(session->imap_stream, 0);
  1350. r = mailimap_send_current_tag(session);
  1351. if (r != MAILIMAP_NO_ERROR) {
  1352. res = r;
  1353. goto free_sasl_conn;
  1354. }
  1355. r = mailimap_authenticate_send(session->imap_stream, auth_type);
  1356. if (r != MAILIMAP_NO_ERROR) {
  1357. res = r;
  1358. goto free_sasl_conn;
  1359. }
  1360. r = mailimap_crlf_send(session->imap_stream);
  1361. if (r != MAILIMAP_NO_ERROR) {
  1362. res = r;
  1363. goto free_sasl_conn;
  1364. }
  1365. if (mailstream_flush(session->imap_stream) == -1) {
  1366. res = MAILIMAP_ERROR_STREAM;
  1367. goto free_sasl_conn;
  1368. }
  1369. while (1) {
  1370. struct mailimap_continue_req * cont_req;
  1371. char * response_base64;
  1372. int got_response;
  1373. char * encoded;
  1374. unsigned int encoded_len;
  1375. unsigned int max_encoded;
  1376. if (mailimap_read_line(session) == NULL) {
  1377. res = MAILIMAP_ERROR_STREAM;
  1378. goto free_sasl_conn;
  1379. }
  1380. indx = 0;
  1381. r = mailimap_continue_req_parse(session->imap_stream,
  1382. session->imap_stream_buffer,
  1383. &indx, &cont_req,
  1384. session->imap_progr_rate, session->imap_progr_fun);
  1385. if (r != MAILIMAP_NO_ERROR)
  1386. break;
  1387. got_response = 1;
  1388. if (cont_req->cr_type == MAILIMAP_CONTINUE_REQ_BASE64) {
  1389. response_base64 = cont_req->cr_data.cr_base64;
  1390. if (* response_base64 == '\0')
  1391. got_response = 0;
  1392. }
  1393. else {
  1394. response_base64 = "";
  1395. got_response = 0;
  1396. }
  1397. if (got_response) {
  1398. unsigned int response_len;
  1399. char * decoded;
  1400. unsigned int decoded_len;
  1401. unsigned int max_decoded;
  1402. response_len = (unsigned int) strlen(response_base64);
  1403. max_decoded = response_len * 3 / 4;
  1404. decoded = malloc(max_decoded + 1);
  1405. if (decoded == NULL) {
  1406. mailimap_continue_req_free(cont_req);
  1407. res = MAILIMAP_ERROR_MEMORY;
  1408. goto free_sasl_conn;
  1409. }
  1410. r = sasl_decode64(response_base64, response_len,
  1411. decoded, max_decoded + 1, &decoded_len);
  1412. mailimap_continue_req_free(cont_req);
  1413. if (r != SASL_OK) {
  1414. free(decoded);
  1415. res = MAILIMAP_ERROR_MEMORY;
  1416. goto free_sasl_conn;
  1417. }
  1418. r = sasl_client_step(session->imap_sasl.sasl_conn,
  1419. decoded, decoded_len, NULL, &sasl_out, &sasl_out_len);
  1420. free(decoded);
  1421. if ((r != SASL_CONTINUE) && (r != SASL_OK)) {
  1422. res = MAILIMAP_ERROR_LOGIN;
  1423. goto free_sasl_conn;
  1424. }
  1425. }
  1426. else {
  1427. mailimap_continue_req_free(cont_req);
  1428. }
  1429. max_encoded = ((sasl_out_len + 2) / 3) * 4;
  1430. encoded = malloc(max_encoded + 1);
  1431. if (encoded == NULL) {
  1432. res = MAILIMAP_ERROR_MEMORY;
  1433. goto free_sasl_conn;
  1434. }
  1435. r = sasl_encode64(sasl_out, sasl_out_len,
  1436. encoded, max_encoded + 1, &encoded_len);
  1437. if (r != SASL_OK) {
  1438. free(encoded);
  1439. res = MAILIMAP_ERROR_MEMORY;
  1440. goto free_sasl_conn;
  1441. }
  1442. r = mailimap_token_send(session->imap_stream, encoded);
  1443. free(encoded);
  1444. if (r != MAILIMAP_NO_ERROR) {
  1445. res = r;
  1446. goto free_sasl_conn;
  1447. }
  1448. r = mailimap_crlf_send(session->imap_stream);
  1449. if (r != MAILIMAP_NO_ERROR) {
  1450. res = r;
  1451. goto free_sasl_conn;
  1452. }
  1453. if (mailstream_flush(session->imap_stream) == -1) {
  1454. res = MAILIMAP_ERROR_STREAM;
  1455. goto free_sasl_conn;
  1456. }
  1457. }
  1458. free(session->imap_sasl.sasl_secret);
  1459. session->imap_sasl.sasl_secret = NULL;
  1460. r = mailimap_parse_response(session, &response);
  1461. if (r != MAILIMAP_NO_ERROR) {
  1462. res = r;
  1463. goto free_sasl_conn;
  1464. }
  1465. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  1466. mailimap_response_free(response);
  1467. switch (error_code) {
  1468. case MAILIMAP_RESP_COND_STATE_OK:
  1469. session->imap_state = MAILIMAP_STATE_AUTHENTICATED;
  1470. res = MAILIMAP_NO_ERROR;
  1471. goto free_sasl_conn;
  1472. default:
  1473. res = MAILIMAP_ERROR_LOGIN;
  1474. goto free_sasl_conn;
  1475. }
  1476. free_sasl_conn:
  1477. mailstream_set_privacy(session->imap_stream, 1);
  1478. sasl_dispose((sasl_conn_t **) &session->imap_sasl.sasl_conn);
  1479. session->imap_sasl.sasl_conn = NULL;
  1480. mailsasl_unref();
  1481. free_secret:
  1482. free(session->imap_sasl.sasl_secret);
  1483. session->imap_sasl.sasl_secret = NULL;
  1484. err:
  1485. return res;
  1486. #else
  1487. return MAILIMAP_ERROR_LOGIN;
  1488. #endif
  1489. }
  1490. LIBETPAN_EXPORT
  1491. int mailimap_lsub(mailimap * session, const char * mb,
  1492. const char * list_mb, clist ** result)
  1493. {
  1494. struct mailimap_response * response;
  1495. int r;
  1496. int error_code;
  1497. if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
  1498. (session->imap_state != MAILIMAP_STATE_SELECTED))
  1499. return MAILIMAP_ERROR_BAD_STATE;
  1500. r = mailimap_send_current_tag(session);
  1501. if (r != MAILIMAP_NO_ERROR)
  1502. return r;
  1503. r = mailimap_lsub_send(session->imap_stream, mb, list_mb);
  1504. if (r != MAILIMAP_NO_ERROR)
  1505. return r;
  1506. r = mailimap_crlf_send(session->imap_stream);
  1507. if (r != MAILIMAP_NO_ERROR)
  1508. return r;
  1509. if (mailstream_flush(session->imap_stream) == -1)
  1510. return MAILIMAP_ERROR_STREAM;
  1511. if (mailimap_read_line(session) == NULL)
  1512. return MAILIMAP_ERROR_STREAM;
  1513. r = mailimap_parse_response(session, &response);
  1514. if (r != MAILIMAP_NO_ERROR)
  1515. return r;
  1516. * result = session->imap_response_info->rsp_mailbox_lsub;
  1517. session->imap_response_info->rsp_mailbox_lsub = NULL;
  1518. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  1519. mailimap_response_free(response);
  1520. switch (error_code) {
  1521. case MAILIMAP_RESP_COND_STATE_OK:
  1522. return MAILIMAP_NO_ERROR;
  1523. default:
  1524. return MAILIMAP_ERROR_LSUB;
  1525. }
  1526. }
  1527. LIBETPAN_EXPORT
  1528. void mailimap_list_result_free(clist * list)
  1529. {
  1530. clist_foreach(list, (clist_func) mailimap_mailbox_list_free, NULL);
  1531. clist_free(list);
  1532. }
  1533. LIBETPAN_EXPORT
  1534. int mailimap_rename(mailimap * session,
  1535. const char * mb, const char * new_name)
  1536. {
  1537. struct mailimap_response * response;
  1538. int r;
  1539. int error_code;
  1540. if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
  1541. (session->imap_state != MAILIMAP_STATE_SELECTED))
  1542. return MAILIMAP_ERROR_BAD_STATE;
  1543. r = mailimap_send_current_tag(session);
  1544. if (r != MAILIMAP_NO_ERROR)
  1545. return r;
  1546. r = mailimap_rename_send(session->imap_stream, mb, new_name);
  1547. if (r != MAILIMAP_NO_ERROR)
  1548. return r;
  1549. if (!mailimap_crlf_send(session->imap_stream))
  1550. if (r != MAILIMAP_NO_ERROR)
  1551. return r;
  1552. if (mailstream_flush(session->imap_stream) == -1)
  1553. return MAILIMAP_ERROR_STREAM;
  1554. if (mailimap_read_line(session) == NULL)
  1555. return MAILIMAP_ERROR_STREAM;
  1556. r = mailimap_parse_response(session, &response);
  1557. if (r != MAILIMAP_NO_ERROR)
  1558. return r;
  1559. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  1560. mailimap_response_free(response);
  1561. switch (error_code) {
  1562. case MAILIMAP_RESP_COND_STATE_OK:
  1563. return MAILIMAP_NO_ERROR;
  1564. default:
  1565. return MAILIMAP_ERROR_RENAME;
  1566. }
  1567. }
  1568. LIBETPAN_EXPORT
  1569. int
  1570. mailimap_search(mailimap * session, const char * charset,
  1571. struct mailimap_search_key * key, clist ** result)
  1572. {
  1573. return mailimap_search_modseq(session, charset, key, result, NULL);
  1574. }
  1575. LIBETPAN_EXPORT
  1576. int
  1577. mailimap_uid_search(mailimap * session, const char * charset,
  1578. struct mailimap_search_key * key, clist ** result)
  1579. {
  1580. return mailimap_uid_search_modseq(session, charset, key, result, NULL);
  1581. }
  1582. LIBETPAN_EXPORT int mailimap_search_literalplus(mailimap * session, const char * charset,
  1583. struct mailimap_search_key * key, clist ** result)
  1584. {
  1585. return mailimap_search_literalplus_modseq(session, charset, key, result, NULL);
  1586. }
  1587. LIBETPAN_EXPORT int mailimap_uid_search_literalplus(mailimap * session, const char * charset,
  1588. struct mailimap_search_key * key, clist ** result)
  1589. {
  1590. return mailimap_uid_search_literalplus_modseq(session, charset, key, result, NULL);
  1591. }
  1592. LIBETPAN_EXPORT
  1593. void mailimap_search_result_free(clist * search_result)
  1594. {
  1595. clist_foreach(search_result, (clist_func) free, NULL);
  1596. clist_free(search_result);
  1597. }
  1598. LIBETPAN_EXPORT
  1599. int
  1600. mailimap_select(mailimap * session, const char * mb)
  1601. {
  1602. uint64_t dummy;
  1603. return mailimap_select_condstore_optional(session, mb, 0, &dummy);
  1604. }
  1605. LIBETPAN_EXPORT
  1606. int
  1607. mailimap_status(mailimap * session, const char * mb,
  1608. struct mailimap_status_att_list * status_att_list,
  1609. struct mailimap_mailbox_data_status ** result)
  1610. {
  1611. struct mailimap_response * response;
  1612. int r;
  1613. int error_code;
  1614. if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
  1615. (session->imap_state != MAILIMAP_STATE_SELECTED))
  1616. return MAILIMAP_ERROR_BAD_STATE;
  1617. r = mailimap_send_current_tag(session);
  1618. if (r != MAILIMAP_NO_ERROR)
  1619. return r;
  1620. r = mailimap_status_send(session->imap_stream, mb, status_att_list);
  1621. if (r != MAILIMAP_NO_ERROR)
  1622. return r;
  1623. r = mailimap_crlf_send(session->imap_stream);
  1624. if (r != MAILIMAP_NO_ERROR)
  1625. return r;
  1626. if (mailstream_flush(session->imap_stream) == -1)
  1627. return MAILIMAP_ERROR_STREAM;
  1628. if (mailimap_read_line(session) == NULL)
  1629. return MAILIMAP_ERROR_STREAM;
  1630. r = mailimap_parse_response(session, &response);
  1631. if (r != MAILIMAP_NO_ERROR)
  1632. return r;
  1633. * result = session->imap_response_info->rsp_status;
  1634. session->imap_response_info->rsp_status = NULL;
  1635. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  1636. mailimap_response_free(response);
  1637. switch (error_code) {
  1638. case MAILIMAP_RESP_COND_STATE_OK:
  1639. return MAILIMAP_NO_ERROR;
  1640. default:
  1641. return MAILIMAP_ERROR_STATUS;
  1642. }
  1643. }
  1644. LIBETPAN_EXPORT
  1645. int
  1646. mailimap_store(mailimap * session,
  1647. struct mailimap_set * set,
  1648. struct mailimap_store_att_flags * store_att_flags)
  1649. {
  1650. #if 0
  1651. struct mailimap_response * response;
  1652. int r;
  1653. int error_code;
  1654. if (session->imap_state != MAILIMAP_STATE_SELECTED)
  1655. return MAILIMAP_ERROR_BAD_STATE;
  1656. r = mailimap_send_current_tag(session);
  1657. if (r != MAILIMAP_NO_ERROR)
  1658. return r;
  1659. r = mailimap_store_send(session->imap_stream, set, store_att_flags);
  1660. if (r != MAILIMAP_NO_ERROR)
  1661. return r;
  1662. r = mailimap_crlf_send(session->imap_stream);
  1663. if (r != MAILIMAP_NO_ERROR)
  1664. return r;
  1665. if (mailstream_flush(session->imap_stream) == -1)
  1666. return MAILIMAP_ERROR_STREAM;
  1667. if (mailimap_read_line(session) == NULL)
  1668. return MAILIMAP_ERROR_STREAM;
  1669. r = mailimap_parse_response(session, &response);
  1670. if (r != MAILIMAP_NO_ERROR)
  1671. return r;
  1672. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  1673. mailimap_response_free(response);
  1674. switch (error_code) {
  1675. case MAILIMAP_RESP_COND_STATE_OK:
  1676. return MAILIMAP_NO_ERROR;
  1677. default:
  1678. return MAILIMAP_ERROR_STORE;
  1679. }
  1680. #else
  1681. return mailimap_store_unchangedsince_optional(session,
  1682. set, 0, 0, store_att_flags);
  1683. #endif
  1684. }
  1685. LIBETPAN_EXPORT
  1686. int
  1687. mailimap_uid_store(mailimap * session,
  1688. struct mailimap_set * set,
  1689. struct mailimap_store_att_flags * store_att_flags)
  1690. {
  1691. #if 0
  1692. struct mailimap_response * response;
  1693. int r;
  1694. int error_code;
  1695. if (session->imap_state != MAILIMAP_STATE_SELECTED)
  1696. return MAILIMAP_ERROR_BAD_STATE;
  1697. r = mailimap_send_current_tag(session);
  1698. if (r != MAILIMAP_NO_ERROR)
  1699. return r;
  1700. r = mailimap_uid_store_send(session->imap_stream, set, store_att_flags);
  1701. if (r != MAILIMAP_NO_ERROR)
  1702. return r;
  1703. r = mailimap_crlf_send(session->imap_stream);
  1704. if (r != MAILIMAP_NO_ERROR)
  1705. return r;
  1706. if (mailstream_flush(session->imap_stream) == -1)
  1707. return MAILIMAP_ERROR_STREAM;
  1708. if (mailimap_read_line(session) == NULL)
  1709. return MAILIMAP_ERROR_STREAM;
  1710. r = mailimap_parse_response(session, &response);
  1711. if (r != MAILIMAP_NO_ERROR)
  1712. return r;
  1713. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  1714. mailimap_response_free(response);
  1715. switch (error_code) {
  1716. case MAILIMAP_RESP_COND_STATE_OK:
  1717. return MAILIMAP_NO_ERROR;
  1718. default:
  1719. return MAILIMAP_ERROR_UID_STORE;
  1720. }
  1721. #else
  1722. return mailimap_uid_store_unchangedsince_optional(session,
  1723. set, 0, 0, store_att_flags);
  1724. #endif
  1725. }
  1726. LIBETPAN_EXPORT
  1727. int mailimap_subscribe(mailimap * session, const char * mb)
  1728. {
  1729. struct mailimap_response * response;
  1730. int r;
  1731. int error_code;
  1732. if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
  1733. (session->imap_state != MAILIMAP_STATE_SELECTED))
  1734. return MAILIMAP_ERROR_BAD_STATE;
  1735. r = mailimap_send_current_tag(session);
  1736. if (r != MAILIMAP_NO_ERROR)
  1737. return r;
  1738. r = mailimap_subscribe_send(session->imap_stream, mb);
  1739. if (r != MAILIMAP_NO_ERROR)
  1740. return r;
  1741. r = mailimap_crlf_send(session->imap_stream);
  1742. if (r != MAILIMAP_NO_ERROR)
  1743. return r;
  1744. if (mailstream_flush(session->imap_stream) == -1)
  1745. return MAILIMAP_ERROR_STREAM;
  1746. if (mailimap_read_line(session) == NULL)
  1747. return MAILIMAP_ERROR_STREAM;
  1748. r = mailimap_parse_response(session, &response);
  1749. if (r != MAILIMAP_NO_ERROR)
  1750. return r;
  1751. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  1752. mailimap_response_free(response);
  1753. switch (error_code) {
  1754. case MAILIMAP_RESP_COND_STATE_OK:
  1755. return MAILIMAP_NO_ERROR;
  1756. default:
  1757. return MAILIMAP_ERROR_SUBSCRIBE;
  1758. }
  1759. }
  1760. LIBETPAN_EXPORT
  1761. int mailimap_unsubscribe(mailimap * session, const char * mb)
  1762. {
  1763. struct mailimap_response * response;
  1764. int r;
  1765. int error_code;
  1766. if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
  1767. (session->imap_state != MAILIMAP_STATE_SELECTED))
  1768. return MAILIMAP_ERROR_BAD_STATE;
  1769. r = mailimap_send_current_tag(session);
  1770. if (r != MAILIMAP_NO_ERROR)
  1771. return r;
  1772. r = mailimap_unsubscribe_send(session->imap_stream, mb);
  1773. if (r != MAILIMAP_NO_ERROR)
  1774. return r;
  1775. r = mailimap_crlf_send(session->imap_stream);
  1776. if (r != MAILIMAP_NO_ERROR)
  1777. return r;
  1778. if (mailstream_flush(session->imap_stream) == -1)
  1779. return MAILIMAP_ERROR_STREAM;
  1780. if (mailimap_read_line(session) == NULL)
  1781. return MAILIMAP_ERROR_STREAM;
  1782. r = mailimap_parse_response(session, &response);
  1783. if (r != MAILIMAP_NO_ERROR)
  1784. return r;
  1785. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  1786. mailimap_response_free(response);
  1787. switch (error_code) {
  1788. case MAILIMAP_RESP_COND_STATE_OK:
  1789. return MAILIMAP_NO_ERROR;
  1790. default:
  1791. return MAILIMAP_ERROR_UNSUBSCRIBE;
  1792. }
  1793. }
  1794. LIBETPAN_EXPORT
  1795. int mailimap_starttls(mailimap * session)
  1796. {
  1797. struct mailimap_response * response;
  1798. int r;
  1799. int error_code;
  1800. r = mailimap_send_current_tag(session);
  1801. if (r != MAILIMAP_NO_ERROR)
  1802. return r;
  1803. r = mailimap_starttls_send(session->imap_stream);
  1804. if (r != MAILIMAP_NO_ERROR)
  1805. return r;
  1806. r = mailimap_crlf_send(session->imap_stream);
  1807. if (r != MAILIMAP_NO_ERROR)
  1808. return r;
  1809. if (mailstream_flush(session->imap_stream) == -1)
  1810. return MAILIMAP_ERROR_STREAM;
  1811. if (mailimap_read_line(session) == NULL)
  1812. return MAILIMAP_ERROR_STREAM;
  1813. r = mailimap_parse_response(session, &response);
  1814. if (r != MAILIMAP_NO_ERROR)
  1815. return r;
  1816. error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
  1817. mailimap_response_free(response);
  1818. switch (error_code) {
  1819. case MAILIMAP_RESP_COND_STATE_OK:
  1820. return MAILIMAP_NO_ERROR;
  1821. default:
  1822. return MAILIMAP_ERROR_STARTTLS;
  1823. }
  1824. }
  1825. char * mailimap_read_line(mailimap * session)
  1826. {
  1827. return mailstream_read_line(session->imap_stream, session->imap_stream_buffer);
  1828. }
  1829. int mailimap_send_current_tag(mailimap * session)
  1830. {
  1831. char tag_str[15];
  1832. int r;
  1833. session->imap_tag ++;
  1834. if(mailimap_is_163_workaround_enabled(session))
  1835. snprintf(tag_str, 15, "C%i", session->imap_tag);
  1836. else
  1837. snprintf(tag_str, 15, "%i", session->imap_tag);
  1838. r = mailimap_tag_send(session->imap_stream, tag_str);
  1839. if (r != MAILIMAP_NO_ERROR)
  1840. return r;
  1841. r = mailimap_space_send(session->imap_stream);
  1842. if (r != MAILIMAP_NO_ERROR)
  1843. return r;
  1844. return MAILIMAP_NO_ERROR;
  1845. }
  1846. int mailimap_parse_response(mailimap * session,
  1847. struct mailimap_response ** result)
  1848. {
  1849. size_t indx;
  1850. struct mailimap_response * response;
  1851. char tag_str[15];
  1852. int r;
  1853. indx = 0;
  1854. session->imap_response = NULL;
  1855. if (session->imap_stream_buffer->allocated_len > 128 * 1024) {
  1856. MMAPString * buffer;
  1857. buffer = mmap_string_new_len(session->imap_stream_buffer->str, session->imap_stream_buffer->len);
  1858. mmap_string_free(session->imap_stream_buffer);
  1859. session->imap_stream_buffer = buffer;
  1860. }
  1861. if ((session->imap_body_progress_fun != NULL) ||
  1862. (session->imap_items_progress_fun != NULL)) {
  1863. r = mailimap_response_parse_with_context(session->imap_stream,
  1864. session->imap_stream_buffer,
  1865. &indx, &response,
  1866. session->imap_body_progress_fun,
  1867. session->imap_items_progress_fun,
  1868. session->imap_progress_context,
  1869. session->imap_msg_att_handler,
  1870. session->imap_msg_att_handler_context);
  1871. }
  1872. else {
  1873. r = mailimap_response_parse(session->imap_stream,
  1874. session->imap_stream_buffer,
  1875. &indx, &response,
  1876. session->imap_progr_rate, session->imap_progr_fun);
  1877. }
  1878. if (r != MAILIMAP_NO_ERROR)
  1879. return r;
  1880. #if 0
  1881. mailimap_response_print(response);
  1882. #endif
  1883. response_store(session, response);
  1884. if (response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_text->rsp_text != NULL) {
  1885. if (mmap_string_assign(session->imap_response_buffer,
  1886. response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_text->rsp_text)
  1887. == NULL) {
  1888. mailimap_response_free(response);
  1889. return MAILIMAP_ERROR_MEMORY;
  1890. }
  1891. }
  1892. session->imap_response = session->imap_response_buffer->str;
  1893. if (response->rsp_resp_done->rsp_type == MAILIMAP_RESP_DONE_TYPE_FATAL) {
  1894. mailimap_response_free(response);
  1895. return MAILIMAP_ERROR_FATAL;
  1896. }
  1897. snprintf(tag_str, 15, "%i", session->imap_tag);
  1898. if (strcmp(response->rsp_resp_done->rsp_data.rsp_tagged->rsp_tag, tag_str) != 0) {
  1899. mailimap_response_free(response);
  1900. return MAILIMAP_ERROR_PROTOCOL;
  1901. }
  1902. if (response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type ==
  1903. MAILIMAP_RESP_COND_STATE_BAD) {
  1904. mailimap_response_free(response);
  1905. return MAILIMAP_ERROR_PROTOCOL;
  1906. }
  1907. * result = response;
  1908. return MAILIMAP_NO_ERROR;
  1909. }
  1910. static int parse_greeting(mailimap * session,
  1911. struct mailimap_greeting ** result)
  1912. {
  1913. size_t indx;
  1914. struct mailimap_greeting * greeting;
  1915. int r;
  1916. indx = 0;
  1917. session->imap_response = NULL;
  1918. r = mailimap_greeting_parse(session->imap_stream,
  1919. session->imap_stream_buffer,
  1920. &indx, &greeting, session->imap_progr_rate,
  1921. session->imap_progr_fun);
  1922. if (r != MAILIMAP_NO_ERROR)
  1923. return r;
  1924. #if 0
  1925. mailimap_greeting_print(greeting);
  1926. #endif
  1927. greeting_store(session, greeting);
  1928. if (greeting->gr_type == MAILIMAP_GREETING_RESP_COND_BYE) {
  1929. if (greeting->gr_data.gr_bye->rsp_text->rsp_text != NULL) {
  1930. if (mmap_string_assign(session->imap_response_buffer,
  1931. greeting->gr_data.gr_bye->rsp_text->rsp_text) == NULL)
  1932. return MAILIMAP_ERROR_MEMORY;
  1933. }
  1934. session->imap_response = session->imap_response_buffer->str;
  1935. return MAILIMAP_ERROR_DONT_ACCEPT_CONNECTION;
  1936. }
  1937. if (greeting->gr_data.gr_auth->rsp_text->rsp_text != NULL) {
  1938. if (mmap_string_assign(session->imap_response_buffer,
  1939. greeting->gr_data.gr_auth->rsp_text->rsp_text) == NULL)
  1940. return MAILIMAP_ERROR_MEMORY;
  1941. }
  1942. session->imap_response = session->imap_response_buffer->str;
  1943. * result = greeting;
  1944. return MAILIMAP_NO_ERROR;
  1945. }
  1946. LIBETPAN_EXPORT
  1947. mailimap * mailimap_new(size_t imap_progr_rate,
  1948. progress_function * imap_progr_fun)
  1949. {
  1950. mailimap * f;
  1951. f = malloc(sizeof(* f));
  1952. if (f == NULL)
  1953. goto err;
  1954. f->imap_response = NULL;
  1955. f->imap_stream = NULL;
  1956. f->imap_progr_rate = imap_progr_rate;
  1957. f->imap_progr_fun = imap_progr_fun;
  1958. f->imap_stream_buffer = mmap_string_new("");
  1959. if (f->imap_stream_buffer == NULL)
  1960. goto free_f;
  1961. f->imap_response_buffer = mmap_string_new("");
  1962. if (f->imap_response_buffer == NULL)
  1963. goto free_stream_buffer;
  1964. f->imap_state = MAILIMAP_STATE_DISCONNECTED;
  1965. f->imap_tag = 0;
  1966. f->imap_selection_info = NULL;
  1967. f->imap_response_info = NULL;
  1968. f->imap_connection_info = NULL;
  1969. #ifdef USE_SASL
  1970. f->imap_sasl.sasl_conn = NULL;
  1971. #endif
  1972. f->imap_idle_timestamp = 0;
  1973. f->imap_idle_maxdelay = 29 * 60; /* IMAP IDLE spec */
  1974. f->imap_body_progress_fun = NULL;
  1975. f->imap_items_progress_fun = NULL;
  1976. f->imap_progress_context = NULL;
  1977. f->imap_msg_att_handler = NULL;
  1978. f->imap_msg_att_handler_context = NULL;
  1979. f->imap_timeout = 0;
  1980. f->imap_logger = NULL;
  1981. f->imap_logger_context = NULL;
  1982. f->is_163_workaround_enabled = 0;
  1983. return f;
  1984. free_stream_buffer:
  1985. mmap_string_free(f->imap_stream_buffer);
  1986. free_f:
  1987. free(f);
  1988. err:
  1989. return NULL;
  1990. }
  1991. LIBETPAN_EXPORT
  1992. void mailimap_free(mailimap * session)
  1993. {
  1994. #ifdef USE_SASL
  1995. if (session->imap_sasl.sasl_conn != NULL) {
  1996. sasl_dispose((sasl_conn_t **) &session->imap_sasl.sasl_conn);
  1997. mailsasl_unref();
  1998. }
  1999. #endif
  2000. if (session->imap_stream)
  2001. mailimap_logout(session);
  2002. mmap_string_free(session->imap_response_buffer);
  2003. mmap_string_free(session->imap_stream_buffer);
  2004. if (session->imap_response_info)
  2005. mailimap_response_info_free(session->imap_response_info);
  2006. if (session->imap_selection_info)
  2007. mailimap_selection_info_free(session->imap_selection_info);
  2008. if (session->imap_connection_info)
  2009. mailimap_connection_info_free(session->imap_connection_info);
  2010. free(session);
  2011. }
  2012. LIBETPAN_EXPORT
  2013. void mailimap_set_timeout(mailimap * session, time_t timeout)
  2014. {
  2015. session->imap_timeout = timeout;
  2016. }
  2017. LIBETPAN_EXPORT
  2018. time_t mailimap_get_timeout(mailimap * session)
  2019. {
  2020. return session->imap_timeout;
  2021. }
  2022. LIBETPAN_EXPORT
  2023. void mailimap_set_progress_callback(mailimap * session,
  2024. mailprogress_function * body_progr_fun,
  2025. mailprogress_function * items_progr_fun,
  2026. void * context)
  2027. {
  2028. session->imap_body_progress_fun = body_progr_fun;
  2029. session->imap_items_progress_fun = items_progr_fun;
  2030. session->imap_progress_context = context;
  2031. }
  2032. LIBETPAN_EXPORT
  2033. void mailimap_set_msg_att_handler(mailimap * session,
  2034. mailimap_msg_att_handler * handler,
  2035. void * context)
  2036. {
  2037. session->imap_msg_att_handler = handler;
  2038. session->imap_msg_att_handler_context = context;
  2039. }
  2040. static inline void imap_logger(mailstream * s, int log_type,
  2041. const char * str, size_t size, void * context)
  2042. {
  2043. mailimap * session;
  2044. session = context;
  2045. if (session->imap_logger == NULL)
  2046. return;
  2047. session->imap_logger(session, log_type, str, size, session->imap_logger_context);
  2048. }
  2049. LIBETPAN_EXPORT
  2050. void mailimap_set_logger(mailimap * session, void (* logger)(mailimap * session, int log_type,
  2051. const char * str, size_t size, void * context), void * logger_context)
  2052. {
  2053. session->imap_logger = logger;
  2054. session->imap_logger_context = logger_context;
  2055. }
  2056. LIBETPAN_EXPORT
  2057. void mailimap_set_163_workaround_enabled(mailimap * session, int enabled) {
  2058. imap->is_163_workaround_enabled = enabled;
  2059. }
  2060. LIBETPAN_EXPORT
  2061. int mailimap_is_163_workaround_enabled(mailimap * session) {
  2062. return imap->is_163_workaround_enabled;
  2063. }