2 * Session layer proxy for Citadel
3 * (c) 1998 by Art Cancro, All Rights Reserved, released under GNU GPL v2
8 * NOTE: this isn't finished, so don't use it!!
12 /* Directory to put the message cache in */
13 #define CACHE_DIR "/var/citadelproxy"
15 /* Number of days to keep messages in the cache */
16 #define CACHE_EXPIRE 60
18 /* Uncomment to enable prefetch */
19 /* #define ENABLE_PREFETCH */
21 /* Name and password to use for caching */
22 #define PREFETCH_USER_NAME "cypherpunks"
23 #define PREFETCH_USER_PASSWORD "cypherpunks"
28 #include <sys/types.h>
35 struct RoomList *next;
46 * num_parms() - discover number of parameters...
48 int num_parms(char *source)
53 for (a=0; a<strlen(source); ++a)
54 if (source[a]=='|') ++count;
60 * extract() - extract a parameter from a series of "|" separated...
62 void extract(char *dest, char *source, int parmnum)
68 n = num_parms(source);
75 if ( (parmnum == 0) && (n == 1) ) {
80 while (count++ < parmnum) do {
82 } while( (strlen(buf)>0) && (buf[0]!='|') );
83 if (buf[0]=='|') strcpy(buf,&buf[1]);
84 for (count = 0; count<strlen(buf); ++count)
85 if (buf[count] == '|') buf[count] = 0;
95 void logoff(int code) {
100 /* Fetch a message (or check its status in the cache)
102 void fetch_message(long msgnum) {
108 sprintf(filename, "%ld", msgnum);
110 if (access(filename, F_OK)==0) {
111 return; /* Already on disk */
114 /* The message is written to a file with a temporary name, in
115 * order to avoid another user accidentally fetching a
116 * partially written message from the cache.
118 sprintf(buf, "MSG0 %ld", msgnum);
121 if (buf[0] != '1') return;
122 sprintf(temp, "%ld.%d", msgnum, getpid());
123 fp = fopen(temp, "w");
124 while (serv_gets(buf), strcmp(buf, "000")) {
125 fprintf(fp, "%s\n", buf);
129 /* Now that the message is complete, it can be renamed to the
130 * filename that the cache manager will recognize it with.
132 link(temp, filename);
138 * This loop pre-fetches lots of messages
142 struct RoomList *rl = NULL;
143 struct RoomList *rlptr;
144 struct MsgList *ml = NULL;
145 struct MsgList *mlptr;
156 /* Log in (this is kind of arbitrary) */
157 sprintf(buf, "USER %s", PREFETCH_USER_NAME);
161 sprintf(buf, "PASS %s", PREFETCH_USER_PASSWORD);
164 if (buf[0] != '2') exit(1);
167 sprintf(buf, "NEWU %s", PREFETCH_USER_NAME);
170 if (buf[0] != '2') exit(1);
171 sprintf(buf, "SETP %s", PREFETCH_USER_PASSWORD);
174 if (buf[0] != '2') exit(1);
177 /* Fetch the roomlist (rooms with new messages only) */
180 if (buf[0] != '1') exit(2);
181 while (serv_gets(buf), strcmp(buf, "000")) {
182 rlptr = (struct rlptr *) malloc(sizeof(struct RoomList));
185 extract(rlptr->roomname, buf, 0);
188 /* Go to each room, fetching new messages */
190 sprintf(buf, "GOTO %s", rl->roomname);
194 serv_puts("MSGS NEW");
198 while (serv_gets(buf), strcmp(buf, "000")) {
199 mlptr = (struct mlptr *)
200 malloc(sizeof(struct MsgList));
203 mlptr->msgnum = atol(buf);
208 /* Fetch each message */
210 fetch_message(ml->msgnum);
216 /* Free the room list pointer */
227 void do_msg0(char cmd[]) {
234 msgnum = atol(&cmd[5]);
235 sprintf(filename, "%ld", msgnum);
237 /* If the message is cached, use the copy on disk */
238 fp = fopen(filename, "r");
240 printf("%d Cached message %ld:\n", LISTING_FOLLOWS, msgnum);
241 while (fgets(buf, 256, fp) != NULL) {
242 buf[strlen(buf)-1]=0;
250 /* Otherwise, fetch the message from the server and cache it */
252 sprintf(buf, "MSG0 %ld", msgnum);
261 /* The message is written to a file with a temporary name, in
262 * order to avoid another user accidentally fetching a
263 * partially written message from the cache.
265 sprintf(temp, "%ld.%d", msgnum, getpid());
266 fp = fopen(temp, "w");
267 while (serv_gets(buf), strcmp(buf, "000")) {
269 fprintf(fp, "%s\n", buf);
275 /* Now that the message is complete, it can be renamed to the
276 * filename that the cache manager will recognize it with.
278 link(temp, filename);
293 if (fgets(cmd, 256, stdin) == NULL) {
297 cmd[strlen(cmd)-1] = 0;
299 /* QUIT commands are handled specially */
300 if (!strncasecmp(cmd, "QUIT", 4)) {
302 printf("%d Proxy says: Bye!\n", OK);
305 "/usr/bin/find %s -mtime +%d -exec rm -f {} \\; &",
306 CACHE_DIR, CACHE_EXPIRE);
311 else if (!strncasecmp(cmd, "CHAT", 4)) {
312 printf("%d Can't chat through the proxy ... yet.\n",
316 else if (!strncasecmp(cmd, "MSG0", 4)) {
320 /* Other commands, just pass through. */
325 printf("%s\n", resp);
328 /* Simple command-response... */
329 if ( (resp[0]=='2')||(resp[0]=='3')||(resp[0]=='5') ) {
332 /* Textual input... */
333 else if (resp[0] == '4') {
335 if (fgets(buf, 256, stdin) == NULL) {
338 buf[strlen(buf)-1] = 0;
340 } while (strcmp(buf, "000"));
343 /* Textual output... */
344 else if (resp[0] == '1') {
348 } while (strcmp(buf, "000"));
351 /* Binary output... */
352 else if (resp[0] == '6') {
353 bytes = atol(&resp[4]);
354 serv_read(buf, bytes);
355 fwrite(buf, bytes, 1, stdout);
359 /* Binary input... */
360 else if (resp[0] == '7') {
361 bytes = atol(&resp[4]);
362 fread(buf, bytes, 1, stdin);
363 serv_write(buf, bytes);
367 else if (resp[0] == '8') {
371 fgets(buf, 256, stdin);
372 buf[strlen(buf)-1] = 0;
374 } while (strcmp(buf, "000"));
384 void main(int argc, char *argv[]) {
388 /* Create the cache directory. Die on any error *except* EEXIST
389 * because it's perfectly ok if the cache already exists.
391 if (mkdir(CACHE_DIR, 0700)!=0) {
392 if (errno != EEXIST) {
393 printf("%d Error creating cache directory: %s\n",
394 ERROR+INTERNAL_ERROR,
401 if (chdir(CACHE_DIR) != 0) exit(errno);
403 #ifdef ENABLE_PREFETCH
406 attach_to_server(argc, argv, NULL, NULL);
407 #ifdef ENABLE_PREFETCH
408 if (pid == 0) do_prefetch();
412 strcat(buf, " (VIA PROXY)");
415 if (buf[0] != '2') exit(0);