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