1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999-2021 Free Software Foundation, Inc.
3
4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Mailutils 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
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
16
17 #include "imap4d.h"
18
19 int
util_do_command(struct imap4d_session * session,imap4d_tokbuf_t tok)20 util_do_command (struct imap4d_session *session, imap4d_tokbuf_t tok)
21 {
22 char *tag, *cmd;
23 struct imap4d_command *command;
24 static struct imap4d_command nullcommand;
25 int argc = imap4d_tokbuf_argc (tok);
26
27 if (argc == 0)
28 {
29 nullcommand.name = "";
30 nullcommand.tag = (char *) "*";
31 return io_completion_response (&nullcommand, RESP_BAD, "Null command");
32 }
33 else if (argc == 1)
34 {
35 nullcommand.name = "";
36 nullcommand.tag = imap4d_tokbuf_getarg (tok, 0);
37 return io_completion_response (&nullcommand, RESP_BAD, "Missing command");
38 }
39
40 tag = imap4d_tokbuf_getarg (tok, 0);
41 cmd = imap4d_tokbuf_getarg (tok, 1);
42
43 command = util_getcommand (cmd, imap4d_command_table);
44 if (command == NULL)
45 {
46 nullcommand.name = "";
47 nullcommand.tag = tag;
48 return io_completion_response (&nullcommand, RESP_BAD, "Invalid command");
49 }
50
51 command->tag = tag;
52
53 if (command->states && (command->states & state) == 0)
54 return io_completion_response (command, RESP_BAD, "Wrong state");
55
56 return command->func (session, command, tok);
57 }
58
59 struct imap4d_command *
util_getcommand(char * cmd,struct imap4d_command command_table[])60 util_getcommand (char *cmd, struct imap4d_command command_table[])
61 {
62 size_t i, len = strlen (cmd);
63
64 for (i = 0; command_table[i].name != 0; i++)
65 {
66 if (strlen (command_table[i].name) == len &&
67 !mu_c_strcasecmp (command_table[i].name, cmd))
68 return &command_table[i];
69 }
70 return NULL;
71 }
72
73 static void
adjust_tm(struct tm * tm,struct mu_timezone * tz,enum datetime_parse_mode flag)74 adjust_tm (struct tm *tm, struct mu_timezone *tz,
75 enum datetime_parse_mode flag)
76 {
77 switch (flag)
78 {
79 case datetime_default:
80 break;
81 case datetime_date_only:
82 tm->tm_sec = 0;
83 tm->tm_min = 0;
84 tm->tm_hour = 0;
85 #if HAVE_STRUCT_TM_TM_ISDST
86 tm->tm_isdst = 0;
87 #endif
88 #if HAVE_STRUCT_TM_TM_GMTOFF
89 tm->tm_gmtoff = 0;
90 #endif
91 tz->utc_offset = 0;
92 tz->tz_name = NULL;
93 break;
94
95 case datetime_time_only:
96 tm->tm_mon = 0;
97 tm->tm_year = 0;
98 tm->tm_yday = 0;
99 tm->tm_wday = 0;
100 tm->tm_mday = 0;
101 break;
102 }
103 }
104
105 int
util_parse_internal_date(char * date,time_t * timep,enum datetime_parse_mode flag)106 util_parse_internal_date (char *date, time_t *timep,
107 enum datetime_parse_mode flag)
108 {
109 struct tm tm;
110 struct mu_timezone tz;
111 time_t time;
112
113 if (mu_scan_datetime (date, MU_DATETIME_INTERNALDATE, &tm, &tz, NULL))
114 return 1;
115
116 adjust_tm (&tm, &tz, flag);
117
118 time = mu_datetime_to_utc (&tm, &tz);
119 if (time == (time_t) - 1)
120 return 2;
121
122 *timep = time;
123 return 0;
124 }
125
126 int
util_parse_822_date(const char * date,time_t * timep,enum datetime_parse_mode flag)127 util_parse_822_date (const char *date, time_t *timep,
128 enum datetime_parse_mode flag)
129 {
130 struct tm tm;
131 struct mu_timezone tz;
132 const char *p = date;
133
134 if (mu_parse822_date_time (&p, date + strlen (date), &tm, &tz) == 0)
135 {
136 adjust_tm (&tm, &tz, flag);
137 *timep = mu_datetime_to_utc (&tm, &tz);
138 return 0;
139 }
140 return 1;
141 }
142
143 int
util_parse_ctime_date(const char * date,time_t * timep,enum datetime_parse_mode flag)144 util_parse_ctime_date (const char *date, time_t *timep,
145 enum datetime_parse_mode flag)
146 {
147 struct tm tm;
148 struct mu_timezone tz;
149
150 if (mu_scan_datetime (date, MU_DATETIME_FROM, &tm, &tz, NULL) == 0)
151 {
152 adjust_tm (&tm, &tz, flag);
153 *timep = mu_datetime_to_utc (&tm, &tz);
154 return 0;
155 }
156 return 1;
157 }
158
159 void
util_print_flags(mu_attribute_t attr)160 util_print_flags (mu_attribute_t attr)
161 {
162 int flags = 0;
163
164 mu_attribute_get_flags (attr, &flags);
165 mu_imap_format_flags (iostream, flags, 1);
166 }
167
168 int
util_attribute_matches_flag(mu_attribute_t attr,const char * item)169 util_attribute_matches_flag (mu_attribute_t attr, const char *item)
170 {
171 int flags = 0, mask = 0;
172
173 mu_attribute_get_flags (attr, &flags);
174 mu_imap_flag_to_attribute (item, &mask);
175 if (mask == MU_ATTRIBUTE_RECENT)
176 return MU_ATTRIBUTE_IS_UNSEEN (flags);
177
178 return flags & mask;
179 }
180
181 char *
util_localname()182 util_localname ()
183 {
184 static char *localname;
185
186 if (!localname)
187 {
188 char *name;
189 int name_len = 256;
190 int status = 1;
191 struct hostent *hp;
192
193 name = malloc (name_len);
194 while (name
195 && (status = gethostname (name, name_len)) == 0
196 && !memchr (name, 0, name_len))
197 {
198 name_len *= 2;
199 name = realloc (name, name_len);
200 }
201 if (status || name == NULL)
202 {
203 mu_diag_output (MU_DIAG_CRIT, _("cannot find out my own hostname"));
204 exit (EX_OSERR);
205 }
206
207 hp = gethostbyname (name);
208 if (hp)
209 {
210 struct in_addr inaddr;
211 inaddr.s_addr = *(unsigned int *) hp->h_addr;
212 hp = gethostbyaddr ((const char *) &inaddr,
213 sizeof (struct in_addr), AF_INET);
214 if (hp)
215 {
216 free (name);
217 name = mu_strdup ((char *) hp->h_name);
218 }
219 }
220 localname = name;
221 }
222 return localname;
223 }
224
225 /* Return the uindvalidity of a mailbox.
226 When a mailbox is selected, whose first message does not keep X-UIDVALIDITY
227 value, the uidvalidity is computed basing on the return of time(). Now,
228 if we call "EXAMINE mailbox" or "STATUS mailbox (UIDVALIDITY)" the same
229 mailbox is opened second time and the uidvalidity recalculated. Thus each
230 subsequent call to EXAMINE or STATUS upon an already selected mailbox
231 will return a different uidvalidity value. To avoid this, util_uidvalidity()
232 first sees if it is asked to operate upon an already opened mailbox
233 and if so, returns the previously computed value. */
234 int
util_uidvalidity(mu_mailbox_t smbox,unsigned long * uidvp)235 util_uidvalidity (mu_mailbox_t smbox, unsigned long *uidvp)
236 {
237 mu_url_t mbox_url = NULL;
238 mu_url_t smbox_url = NULL;
239
240 mu_mailbox_get_url (mbox, &mbox_url);
241 mu_mailbox_get_url (smbox, &smbox_url);
242 if (strcmp (mu_url_to_string (mbox_url), mu_url_to_string (smbox_url)) == 0)
243 smbox = mbox;
244 return mu_mailbox_uidvalidity (smbox, uidvp);
245 }
246
247 void
util_bye()248 util_bye ()
249 {
250 mu_stream_close (iostream);
251 mu_stream_destroy (&iostream);
252 }
253
254 void
util_chdir(const char * dir)255 util_chdir (const char *dir)
256 {
257 int rc = chdir (dir);
258 if (rc)
259 mu_error ("Cannot change to home directory `%s': %s",
260 dir, mu_strerror (errno));
261 }
262
263 int
is_atom(const char * s)264 is_atom (const char *s)
265 {
266 if (strpbrk (s, "(){ \t%*\"\\"))
267 return 0;
268 for (; *s; s++)
269 {
270 if (mu_iscntrl (*s))
271 return 0;
272 }
273 return 1;
274 }
275
276 int
set_xscript_level(int xlev)277 set_xscript_level (int xlev)
278 {
279 if (imap4d_transcript)
280 {
281 if (xlev != MU_XSCRIPT_NORMAL)
282 {
283 if (mu_debug_level_p (MU_DEBCAT_REMOTE,
284 xlev == MU_XSCRIPT_SECURE ?
285 MU_DEBUG_TRACE6 : MU_DEBUG_TRACE7))
286 return MU_XSCRIPT_NORMAL;
287 }
288
289 if (mu_stream_ioctl (iostream, MU_IOCTL_XSCRIPTSTREAM,
290 MU_IOCTL_XSCRIPTSTREAM_LEVEL, &xlev) == 0)
291 return xlev;
292 }
293 return 0;
294 }
295
296 /* Hide next LEN bytes of client input in transcript */
297 void
xscript_declare_client_payload(size_t len)298 xscript_declare_client_payload (size_t len)
299 {
300 struct mu_xscript_channel chan;
301
302 chan.cd = 0;
303 chan.level = MU_XSCRIPT_PAYLOAD;
304 chan.length = len;
305 mu_stream_ioctl (iostream, MU_IOCTL_XSCRIPTSTREAM,
306 MU_IOCTL_XSCRIPTSTREAM_CHANNEL, &chan);
307 }
308
309