]> code.citadel.org Git - citadel.git/blob - citadel/proxy.c
fd2750033cabf8106aec4753e76810c3e6b9e2d2
[citadel.git] / citadel / proxy.c
1 /*
2  * Session layer proxy for Citadel
3  * (c) 1998 by Art Cancro, All Rights Reserved, released under GNU GPL v2
4  */
5
6 /*
7  * NOTE: this isn't finished, so don't use it!!
8  *
9  */
10
11 /* Directory to put the message cache in */
12 #define CACHE_DIR       "/var/citadelproxy"
13
14 /* Number of days to keep messages in the cache */
15 #define CACHE_EXPIRE    60
16
17 /* Uncomment to enable prefetch */
18 /* #define ENABLE_PREFETCH */
19
20 /* Name and password to use for caching */
21 #define PREFETCH_USER_NAME      "cypherpunks"
22 #define PREFETCH_USER_PASSWORD  "cypherpunks"
23
24
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <errno.h>
31 #include "citadel.h"
32
33 struct RoomList {
34         struct RoomList *next;
35         char roomname[32];
36         };
37
38 struct MsgList {
39         struct MsgList *next;
40         long msgnum;
41         };
42
43
44 /*
45  * num_parms()  -  discover number of parameters...
46  */
47 int num_parms(char *source)
48 {
49         int a;
50         int count = 1;
51
52         for (a=0; a<strlen(source); ++a)
53                 if (source[a]=='|') ++count;
54         return(count);
55         }
56
57
58 /*
59  * extract()  -  extract a parameter from a series of "|" separated...
60  */
61 void extract(char *dest, char *source, int parmnum)
62 {
63         char buf[256];
64         int count = 0;
65         int n;
66
67         n = num_parms(source);
68
69         if (parmnum >= n) {
70                 strcpy(dest,"");
71                 return;
72                 }
73         strcpy(buf,source);
74         if ( (parmnum == 0) && (n == 1) ) {
75                 strcpy(dest,buf);
76                 return;
77                 }
78
79         while (count++ < parmnum) do {
80                 strcpy(buf,&buf[1]);
81                 } while( (strlen(buf)>0) && (buf[0]!='|') );
82         if (buf[0]=='|') strcpy(buf,&buf[1]);
83         for (count = 0; count<strlen(buf); ++count)
84                 if (buf[count] == '|') buf[count] = 0;
85         strcpy(dest,buf);
86         }
87
88
89
90
91
92
93
94 void logoff(int code) {
95         exit(code);
96         }
97
98
99 /* Fetch a message (or check its status in the cache)
100  */
101 void fetch_message(long msgnum) {
102         char filename[64];
103         char temp[64];
104         FILE *fp;
105         char buf[256];
106
107         sprintf(filename, "%ld", msgnum);
108
109         if (access(filename, F_OK)==0) {
110                 return;                         /* Already on disk */
111                 }
112
113         /* The message is written to a file with a temporary name, in
114          * order to avoid another user accidentally fetching a
115          * partially written message from the cache.
116          */
117         sprintf(buf, "MSG0 %ld", msgnum);
118         serv_puts(buf);
119         serv_gets(buf);
120         if (buf[0] != '1') return;
121         sprintf(temp, "%ld.%d", msgnum, getpid());
122         fp = fopen(temp, "w");
123         while (serv_gets(buf), strcmp(buf, "000")) {
124                 fprintf(fp, "%s\n", buf);
125                 }
126         fclose(fp);
127
128         /* Now that the message is complete, it can be renamed to the
129          * filename that the cache manager will recognize it with.
130          */
131         link(temp, filename);
132         unlink(temp);
133         }
134
135
136 /*
137  * This loop pre-fetches lots of messages
138  */
139 void do_prefetch() {
140         char buf[256];
141         struct RoomList *rl = NULL;
142         struct RoomList *rlptr;
143         struct MsgList *ml = NULL;
144         struct MsgList *mlptr;
145
146         close(0);
147         close(1);
148         close(2);
149
150         serv_gets(buf);
151         if (buf[0] != '2') {
152                 exit(0);
153                 }
154
155         /* Log in (this is kind of arbitrary) */
156         sprintf(buf, "USER %s", PREFETCH_USER_NAME);
157         serv_puts(buf);
158         serv_gets(buf);
159         if (buf[0]=='3') {
160                 sprintf(buf, "PASS %s", PREFETCH_USER_PASSWORD);
161                 serv_puts(buf);
162                 serv_gets(buf);
163                 if (buf[0] != '2') exit(1);
164                 }
165         else {
166                 sprintf(buf, "NEWU %s", PREFETCH_USER_NAME);
167                 serv_puts(buf);
168                 serv_gets(buf);
169                 if (buf[0] != '2') exit(1);
170                 sprintf(buf, "SETP %s", PREFETCH_USER_PASSWORD);
171                 serv_puts(buf);
172                 serv_gets(buf);
173                 if (buf[0] != '2') exit(1);
174                 }
175
176         /* Fetch the roomlist (rooms with new messages only) */
177         serv_puts("LKRN");
178         serv_gets(buf);
179         if (buf[0] != '1') exit(2);
180         while (serv_gets(buf), strcmp(buf, "000")) {
181                 rlptr = (struct rlptr *) malloc(sizeof(struct RoomList));
182                 rlptr->next = rl;
183                 rl = rlptr;
184                 extract(rlptr->roomname, buf, 0);
185                 }
186
187         /* Go to each room, fetching new messages */
188         while (rl != NULL) {
189                 sprintf(buf, "GOTO %s", rl->roomname);
190                 serv_puts(buf);
191                 serv_gets(buf);
192                 if (buf[0]=='2') {
193                         serv_puts("MSGS NEW");
194                         serv_gets(buf);
195                         ml = NULL;
196                         if (buf[0]=='1') {
197                                 while (serv_gets(buf), strcmp(buf, "000")) {
198                                         mlptr = (struct mlptr *)
199                                                 malloc(sizeof(struct MsgList));
200                                         mlptr->next = ml;
201                                         ml = mlptr;
202                                         mlptr->msgnum = atol(buf);
203                                         }
204                                 }
205                         }
206
207                 /* Fetch each message */
208                 while (ml != NULL) {
209                         fetch_message(ml->msgnum);
210                         mlptr = ml;
211                         ml = ml->next;
212                         free(mlptr);
213                         }
214
215                 /* Free the room list pointer */
216                 rlptr = rl;
217                 rl = rl->next;
218                 free(rlptr);
219                 }
220
221         /* Now log out. */
222         serv_puts("QUIT");
223         exit(0);
224         }
225
226 void do_msg0(char cmd[]) {
227         long msgnum;
228         char filename[32];
229         char temp[32];
230         char buf[256];
231         FILE *fp;
232
233         msgnum = atol(&cmd[5]);
234         sprintf(filename, "%ld", msgnum);
235
236         /* If the message is cached, use the copy on disk */
237         fp = fopen(filename, "r");
238         if (fp != NULL) {
239                 printf("%d Cached message %ld:\n", LISTING_FOLLOWS, msgnum);
240                 while (fgets(buf, 256, fp) != NULL) {
241                         buf[strlen(buf)-1]=0;
242                         printf("%s\n", buf);
243                         }
244                 fclose(fp);
245                 printf("000\n");
246                 fflush(stdout);
247                 }
248
249         /* Otherwise, fetch the message from the server and cache it */
250         else {
251                 sprintf(buf, "MSG0 %ld", msgnum);
252                 serv_puts(buf); 
253                 serv_gets(buf);
254                 printf("%s\n", buf);
255                 fflush(stdout);
256                 if (buf[0] != '1') {
257                         return;
258                         }
259
260                 /* The message is written to a file with a temporary name, in
261                  * order to avoid another user accidentally fetching a
262                  * partially written message from the cache.
263                  */
264                 sprintf(temp, "%ld.%d", msgnum, getpid());
265                 fp = fopen(temp, "w");
266                 while (serv_gets(buf), strcmp(buf, "000")) {
267                         printf("%s\n", buf);
268                         fprintf(fp, "%s\n", buf);
269                         }
270                 printf("%s\n", buf);
271                 fflush(stdout);
272                 fclose(fp);
273
274                 /* Now that the message is complete, it can be renamed to the
275                  * filename that the cache manager will recognize it with.
276                  */
277                 link(temp, filename);
278                 unlink(temp);
279                 }
280
281         }
282
283
284 void do_mainloop() {
285         char cmd[256];
286         char resp[256];
287         char buf[4096];
288         int bytes;
289
290         while(1) {
291                 fflush(stdout);
292                 if (fgets(cmd, 256, stdin) == NULL) {
293                         serv_puts("QUIT");
294                         exit(1);
295                         }
296                 cmd[strlen(cmd)-1] = 0;
297
298                 /* QUIT commands are handled specially */
299                 if (!strncasecmp(cmd, "QUIT", 4)) {
300                         serv_puts("QUIT");
301                         printf("%d Proxy says: Bye!\n", OK);
302                         fflush(stdout);
303                         sprintf(buf,
304                           "/usr/bin/find %s -mtime +%d -exec rm -f {} \\; &",
305                           CACHE_DIR, CACHE_EXPIRE);
306                         system(buf);
307                         exit(0);
308                         }
309
310                 else if (!strncasecmp(cmd, "CHAT", 4)) {
311                         printf("%d Can't chat through the proxy ... yet.\n",
312                                 ERROR);
313                         }
314
315                 else if (!strncasecmp(cmd, "MSG0", 4)) {
316                         do_msg0(cmd);
317                         }
318
319                 /* Other commands, just pass through. */
320                 else {
321                         
322                         serv_puts(cmd);
323                         serv_gets(resp);
324                         printf("%s\n", resp);
325                         fflush(stdout);
326
327                         /* Simple command-response... */
328                         if ( (resp[0]=='2')||(resp[0]=='3')||(resp[0]=='5') ) {
329                                 }
330
331                         /* Textual input... */
332                         else if (resp[0] == '4') {
333                                 do {
334                                         if (fgets(buf, 256, stdin) == NULL) {
335                                                 exit(errno);
336                                                 }
337                                         buf[strlen(buf)-1] = 0;
338                                         serv_puts(buf);
339                                         } while (strcmp(buf, "000"));
340                                 }
341
342                         /* Textual output... */
343                         else if (resp[0] == '1') {
344                                 do {
345                                         serv_gets(buf);
346                                         printf("%s\n", buf);
347                                         } while (strcmp(buf, "000"));
348                                 }
349
350                         /* Binary output... */
351                         else if (resp[0] == '6') {
352                                 bytes = atol(&resp[4]);
353                                 serv_read(buf, bytes);
354                                 fwrite(buf, bytes, 1, stdout);
355                                 fflush(stdout);
356                                 }
357
358                         /* Binary input... */
359                         else if (resp[0] == '7') {
360                                 bytes = atol(&resp[4]);
361                                 fread(buf, bytes, 1, stdin);
362                                 serv_write(buf, bytes);
363                                 }
364
365                         /* chat... */
366                         else if (resp[0] == '8') {
367                                 sleep(2);
368                                 serv_puts("/quit");
369                                 do {
370                                         fgets(buf, 256, stdin);
371                                         buf[strlen(buf)-1] = 0;
372                                         serv_puts(buf);
373                                         } while (strcmp(buf, "000"));
374                                 }
375
376
377                         }
378                 }
379         }
380
381
382
383 void main(int argc, char *argv[]) {
384         char buf[256];
385         int pid;
386
387         /* Create the cache directory.  Die on any error *except* EEXIST
388          * because it's perfectly ok if the cache already exists.
389          */
390         if (mkdir(CACHE_DIR, 0700)!=0) {
391                 if (errno != EEXIST) {
392                         printf("%d Error creating cache directory: %s\n",
393                                 ERROR+INTERNAL_ERROR,
394                                 strerror(errno));
395                         exit(errno);
396                         }
397                 }
398
399         /* Now go there */
400         if (chdir(CACHE_DIR) != 0) exit(errno);
401
402 #ifdef ENABLE_PREFETCH
403         pid = fork();
404 #endif
405         attach_to_server(argc, argv);
406 #ifdef ENABLE_PREFETCH
407         if (pid == 0) do_prefetch();
408 #endif
409
410         serv_gets(buf);
411         strcat(buf, " (VIA PROXY)");
412         printf("%s\n", buf);
413         fflush(stdout);
414         if (buf[0] != '2') exit(0);
415
416         do_mainloop();
417         }