4 * A partially functional session layer proxy for Citadel
5 * (c) 1998 by Art Cancro, All Rights Reserved, released under GNU GPL v2
6 * NOTE: this isn't finished, so don't use it!!
10 /* Directory to put the message cache in */
11 #define CACHE_DIR "/var/citadelproxy"
13 /* Number of days to keep messages in the cache */
14 #define CACHE_EXPIRE 60
16 /* Uncomment to enable prefetch */
17 /* #define ENABLE_PREFETCH */
19 /* Name and password to use for caching */
20 #define PREFETCH_USER_NAME "cypherpunks"
21 #define PREFETCH_USER_PASSWORD "cypherpunks"
26 #include <sys/types.h>
33 struct RoomList *next;
44 * num_parms() - discover number of parameters...
46 int num_parms(char *source)
51 for (a=0; a<strlen(source); ++a)
52 if (source[a]=='|') ++count;
58 * extract() - extract a parameter from a series of "|" separated...
60 void extract(char *dest, char *source, int parmnum)
66 n = num_parms(source);
73 if ( (parmnum == 0) && (n == 1) ) {
78 while (count++ < parmnum) do {
80 } while( (strlen(buf)>0) && (buf[0]!='|') );
81 if (buf[0]=='|') strcpy(buf,&buf[1]);
82 for (count = 0; count<strlen(buf); ++count)
83 if (buf[count] == '|') buf[count] = 0;
93 void logoff(int code) {
98 /* Fetch a message (or check its status in the cache)
100 void fetch_message(long msgnum) {
106 sprintf(filename, "%ld", msgnum);
108 if (access(filename, F_OK)==0) {
109 return; /* Already on disk */
112 /* The message is written to a file with a temporary name, in
113 * order to avoid another user accidentally fetching a
114 * partially written message from the cache.
116 sprintf(buf, "MSG0 %ld", msgnum);
119 if (buf[0] != '1') return;
120 sprintf(temp, "%ld.%d", msgnum, getpid());
121 fp = fopen(temp, "w");
122 while (serv_gets(buf), strcmp(buf, "000")) {
123 fprintf(fp, "%s\n", buf);
127 /* Now that the message is complete, it can be renamed to the
128 * filename that the cache manager will recognize it with.
130 link(temp, filename);
136 * This loop pre-fetches lots of messages
140 struct RoomList *rl = NULL;
141 struct RoomList *rlptr;
142 struct MsgList *ml = NULL;
143 struct MsgList *mlptr;
154 /* Log in (this is kind of arbitrary) */
155 sprintf(buf, "USER %s", PREFETCH_USER_NAME);
159 sprintf(buf, "PASS %s", PREFETCH_USER_PASSWORD);
162 if (buf[0] != '2') exit(1);
165 sprintf(buf, "NEWU %s", PREFETCH_USER_NAME);
168 if (buf[0] != '2') exit(1);
169 sprintf(buf, "SETP %s", PREFETCH_USER_PASSWORD);
172 if (buf[0] != '2') exit(1);
175 /* Fetch the roomlist (rooms with new messages only) */
178 if (buf[0] != '1') exit(2);
179 while (serv_gets(buf), strcmp(buf, "000")) {
180 rlptr = (struct rlptr *) malloc(sizeof(struct RoomList));
183 extract(rlptr->roomname, buf, 0);
186 /* Go to each room, fetching new messages */
188 sprintf(buf, "GOTO %s", rl->roomname);
192 serv_puts("MSGS NEW");
196 while (serv_gets(buf), strcmp(buf, "000")) {
197 mlptr = (struct mlptr *)
198 malloc(sizeof(struct MsgList));
201 mlptr->msgnum = atol(buf);
206 /* Fetch each message */
208 fetch_message(ml->msgnum);
214 /* Free the room list pointer */
225 void do_msg0(char cmd[]) {
232 msgnum = atol(&cmd[5]);
233 sprintf(filename, "%ld", msgnum);
235 /* If the message is cached, use the copy on disk */
236 fp = fopen(filename, "r");
238 printf("%d Cached message %ld:\n", LISTING_FOLLOWS, msgnum);
239 while (fgets(buf, 256, fp) != NULL) {
240 buf[strlen(buf)-1]=0;
248 /* Otherwise, fetch the message from the server and cache it */
250 sprintf(buf, "MSG0 %ld", msgnum);
259 /* The message is written to a file with a temporary name, in
260 * order to avoid another user accidentally fetching a
261 * partially written message from the cache.
263 sprintf(temp, "%ld.%d", msgnum, getpid());
264 fp = fopen(temp, "w");
265 while (serv_gets(buf), strcmp(buf, "000")) {
267 fprintf(fp, "%s\n", buf);
273 /* Now that the message is complete, it can be renamed to the
274 * filename that the cache manager will recognize it with.
276 link(temp, filename);
291 if (fgets(cmd, 256, stdin) == NULL) {
295 cmd[strlen(cmd)-1] = 0;
297 /* QUIT commands are handled specially */
298 if (!strncasecmp(cmd, "QUIT", 4)) {
300 printf("%d Proxy says: Bye!\n", OK);
303 "/usr/bin/find %s -mtime +%d -exec rm -f {} \\; &",
304 CACHE_DIR, CACHE_EXPIRE);
309 else if (!strncasecmp(cmd, "CHAT", 4)) {
310 printf("%d Can't chat through the proxy ... yet.\n",
314 else if (!strncasecmp(cmd, "MSG0", 4)) {
318 /* Other commands, just pass through. */
323 printf("%s\n", resp);
326 /* Simple command-response... */
327 if ( (resp[0]=='2')||(resp[0]=='3')||(resp[0]=='5') ) {
330 /* Textual input... */
331 else if (resp[0] == '4') {
333 if (fgets(buf, 256, stdin) == NULL) {
336 buf[strlen(buf)-1] = 0;
338 } while (strcmp(buf, "000"));
341 /* Textual output... */
342 else if (resp[0] == '1') {
346 } while (strcmp(buf, "000"));
349 /* Binary output... */
350 else if (resp[0] == '6') {
351 bytes = atol(&resp[4]);
352 serv_read(buf, bytes);
353 fwrite(buf, bytes, 1, stdout);
357 /* Binary input... */
358 else if (resp[0] == '7') {
359 bytes = atol(&resp[4]);
360 fread(buf, bytes, 1, stdin);
361 serv_write(buf, bytes);
365 else if (resp[0] == '8') {
369 fgets(buf, 256, stdin);
370 buf[strlen(buf)-1] = 0;
372 } while (strcmp(buf, "000"));
382 void main(int argc, char *argv[]) {
386 /* Create the cache directory. Die on any error *except* EEXIST
387 * because it's perfectly ok if the cache already exists.
389 if (mkdir(CACHE_DIR, 0700)!=0) {
390 if (errno != EEXIST) {
391 printf("%d Error creating cache directory: %s\n",
392 ERROR+INTERNAL_ERROR,
399 if (chdir(CACHE_DIR) != 0) exit(errno);
401 #ifdef ENABLE_PREFETCH
404 attach_to_server(argc, argv, NULL, NULL);
405 #ifdef ENABLE_PREFETCH
406 if (pid == 0) do_prefetch();
410 strcat(buf, " (VIA PROXY)");
413 if (buf[0] != '2') exit(0);