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