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 /* Directory to put the message cache in */
12 #define CACHE_DIR "/var/citadelproxy"
14 /* Number of days to keep messages in the cache */
15 #define CACHE_EXPIRE 60
17 /* Uncomment to enable prefetch */
18 /* #define ENABLE_PREFETCH */
20 /* Name and password to use for caching */
21 #define PREFETCH_USER_NAME "cypherpunks"
22 #define PREFETCH_USER_PASSWORD "cypherpunks"
27 #include <sys/types.h>
34 struct RoomList *next;
45 * num_parms() - discover number of parameters...
47 int num_parms(char *source)
52 for (a=0; a<strlen(source); ++a)
53 if (source[a]=='|') ++count;
59 * extract() - extract a parameter from a series of "|" separated...
61 void extract(char *dest, char *source, int parmnum)
67 n = num_parms(source);
74 if ( (parmnum == 0) && (n == 1) ) {
79 while (count++ < parmnum) do {
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;
94 void logoff(int code) {
99 /* Fetch a message (or check its status in the cache)
101 void fetch_message(long msgnum) {
107 sprintf(filename, "%ld", msgnum);
109 if (access(filename, F_OK)==0) {
110 return; /* Already on disk */
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.
117 sprintf(buf, "MSG0 %ld", msgnum);
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);
128 /* Now that the message is complete, it can be renamed to the
129 * filename that the cache manager will recognize it with.
131 link(temp, filename);
137 * This loop pre-fetches lots of messages
141 struct RoomList *rl = NULL;
142 struct RoomList *rlptr;
143 struct MsgList *ml = NULL;
144 struct MsgList *mlptr;
155 /* Log in (this is kind of arbitrary) */
156 sprintf(buf, "USER %s", PREFETCH_USER_NAME);
160 sprintf(buf, "PASS %s", PREFETCH_USER_PASSWORD);
163 if (buf[0] != '2') exit(1);
166 sprintf(buf, "NEWU %s", PREFETCH_USER_NAME);
169 if (buf[0] != '2') exit(1);
170 sprintf(buf, "SETP %s", PREFETCH_USER_PASSWORD);
173 if (buf[0] != '2') exit(1);
176 /* Fetch the roomlist (rooms with new messages only) */
179 if (buf[0] != '1') exit(2);
180 while (serv_gets(buf), strcmp(buf, "000")) {
181 rlptr = (struct rlptr *) malloc(sizeof(struct RoomList));
184 extract(rlptr->roomname, buf, 0);
187 /* Go to each room, fetching new messages */
189 sprintf(buf, "GOTO %s", rl->roomname);
193 serv_puts("MSGS NEW");
197 while (serv_gets(buf), strcmp(buf, "000")) {
198 mlptr = (struct mlptr *)
199 malloc(sizeof(struct MsgList));
202 mlptr->msgnum = atol(buf);
207 /* Fetch each message */
209 fetch_message(ml->msgnum);
215 /* Free the room list pointer */
226 void do_msg0(char cmd[]) {
233 msgnum = atol(&cmd[5]);
234 sprintf(filename, "%ld", msgnum);
236 /* If the message is cached, use the copy on disk */
237 fp = fopen(filename, "r");
239 printf("%d Cached message %ld:\n", LISTING_FOLLOWS, msgnum);
240 while (fgets(buf, 256, fp) != NULL) {
241 buf[strlen(buf)-1]=0;
249 /* Otherwise, fetch the message from the server and cache it */
251 sprintf(buf, "MSG0 %ld", msgnum);
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.
264 sprintf(temp, "%ld.%d", msgnum, getpid());
265 fp = fopen(temp, "w");
266 while (serv_gets(buf), strcmp(buf, "000")) {
268 fprintf(fp, "%s\n", buf);
274 /* Now that the message is complete, it can be renamed to the
275 * filename that the cache manager will recognize it with.
277 link(temp, filename);
292 if (fgets(cmd, 256, stdin) == NULL) {
296 cmd[strlen(cmd)-1] = 0;
298 /* QUIT commands are handled specially */
299 if (!strncasecmp(cmd, "QUIT", 4)) {
301 printf("%d Proxy says: Bye!\n", OK);
304 "/usr/bin/find %s -mtime +%d -exec rm -f {} \\; &",
305 CACHE_DIR, CACHE_EXPIRE);
310 else if (!strncasecmp(cmd, "CHAT", 4)) {
311 printf("%d Can't chat through the proxy ... yet.\n",
315 else if (!strncasecmp(cmd, "MSG0", 4)) {
319 /* Other commands, just pass through. */
324 printf("%s\n", resp);
327 /* Simple command-response... */
328 if ( (resp[0]=='2')||(resp[0]=='3')||(resp[0]=='5') ) {
331 /* Textual input... */
332 else if (resp[0] == '4') {
334 if (fgets(buf, 256, stdin) == NULL) {
337 buf[strlen(buf)-1] = 0;
339 } while (strcmp(buf, "000"));
342 /* Textual output... */
343 else if (resp[0] == '1') {
347 } while (strcmp(buf, "000"));
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);
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);
366 else if (resp[0] == '8') {
370 fgets(buf, 256, stdin);
371 buf[strlen(buf)-1] = 0;
373 } while (strcmp(buf, "000"));
383 void main(int argc, char *argv[]) {
387 /* Create the cache directory. Die on any error *except* EEXIST
388 * because it's perfectly ok if the cache already exists.
390 if (mkdir(CACHE_DIR, 0700)!=0) {
391 if (errno != EEXIST) {
392 printf("%d Error creating cache directory: %s\n",
393 ERROR+INTERNAL_ERROR,
400 if (chdir(CACHE_DIR) != 0) exit(errno);
402 #ifdef ENABLE_PREFETCH
405 attach_to_server(argc, argv);
406 #ifdef ENABLE_PREFETCH
407 if (pid == 0) do_prefetch();
411 strcat(buf, " (VIA PROXY)");
414 if (buf[0] != '2') exit(0);