2 * Session layer proxy for Citadel
3 * (c) 1998 by Art Cancro, All Rights Reserved, released under GNU GPL v2
7 * NOTE: this isn't finished, so don't use it!!
11 #define CACHE_DIR "/var/citadelproxy"
15 #include <sys/types.h>
22 struct RoomList *next;
33 * num_parms() - discover number of parameters...
35 int num_parms(char *source)
40 for (a=0; a<strlen(source); ++a)
41 if (source[a]=='|') ++count;
47 * extract() - extract a parameter from a series of "|" separated...
49 void extract(char *dest, char *source, int parmnum)
55 n = num_parms(source);
62 if ( (parmnum == 0) && (n == 1) ) {
67 while (count++ < parmnum) do {
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;
82 void logoff(int code) {
87 /* Fetch a message (or check its status in the cache)
89 void fetch_message(long msgnum) {
95 sprintf(filename, "%ld", msgnum);
97 if (access(filename, F_OK)==0) {
98 return; /* Already on disk */
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.
105 sprintf(buf, "MSG0 %ld", msgnum);
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);
116 /* Now that the message is complete, it can be renamed to the
117 * filename that the cache manager will recognize it with.
119 link(temp, filename);
125 * This loop pre-fetches lots of messages
129 struct RoomList *rl = NULL;
130 struct RoomList *rlptr;
131 struct MsgList *ml = NULL;
132 struct MsgList *mlptr;
145 /* Log in (this is kind of arbitrary) */
146 serv_puts("USER cypherpunks");
149 serv_puts("PASS cypherpunks");
151 if (buf[0] != '2') exit(1);
154 serv_puts("NEWU cypherpunks");
156 if (buf[0] != '2') exit(1);
157 serv_puts("SETP cypherpunks");
159 if (buf[0] != '2') exit(1);
162 /* Fetch the roomlist (rooms with new messages only) */
165 if (buf[0] != '1') exit(2);
166 while (serv_gets(buf), strcmp(buf, "000")) {
167 rlptr = (struct rlptr *) malloc(sizeof(struct RoomList));
170 extract(rlptr->roomname, buf, 0);
173 /* Go to each room, fetching new messages */
175 sprintf(buf, "GOTO %s", rl->roomname);
179 serv_puts("MSGS NEW");
183 while (serv_gets(buf), strcmp(buf, "000")) {
184 mlptr = (struct mlptr *)
185 malloc(sizeof(struct MsgList));
188 mlptr->msgnum = atol(buf);
193 /* Fetch each message */
195 fetch_message(ml->msgnum);
201 /* Free the room list pointer */
212 void do_msg0(char cmd[]) {
219 msgnum = atol(&cmd[5]);
220 sprintf(filename, "%ld", msgnum);
222 /* If the message is cached, use the copy on disk */
223 fp = fopen(filename, "r");
225 printf("%d Cached message %ld:\n", LISTING_FOLLOWS, msgnum);
226 while (fgets(buf, 256, fp) != NULL) {
227 buf[strlen(buf)-1]=0;
235 /* Otherwise, fetch the message from the server and cache it */
237 sprintf(buf, "MSG0 %ld", msgnum);
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.
250 sprintf(temp, "%ld.%d", msgnum, getpid());
251 fp = fopen(temp, "w");
252 while (serv_gets(buf), strcmp(buf, "000")) {
254 fprintf(fp, "%s\n", buf);
260 /* Now that the message is complete, it can be renamed to the
261 * filename that the cache manager will recognize it with.
263 link(temp, filename);
278 if (fgets(cmd, 256, stdin) == NULL) {
282 cmd[strlen(cmd)-1] = 0;
284 /* QUIT commands are handled specially */
285 if (!strncasecmp(cmd, "QUIT", 4)) {
287 printf("%d Proxy says: Bye!\n", OK);
292 else if (!strncasecmp(cmd, "CHAT", 4)) {
293 printf("%d Can't chat through the proxy ... yet.\n",
297 else if (!strncasecmp(cmd, "MSG0", 4)) {
301 /* Other commands, just pass through. */
306 printf("%s\n", resp);
309 /* Simple command-response... */
310 if ( (resp[0]=='2')||(resp[0]=='3')||(resp[0]=='5') ) {
313 /* Textual input... */
314 else if (resp[0] == '4') {
316 if (fgets(buf, 256, stdin) == NULL) {
319 buf[strlen(buf)-1] = 0;
321 } while (strcmp(buf, "000"));
324 /* Textual output... */
325 else if (resp[0] == '1') {
329 } while (strcmp(buf, "000"));
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);
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);
348 else if (resp[0] == '8') {
352 fgets(buf, 256, stdin);
353 buf[strlen(buf)-1] = 0;
355 } while (strcmp(buf, "000"));
365 void main(int argc, char *argv[]) {
369 /* Create the cache directory. Die on any error *except* EEXIST
370 * because it's perfectly ok if the cache already exists.
372 if (mkdir(CACHE_DIR, 0700)!=0) {
373 if (errno != EEXIST) {
374 printf("%d Error creating cache directory: %s\n",
375 ERROR+INTERNAL_ERROR,
382 if (chdir(CACHE_DIR) != 0) exit(errno);
385 attach_to_server(argc, argv);
386 if (pid == 0) do_prefetch();
389 strcat(buf, " (VIA PROXY)");
392 if (buf[0] != '2') exit(0);