0138b01f4fd9f2e7f5e282ce3c33ce9eebfde4d1
[citadel.git] / citadel / utils / getmail.c
1 /*
2  * $Id$
3  *
4  * Command-line utility to transmit a server command.
5  *
6  * Copyright (c) 1987-2009 by the citadel.org team
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include <string.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <ctype.h>
31
32 #if TIME_WITH_SYS_TIME
33 # include <sys/time.h>
34 # include <time.h>
35 #else
36 # if HAVE_SYS_TIME_H
37 #  include <sys/time.h>
38 # else
39 #  include <time.h>
40 # endif
41 #endif
42
43 #include <signal.h>
44 #include <errno.h>
45 #include <limits.h>
46 #include <libcitadel.h>
47 #include "citadel.h"
48 #include "citadel_ipc.h"
49 #include "server.h"
50 #include "config.h"
51
52 #define LOCKFILE "/tmp/LCK.sendcommand"
53
54 static CtdlIPC *ipc = NULL;
55
56 /*
57  * make sure only one copy of sendcommand runs at a time, using lock files
58  */
59 int set_lockfile(void)
60 {
61         FILE *lfp;
62         int onppid;
63         int rv;
64
65         if ((lfp = fopen(LOCKFILE, "r")) != NULL) {
66                 rv = fscanf(lfp, "%d", &onppid);
67                 fclose(lfp);
68                 if (!kill(onppid, 0) || errno == EPERM)
69                         return 1;
70         }
71         lfp = fopen(LOCKFILE, "w");
72         fprintf(lfp, "%ld\n", (long) getpid());
73         fclose(lfp);
74         return (0);
75 }
76
77 void remove_lockfile(void)
78 {
79         unlink(LOCKFILE);
80 }
81
82 /*
83  * Why both cleanup() and nq_cleanup() ?  Notice the alarm() call in
84  * cleanup() .  If for some reason sendcommand hangs waiting for the server
85  * to clean up, the alarm clock goes off and the program exits anyway.
86  * The cleanup() routine makes a check to ensure it's not reentering, in
87  * case the ipc module looped it somehow.
88  */
89 void nq_cleanup(int e)
90 {
91         remove_lockfile();
92         exit(e);
93 }
94
95 /*
96  * send binary to server
97  */
98 void serv_write(CtdlIPC *ipc, const char *buf, unsigned int nbytes)
99 {
100         unsigned int bytes_written = 0;
101         int retval;
102 /*
103 #if defined(HAVE_OPENSSL)
104         if (ipc->ssl) {
105                 serv_write_ssl(ipc, buf, nbytes);
106                 return;
107         }
108 #endif
109 */
110         while (bytes_written < nbytes) {
111                 retval = write(ipc->sock, &buf[bytes_written],
112                                nbytes - bytes_written);
113                 if (retval < 1) {
114                         connection_died(ipc, 0);
115                         return;
116                 }
117                 bytes_written += retval;
118         }
119 }
120
121
122 void cleanup(int e)
123 {
124         static int nested = 0;
125
126         alarm(30);
127         signal(SIGALRM, nq_cleanup);
128         serv_write(ipc, "\n", 1);
129         if (nested++ < 1)
130                 CtdlIPCQuit(ipc);
131         nq_cleanup(e);
132 }
133
134 /*
135  * This is implemented as a function rather than as a macro because the
136  * client-side IPC modules expect logoff() to be defined.  They call logoff()
137  * when a problem connecting or staying connected to the server occurs.
138  */
139 void logoff(int e)
140 {
141         cleanup(e);
142 }
143
144 static char *args[] =
145 {"getmail", NULL};
146
147 /*
148  * Connect sendcommand to the Citadel server running on this computer.
149  */
150 void np_attach_to_server(char *host, char *port)
151 {
152         char buf[SIZ];
153         char hostbuf[256] = "";
154         char portbuf[256] = "";
155         int r;
156
157         fprintf(stderr, "Attaching to server...\n");
158         strncpy(hostbuf, host, 256);
159         strncpy(portbuf, port, 256);
160         ipc = CtdlIPC_new(1, args, hostbuf, portbuf);
161         if (!ipc) {
162                 fprintf(stderr, "Can't connect: %s\n", strerror(errno));
163                 exit(3);
164         }
165         CtdlIPC_chat_recv(ipc, buf);
166         fprintf(stderr, "%s\n", &buf[4]);
167         snprintf(buf, sizeof buf, "IPGM %d", config.c_ipgm_secret);
168         r = CtdlIPCInternalProgram(ipc, config.c_ipgm_secret, buf);
169         fprintf(stderr, "%s\n", buf);
170         if (r / 100 != 2) {
171                 cleanup(2);
172         }
173 }
174
175
176 void sendcommand_die(void) {
177         exit(0);
178 }
179
180
181 /*
182  * saves filelen bytes from file at pathname
183  */
184 int save_buffer(void *file, size_t filelen, const char *pathname)
185 {
186         size_t block = 0;
187         size_t bytes_written = 0;
188         FILE *fp;
189
190         fp = fopen(pathname, "w");
191         if (!fp) {
192                 fprintf(stderr, "Cannot open '%s': %s\n", pathname, strerror(errno));
193                 return 0;
194         }
195         do {
196                 block = fwrite((char *)file + bytes_written, 1,
197                                 filelen - bytes_written, fp);
198                 bytes_written += block;
199         } while (errno == EINTR && bytes_written < filelen);
200         fclose(fp);
201
202         if (bytes_written < filelen) {
203                 fprintf(stderr,"Trouble saving '%s': %s\n", pathname,
204                                 strerror(errno));
205                 return 0;
206         }
207         return 1;
208 }
209
210
211 /*
212  * main
213  */
214 int main(int argc, char **argv)
215 {
216         int a, r, i;
217         char cmd[5][SIZ];
218         char buf[SIZ];
219         int MessageToRetrieve;
220         int MessageFound = 0;
221         int relh=0;
222         int home=0;
223         int n=0;
224         char relhome[PATH_MAX]="";
225         char ctdldir[PATH_MAX]=CTDLDIR;
226         fd_set read_fd;
227         struct timeval tv;
228         int ret, err;
229         int server_shutting_down = 0;
230         struct ctdlipcroom *Room;
231         struct ctdlipcmessage *mret;
232         char cret[SIZ];
233         unsigned long *msgarr;
234         struct parts *att;
235
236         strcpy(ctdl_home_directory, DEFAULT_PORT);
237
238         /*
239          * Change directories if specified
240          */
241         for (a = 1; a < argc && n < 5; ++a) {
242                 if (!strncmp(argv[a], "-h", 2)) {
243                         relh=argv[a][2]!='/';
244                         if (!relh) safestrncpy(ctdl_home_directory, &argv[a][2],
245                                                                    sizeof ctdl_home_directory);
246                         else
247                                 safestrncpy(relhome, &argv[a][2],
248                                                         sizeof relhome);
249                         home=1;
250                 } else {
251
252                         strcpy(cmd[n++], argv[a]);
253                 }
254         }
255
256         calc_dirs_n_files(relh, home, relhome, ctdldir, 0);
257         get_config();
258
259         signal(SIGINT, cleanup);
260         signal(SIGQUIT, cleanup);
261         signal(SIGHUP, cleanup);
262         signal(SIGTERM, cleanup);
263
264         fprintf(stderr, "getmail: started (pid=%d) "
265                         "running in %s\n",
266                         (int) getpid(),
267                         ctdl_home_directory);
268         fflush(stderr);
269
270 //      alarm(5);
271 //      signal(SIGALRM, nq_cleanup); /* Set up a watchdog type timer in case we hang */
272         
273         np_attach_to_server(UDS, ctdl_run_dir);
274         fflush(stderr);
275         setIPCDeathHook(sendcommand_die);
276
277         fprintf(stderr, "GOTO %s\n", cmd[0]);
278         CtdlIPCGotoRoom(ipc, cmd[0], "", &Room, cret);
279         fprintf(stderr, "%s\n", cret);
280
281         MessageToRetrieve = atol(cmd[1]);
282
283         r = CtdlIPCGetMessages(ipc, 0, 0, NULL, &msgarr, buf);
284         printf("Messages: ");
285         for (i = 0; msgarr[i] > 0 ; i ++)
286         {
287 //              printf(" %ld ", msgarr[i]);
288                 if (msgarr[i] == MessageToRetrieve)
289                         MessageFound = 1;
290         }
291         if (!MessageFound)
292                 printf("Message %d not found in the above list.", MessageToRetrieve);
293         printf("\n");
294
295         CtdlIPCGetSingleMessage(ipc,  MessageToRetrieve,0,4, &mret, cret);
296         fprintf(stderr, "%s\n", cret);
297         fprintf(stderr, "%s: %s\n", "path", mret->path);
298         fprintf(stderr, "%s: %s\n", "author", mret->author);
299         fprintf(stderr, "%s: %s\n", "subject", mret->subject);
300         fprintf(stderr, "%s: %s\n", "email", mret->email);
301         fprintf(stderr, "%s: %s\n", "text", mret->text);
302
303         att = mret->attachments;
304
305         while (att != NULL){
306                 void *attachment;
307                 char tmp[PATH_MAX];
308                 char buf[SIZ];
309
310                 fprintf(stderr, "Attachment: [%s] %s\n", att->number, att->filename);
311                 r = CtdlIPCAttachmentDownload(ipc, MessageToRetrieve, att->number, &attachment, NULL, buf);
312                 printf("----\%s\n----\n", buf);
313                 if (r / 100 != 2) {
314                         printf("%s\n", buf);
315                 } else {
316                         size_t len;
317                         
318                         len = (size_t)extract_long(buf, 0);
319                         CtdlMakeTempFileName(tmp, sizeof tmp);
320                         strcat(tmp, att->filename);
321                         printf("Saving Attachment to %s", tmp);
322                         save_buffer(attachment, len, tmp);
323                         free(attachment);
324                 }
325                 att = att->next;
326
327         }
328
329         ///if (
330
331
332         CtdlIPCQuit(ipc);
333         exit (1);
334
335
336
337
338
339
340         CtdlIPC_chat_send(ipc, cmd[4]);
341         CtdlIPC_chat_recv(ipc, buf);
342         fprintf(stderr, "%s\n", buf);
343
344         tv.tv_sec = 0;
345         tv.tv_usec = 1000;
346
347         if (!strncasecmp(&buf[1], "31", 2)) {
348                 server_shutting_down = 1;
349         }
350
351         if (buf[0] == '1') {
352                 while (CtdlIPC_chat_recv(ipc, buf), strcmp(buf, "000")) {
353                         printf("%s\n", buf);
354                         alarm(5); /* Kick the watchdog timer */
355                 }
356         } else if (buf[0] == '4') {
357                 do {
358                         if (fgets(buf, sizeof buf, stdin) == NULL)
359                                 strcpy(buf, "000");
360                         if (!IsEmptyStr(buf))
361                                 if (buf[strlen(buf) - 1] == '\n')
362                                         buf[strlen(buf) - 1] = 0;
363                         if (!IsEmptyStr(buf))
364                                 if (buf[strlen(buf) - 1] == '\r')
365                                         buf[strlen(buf) - 1] = 0;
366                         if (strcmp(buf, "000"))
367                                 CtdlIPC_chat_send(ipc, buf);
368                         
369                         FD_ZERO(&read_fd);
370                         FD_SET(ipc->sock, &read_fd);
371                         ret = select(ipc->sock+1, &read_fd, NULL, NULL,  &tv);
372                         err = errno;
373                         if (err!=0)
374                                 printf("select failed: %d", err);
375
376                         if (ret == -1) {
377                                 if (!(errno == EINTR || errno == EAGAIN))
378                                         printf("select failed: %d", err);
379                                 return 1;
380                         }
381
382                         if (ret != 0) {
383                                 size_t n;
384                                 char rbuf[SIZ];
385
386                                 rbuf[0] = '\0';
387                                 n = read(ipc->sock, rbuf, SIZ);
388                                 if (n>0) {
389                                         rbuf[n]='\0';
390                                         fprintf(stderr, "%s", rbuf);
391                                         fflush(stdout);
392                                 }
393                         }
394                         alarm(5); /* Kick the watchdog timer */
395                 } while (strcmp(buf, "000"));
396                 CtdlIPC_chat_send(ipc, "\n");
397                 CtdlIPC_chat_send(ipc, "000");
398         }
399         alarm(0);       /* Shutdown the watchdog timer */
400         fprintf(stderr, "sendcommand: processing ended.\n");
401
402         /* Clean up and log off ... unless the server indicated that the command
403          * we sent is shutting it down, in which case we want to just cut the
404          * connection and exit.
405          */
406         if (server_shutting_down) {
407                 nq_cleanup(0);
408         }
409         else {
410                 cleanup(0);
411         }
412         return 0;
413 }
414
415
416 /*
417  * Stub function
418  */
419 void stty_ctdl(int cmd) {
420 }
421
422