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