1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011-2021 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #include <config.h>
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <mailutils/errno.h>
23 #include <mailutils/msgset.h>
24 #include <mailutils/nls.h>
25 #include <mailutils/imap.h>
26 #include <mailutils/sys/imap.h>
27
28 struct search_closure
29 {
30 mu_msgset_t msgset;
31 int retcode;
32 };
33
34 static int
add_msgno(void * item,void * data)35 add_msgno (void *item, void *data)
36 {
37 int rc;
38 struct imap_list_element *elt = item;
39 struct search_closure *scp = data;
40 char *p;
41 unsigned long num;
42
43 if (elt->type != imap_eltype_string)
44 {
45 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
46 (_("unexpected list element in untagged response from SEARCH")));
47 scp->retcode = MU_ERR_BADREPLY;
48 return MU_ERR_USER0;
49 }
50
51 if (!scp->msgset)
52 {
53 /* First element (SEARCH): create the message set and return */
54 rc = mu_msgset_create (&scp->msgset, NULL, MU_MSGSET_NUM);
55 if (rc)
56 {
57 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
58 (_("cannot create msgset: %s"),
59 mu_strerror (rc)));
60 scp->retcode = rc;
61 return rc;
62 }
63 return 0;
64 }
65
66 num = strtoul (elt->v.string, &p, 10);
67 if (*p)
68 {
69 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
70 (_("not a number in untagged response from SEARCH: %s"),
71 elt->v.string));
72 scp->retcode = MU_ERR_BADREPLY;
73 return MU_ERR_USER0;
74 }
75
76 rc = mu_msgset_add_range (scp->msgset, num, num, MU_MSGSET_NUM);
77 if (rc)
78 {
79 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
80 ("mu_msgset_add_range: %s", mu_strerror (rc)));
81 scp->retcode = rc;
82 return MU_ERR_USER0;
83 }
84 return 0;
85 }
86
87 static void
search_handler(mu_imap_t imap,mu_list_t resp,void * data)88 search_handler (mu_imap_t imap, mu_list_t resp, void *data)
89 {
90 mu_list_foreach (resp, add_msgno, data);
91 }
92
93 int
mu_imap_search(mu_imap_t imap,int uid,const char * expr,mu_msgset_t * msgset)94 mu_imap_search (mu_imap_t imap, int uid, const char *expr, mu_msgset_t *msgset)
95 {
96 char const *argv[3];
97 int i, rc;
98 static struct imap_command com;
99 struct search_closure clos;
100
101 if (!expr)
102 return EINVAL;
103 if (!msgset)
104 return MU_ERR_OUT_PTR_NULL;
105 i = 0;
106 if (uid)
107 argv[i++] = "UID";
108 argv[i++] = "SEARCH";
109
110 clos.msgset = NULL;
111 clos.retcode = 0;
112
113 com.session_state = MU_IMAP_SESSION_SELECTED;
114 com.capa = NULL;
115 com.rx_state = MU_IMAP_CLIENT_SEARCH_RX;
116 com.argc = i;
117 com.argv = argv;
118 com.extra = expr;
119 com.msgset = NULL;
120 com.tagged_handler = NULL;
121 com.untagged_handler = search_handler;
122 com.untagged_handler_data = &clos;
123 rc = mu_imap_gencom (imap, &com);
124 if (rc)
125 mu_msgset_free (clos.msgset);
126 else if (clos.retcode)
127 {
128 mu_msgset_free (clos.msgset);
129 rc = clos.retcode;
130 }
131 else
132 *msgset = clos.msgset;
133 return rc;
134 }
135