075ce9e1cd758a3f729f6b4605bd60ce35499f27
[citadel.git] / citadel / imap_misc.c
1 /*
2  * $Id$
3  *
4  *
5  */
6
7
8 #include "sysdep.h"
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include <signal.h>
14 #include <pwd.h>
15 #include <errno.h>
16 #include <sys/types.h>
17 #include <sys/time.h>
18 #include <sys/wait.h>
19 #include <ctype.h>
20 #include <string.h>
21 #include <limits.h>
22 #include "citadel.h"
23 #include "server.h"
24 #include <time.h>
25 #include "sysdep_decls.h"
26 #include "citserver.h"
27 #include "support.h"
28 #include "config.h"
29 #include "dynloader.h"
30 #include "room_ops.h"
31 #include "user_ops.h"
32 #include "policy.h"
33 #include "database.h"
34 #include "msgbase.h"
35 #include "tools.h"
36 #include "internet_addressing.h"
37 #include "serv_imap.h"
38 #include "imap_tools.h"
39 #include "imap_fetch.h"
40 #include "imap_misc.h"
41 #include "genstamp.h"
42
43
44
45
46
47
48 /*
49  * imap_copy() calls imap_do_copy() to do its actual work, once it's
50  * validated and boiled down the request a bit.  (returns 0 on success)
51  */
52 int imap_do_copy(char *destination_folder) {
53         int i;
54         char roomname[ROOMNAMELEN];
55
56         i = imap_grabroom(roomname, destination_folder);
57         if (i != 0) return(i);
58
59         if (IMAP->num_msgs > 0) {
60                 for (i = 0; i < IMAP->num_msgs; ++i) {
61                         if (IMAP->flags[i] && IMAP_SELECTED) {
62                                 CtdlCopyMsgToRoom(
63                                         IMAP->msgids[i], roomname);
64                         }
65                 }
66         }
67
68         return(0);
69 }
70
71
72 /*
73  * This function is called by the main command loop.
74  */
75 void imap_copy(int num_parms, char *parms[]) {
76         int ret;
77
78         if (num_parms != 4) {
79                 cprintf("%s BAD invalid parameters\r\n", parms[0]);
80                 return;
81         }
82
83         if (imap_is_message_set(parms[2])) {
84                 imap_pick_range(parms[2], 0);
85         }
86         else {
87                 cprintf("%s BAD invalid parameters\r\n", parms[0]);
88                 return;
89         }
90
91         ret = imap_do_copy(parms[3]);
92         if (!ret) {
93                 cprintf("%s OK COPY completed\r\n", parms[0]);
94         }
95         else {
96                 cprintf("%s NO COPY failed (error %d)\r\n", parms[0], ret);
97         }
98 }
99
100 /*
101  * This function is called by the main command loop.
102  */
103 void imap_uidcopy(int num_parms, char *parms[]) {
104
105         if (num_parms != 5) {
106                 cprintf("%s BAD invalid parameters\r\n", parms[0]);
107                 return;
108         }
109
110         if (imap_is_message_set(parms[3])) {
111                 imap_pick_range(parms[3], 1);
112         }
113         else {
114                 cprintf("%s BAD invalid parameters\r\n", parms[0]);
115                 return;
116         }
117
118         if (imap_do_copy(parms[4]) == 0) {
119                 cprintf("%s OK UID COPY completed\r\n", parms[0]);
120         }
121         else {
122                 cprintf("%s NO UID COPY failed\r\n", parms[0]);
123         }
124 }
125
126
127 /*
128  * Poll for express messages (yeah, we can do this in IMAP ... I think)
129  */
130 void imap_print_express_messages(void) {
131         struct ExpressMessage *ptr, *holdptr;
132         char *dumpomatic = NULL;
133         int i;
134
135         if (CC->FirstExpressMessage == NULL) {
136                 return;
137         }
138         begin_critical_section(S_SESSION_TABLE);
139         ptr = CC->FirstExpressMessage;
140         CC->FirstExpressMessage = NULL;
141         end_critical_section(S_SESSION_TABLE);
142
143         while (ptr != NULL) {
144                 dumpomatic = mallok(strlen(ptr->text) + SIZ);
145                 strcpy(dumpomatic, "");
146                 if (ptr->flags && EM_BROADCAST)
147                         strcat(dumpomatic, "Broadcast message ");
148                 else if (ptr->flags && EM_CHAT)
149                         strcat(dumpomatic, "Chat request ");
150                 else if (ptr->flags && EM_GO_AWAY)
151                         strcat(dumpomatic, "Please logoff now, as requested ");
152                 else
153                         strcat(dumpomatic, "Message ");
154                 sprintf(&dumpomatic[strlen(dumpomatic)],
155                         "from %s:\n", ptr->sender);
156                 if (ptr->text != NULL)
157                         strcat(dumpomatic, ptr->text);
158
159                 holdptr = ptr->next;
160                 if (ptr->text != NULL) phree(ptr->text);
161                 phree(ptr);
162                 ptr = holdptr;
163
164                 for (i=0; i<strlen(dumpomatic); ++i) {
165                         if (!isprint(dumpomatic[i])) dumpomatic[i] = ' ';
166                         if (dumpomatic[i]=='\\') dumpomatic[i]='/';
167                         if (dumpomatic[i]=='\"') dumpomatic[i]='\'';
168                 }
169
170                 cprintf("* OK [ALERT] %s\r\n", dumpomatic);
171                 phree(dumpomatic);
172         }
173         cprintf("000\n");
174 }
175
176
177
178 /*
179  * This function is called by the main command loop.
180  */
181 void imap_append(int num_parms, char *parms[]) {
182         size_t literal_length;
183         struct CtdlMessage *msg;
184         int ret;
185         char roomname[ROOMNAMELEN];
186         char buf[SIZ];
187         char savedroom[ROOMNAMELEN];
188         int msgs, new;
189
190
191         if (num_parms < 4) {
192                 cprintf("%s BAD usage error\r\n", parms[0]);
193                 return;
194         }
195
196         if ( (parms[num_parms-1][0] != '{')
197            || (parms[num_parms-1][strlen(parms[num_parms-1])-1] != '}') )  {
198                 cprintf("%s BAD no message literal supplied\r\n", parms[0]);
199                 return;
200         }
201
202         literal_length = (size_t) atol(&parms[num_parms-1][1]);
203         if (literal_length < 1) {
204                 cprintf("%s BAD Message length must be at least 1.\r\n",
205                         parms[0]);
206                 return;
207         }
208
209         imap_free_transmitted_message();        /* just in case. */
210         IMAP->transmitted_message = mallok(literal_length + 1);
211         if (IMAP->transmitted_message == NULL) {
212                 cprintf("%s NO Cannot allocate memory.\r\n", parms[0]);
213                 return;
214         }
215         IMAP->transmitted_length = literal_length;
216
217         cprintf("+ Transmit message now.\r\n");
218         ret = client_read(IMAP->transmitted_message, literal_length);
219         IMAP->transmitted_message[literal_length] = 0;
220         if (ret != 1) {
221                 cprintf("%s NO Read failed.\r\n", parms[0]);
222                 return;
223         }
224
225         lprintf(9, "Converting message...\n");
226         msg = convert_internet_message(IMAP->transmitted_message);
227         IMAP->transmitted_message = NULL;
228         IMAP->transmitted_length = 0;
229
230         /* If the user is locally authenticated, FORCE the From: header to
231          * show up as the real sender.  FIXME do we really want to do this?
232          * Probably should make it site-definable or even room-definable.
233          */
234         if (CC->logged_in) {
235                 if (msg->cm_fields['A'] != NULL) phree(msg->cm_fields['A']);
236                 if (msg->cm_fields['N'] != NULL) phree(msg->cm_fields['N']);
237                 if (msg->cm_fields['H'] != NULL) phree(msg->cm_fields['H']);
238                 msg->cm_fields['A'] = strdoop(CC->usersupp.fullname);
239                 msg->cm_fields['N'] = strdoop(config.c_nodename);
240                 msg->cm_fields['H'] = strdoop(config.c_humannode);
241         }
242
243         ret = imap_grabroom(roomname, parms[2]);
244         if (ret != 0) {
245                 cprintf("%s NO Invalid mailbox name or location, or access denied\r\n",
246                         parms[0]);
247                 return;
248         }
249
250         /*
251          * usergoto() formally takes us to the desired room.  (If another
252          * folder is selected, save its name so we can return there!!!!!)
253          */
254         if (IMAP->selected) {
255                 strcpy(savedroom, CC->quickroom.QRname);
256         }
257         usergoto(roomname, 0, &msgs, &new);
258
259         /* 
260          * Can we post here?
261          */
262         ret = CtdlDoIHavePermissionToPostInThisRoom(buf);
263
264         if (ret) {
265                 /* Nope ... print an error message */
266                 cprintf("%s NO %s\r\n", parms[0], buf);
267         }
268
269         else {
270                 /* Yes ... go ahead and post! */
271                 if (msg != NULL) {
272                         CtdlSaveMsg(msg, "", "", 0);
273                 }
274                 cprintf("%s OK APPEND completed\r\n", parms[0]);
275         }
276
277         /*
278          * IMAP protocol response to client has already been sent by now.
279          *
280          * If another folder is selected, go back to that room so we can resume
281          * our happy day without violent explosions.
282          */
283         if (IMAP->selected) {
284                 usergoto(savedroom, 0, &msgs, &new);
285         }
286
287         /* We don't need this buffer anymore */
288         CtdlFreeMessage(msg);
289 }