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