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