]> code.citadel.org Git - citadel.git/blob - citadel/citadel_ipc.c
* Use a new IPC API (in citadel_ipc.c). Partially converted citadel.c to
[citadel.git] / citadel / citadel_ipc.c
1 /* $Id$ */
2
3 #include "sysdep.h"
4 #if TIME_WITH_SYS_TIME
5 # include <sys/time.h>
6 # include <time.h>
7 #else
8 # if HAVE_SYS_TIME_H
9 #  include <sys/time.h>
10 # else
11 #  include <time.h>
12 # endif
13 #endif
14 #include <stdio.h>
15 #include <sys/types.h>
16 #include <string.h>
17 #include <malloc.h>
18 #include <stdlib.h>
19 #ifdef THREADED_CLIENT
20 #include <pthread.h>
21 #endif
22 #include "citadel.h"
23 #include "citadel_ipc.h"
24 #include "client_crypto.h"
25 #include "tools.h"
26
27 #ifdef THREADED_CLIENT
28 pthread_mutex_t rwlock;
29 #endif
30 extern char express_msgs;
31
32 static volatile int download_in_progress = 0;   /* download file open */
33 static volatile int upload_in_progress = 0;     /* upload file open */
34 /* static volatile int serv_sock;       /* Socket on which we talk to server */
35
36
37 /*
38  * Does nothing.  The server should always return 200.
39  */
40 int CtdlIPCNoop(void)
41 {
42         char aaa[128];
43
44         register int ret;
45
46         netio_lock();
47         serv_puts("NOOP");
48         serv_gets(aaa);
49         ret = atoi(aaa);
50         netio_unlock();
51         return ret;
52 }
53
54
55 /*
56  * Does nothing interesting.  The server should always return 200
57  * along with your string.
58  */
59 int CtdlIPCEcho(const char *arg, char *cret)
60 {
61         register int ret;
62         char *aaa;
63         
64         if (!arg) return -2;
65         if (!cret) return -2;
66
67         aaa = (char *)malloc(strlen(arg) + 6);
68         if (!aaa) return -1;
69
70         sprintf(aaa, "ECHO %s", arg);
71         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
72         free(aaa);
73         return ret;
74 }
75
76
77 /*
78  * Asks the server to close the connecction.
79  * Should always return 200.
80  */
81 int CtdlIPCQuit(void)
82 {
83         register int ret;
84         char aaa[128];
85
86         netio_lock();
87         serv_puts("QUIT");
88         serv_gets(aaa);
89         ret = atoi(aaa);
90         netio_unlock();
91         return ret;
92 }
93
94
95 /*
96  * Asks the server to logout.  Should always return 200, even if no user
97  * was logged in.  The user will not be logged in after this!
98  */
99 int CtdlIPCLogout(void)
100 {
101         register int ret;
102         char aaa[128];
103
104         netio_lock();
105         serv_puts("LOUT");
106         serv_gets(aaa);
107         ret = atoi(aaa);
108         netio_unlock();
109         return ret;
110 }
111
112
113 /*
114  * First stage of authentication - pass the username.  Returns 300 if the
115  * username is able to log in, with the username correctly spelled in cret.
116  * Returns various 500 error codes if the user doesn't exist, etc.
117  */
118 int CtdlIPCTryLogin(const char *username, char *cret)
119 {
120         register int ret;
121         char *aaa;
122
123         if (!username) return -2;
124         if (!cret) return -2;
125
126         aaa = (char *)malloc(strlen(username) + 6);
127         if (!aaa) return -1;
128
129         sprintf(aaa, "USER %s", username);
130         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
131         free(aaa);
132         return ret;
133 }
134
135
136 /*
137  * Second stage of authentication - provide password.  The server returns
138  * 200 and several arguments in cret relating to the user's account.
139  */
140 int CtdlIPCTryPassword(const char *passwd, char *cret)
141 {
142         register int ret;
143         char *aaa;
144
145         if (!passwd) return -2;
146         if (!cret) return -2;
147
148         aaa = (char *)malloc(strlen(passwd) + 6);
149         if (!aaa) return -1;
150
151         sprintf(aaa, "PASS %s", passwd);
152         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
153         free(aaa);
154         return ret;
155 }
156
157
158 /*
159  * Create a new user.  This returns 200 plus the same arguments as TryPassword
160  * unless there was a problem creating the account.
161  */
162 int CtdlIPCCreateUser(const char *username, char *cret)
163 {
164         register int ret;
165         char *aaa;
166
167         if (!username) return -2;
168         if (!cret) return -2;
169
170         aaa = (char *)malloc(strlen(username) + 6);
171         if (!aaa) return -1;
172
173         sprintf(aaa, "NEWU %s", username);
174         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
175         free(aaa);
176         return ret;
177 }
178
179
180 /*
181  * Changes the user's password.  Returns 200 if changed, errors otherwise.
182  */
183 int CtdlIPCChangePassword(const char *passwd, char *cret)
184 {
185         register int ret;
186         char *aaa;
187
188         if (!passwd) return -2;
189         if (!cret) return -2;
190
191         aaa = (char *)malloc(strlen(passwd) + 6);
192         if (!aaa) return -1;
193
194         sprintf(aaa, "SETP %s", passwd);
195         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
196         free(aaa);
197         return ret;
198 }
199
200
201 /* LKRN */
202 /* Caller must free the march list */
203 /* which is 0 = LRMS, 1 = LKRN, 2 = LKRO, 3 = LKRA, 4 = LZRM */
204 /* floor is -1 for all, or floornum */
205 int CtdlIPCKnownRooms(int which, int floor, char *cret, struct march **listing)
206 {
207         register int ret;
208         struct march *march = NULL;
209         static char *proto[] = {"LRMS", "LKRN", "LKRO", "LKRA", "LZRM" };
210         char aaa[256];
211         char *bbb = NULL;
212         size_t bbbsize;
213
214         if (!listing) return -2;
215         if (*listing) return -2;        /* Free the listing first */
216         if (!cret) return -2;
217         if (which < 0 || which > 4) return -2;
218         if (floor < -1) return -2;      /* Can't validate upper bound, sorry */
219
220         sprintf(aaa, "%s %d", proto[which], floor);
221         ret = CtdlIPCGenericCommand(aaa, NULL, 0, &bbb, &bbbsize, cret);
222         if (ret / 100 == 1) {
223                 struct march *mptr;
224
225                 while (strlen(bbb)) {
226                         int a;
227
228                         extract_token(aaa, bbb, 0, '\n');
229                         a = strlen(aaa);
230                         memmove(aaa, bbb + a + 1, strlen(bbb) - a - 1);
231                         mptr = (struct march *) malloc(sizeof (struct march));
232                         if (mptr) {
233                                 mptr->next = NULL;
234                                 extract(mptr->march_name, aaa, 0);
235                                 mptr->march_floor = (char) extract_int(aaa, 2);
236                                 mptr->march_order = (char) extract_int(aaa, 3);
237                                 if (march == NULL)
238                                         march = mptr;
239                                 else {
240                                         struct march *mptr2;
241
242                                         mptr2 = march;
243                                         while (mptr2->next != NULL)
244                                                 mptr2 = mptr2->next;
245                                         mptr2->next = mptr;
246                                 }
247                         }
248                 }
249         }
250         *listing = march;
251         return ret;
252 }
253
254
255 /* GETU */
256 /* Caller must free the struct usersupp; caller may pass an existing one */
257 int CtdlIPCGetConfig(struct usersupp **uret, char *cret)
258 {
259         register int ret;
260
261         if (!cret) return -2;
262         if (!uret) return -2;
263         if (!*uret) *uret = (struct usersupp *)calloc(1, sizeof (struct usersupp));
264         if (!*uret) return -1;
265
266         ret = CtdlIPCGenericCommand("GETU", NULL, 0, NULL, NULL, cret);
267         if (ret / 100 == 2) {
268                 uret[0]->USscreenwidth = extract_int(cret, 0);
269                 uret[0]->USscreenheight = extract_int(cret, 1);
270                 uret[0]->flags = extract_int(cret, 2);
271         }
272         return ret;
273 }
274
275
276 /* SETU */
277 int CtdlIPCSetConfig(struct usersupp *uret, char *cret)
278 {
279         char aaa[48];
280
281         if (!uret) return -2;
282         if (!cret) return -2;
283
284         sprintf(aaa, "SETU %d|%d|%d",
285                         uret->USscreenwidth, uret->USscreenheight,
286                         uret->flags);
287         return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
288 }
289
290
291 /* GOTO */
292 int CtdlIPCGotoRoom(const char *room, const char *passwd,
293                 struct ctdlipcroom **rret, char *cret)
294 {
295         register int ret;
296         char *aaa;
297
298         if (!cret) return -2;
299         if (!rret) return -2;
300         if (!*rret) *rret = (struct ctdlipcroom *)calloc(1, sizeof (struct ctdlipcroom));
301         if (!*rret) return -1;
302
303         if (passwd) {
304                 aaa = (char *)malloc(strlen(room) + strlen(passwd) + 7);
305                 if (!aaa) {
306                         free(*rret);
307                         return -1;
308                 }
309                 sprintf(aaa, "GOTO %s|%s", room, passwd);
310         } else {
311                 aaa = (char *)malloc(strlen(room) + 6);
312                 if (!aaa) {
313                         free(*rret);
314                         return -1;
315                 }
316                 sprintf(aaa, "GOTO %s", room);
317         }
318         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
319         if (ret / 100 == 2) {
320                 extract(rret[0]->RRname, cret, 0);
321                 rret[0]->RRunread = extract_long(cret, 1);
322                 rret[0]->RRtotal = extract_long(cret, 2);
323                 rret[0]->RRinfoupdated = extract_int(cret, 3);
324                 rret[0]->RRflags = extract_int(cret, 4);
325                 rret[0]->RRhighest = extract_long(cret, 5);
326                 rret[0]->RRlastread = extract_long(cret, 6);
327                 rret[0]->RRismailbox = extract_int(cret, 7);
328                 rret[0]->RRaide = extract_int(cret, 8);
329                 rret[0]->RRnewmail = extract_long(cret, 9);
330                 rret[0]->RRfloor = extract_int(cret, 10);
331         } else {
332                 free(*rret);
333         }
334         return ret;
335 }
336
337
338 /* MSGS */
339 /* which is 0 = all, 1 = old, 2 = new, 3 = last, 4 = first, 5 = gt, 6 = lt */
340 /* whicharg is number of messages, applies to last, first, gt, lt */
341 int CtdlIPCGetMessages(int which, int whicharg, const char *template,
342                 long **mret, char *cret)
343 {
344         register int ret;
345         register long count = 0;
346         static char *proto[] =
347                 { "ALL", "OLD", "NEW", "LAST", "FIRST", "GT", "LT" };
348         char aaa[33];
349         char *bbb;
350         size_t bbbsize;
351
352         if (!cret) return -2;
353         if (!mret) return -2;
354         if (*mret) return -2;
355         if (which < 0 || which > 6) return -2;
356
357         if (which <= 2)
358                 sprintf(aaa, "MSGS %s||%d", proto[which],
359                                 (template) ? 1 : 0);
360         else
361                 sprintf(aaa, "MSGS %s|%d|%d", proto[which], whicharg,
362                                 (template) ? 1 : 0);
363         if (template) count = strlen(template);
364         ret = CtdlIPCGenericCommand(aaa, template, count, &bbb, &bbbsize, cret);
365         count = 0;
366         while (strlen(bbb)) {
367                 int a;
368
369                 extract_token(aaa, bbb, 0, '\n');
370                 a = strlen(aaa);
371                 memmove(aaa, bbb + a + 1, strlen(bbb) - a - 1);
372                 *mret = (long *)realloc(mret, (count + 1) * sizeof (long));
373                 if (*mret)
374                         *mret[count++] = atol(aaa);
375                 *mret[count] = 0L;
376         }
377         return ret;
378 }
379
380
381 /* MSG0, MSG2 */
382 int CtdlIPCGetSingleMessage(long msgnum, int headers, int as_mime,
383                 struct ctdlipcmessage **mret, char *cret)
384 {
385         register int ret;
386         char aaa[27];
387         char *bbb;
388         size_t bbbsize;
389
390         if (!cret) return -1;
391         if (!mret) return -1;
392         if (!*mret) *mret = (struct ctdlipcmessage *)calloc(1, sizeof (struct ctdlipcmessage));
393         if (!*mret) return -1;
394         if (!msgnum) return -1;
395
396         sprintf(aaa, "MSG%c %ld|%d", as_mime ? '2' : '0', msgnum, headers);
397         ret = CtdlIPCGenericCommand(aaa, NULL, 0, &bbb, &bbbsize, cret);
398         if (ret / 100 == 1) {
399                 if (!as_mime) {
400                         while (strlen(bbb) > 4 && bbb[4] == '=') {
401                                 int a;
402
403                                 extract_token(aaa, bbb, 0, '\n');
404                                 a = strlen(aaa);
405                                 memmove(aaa, bbb + a + 1, strlen(bbb) - a - 1);
406
407                                 if (!strncasecmp(aaa, "nhdr=yes", 8))
408                                         mret[0]->nhdr = 1;
409                                 else if (!strncasecmp(aaa, "from=", 5))
410                                         strcpy(mret[0]->author, &aaa[5]);
411                                 else if (!strncasecmp(aaa, "type=", 5))
412                                         mret[0]->type = atoi(&aaa[5]);
413                                 else if (!strncasecmp(aaa, "msgn=", 5))
414                                         strcpy(mret[0]->msgid, &aaa[5]);
415                                 else if (!strncasecmp(aaa, "subj=", 5))
416                                         strcpy(mret[0]->subject, &aaa[5]);
417                                 else if (!strncasecmp(aaa, "rfca=", 5))
418                                         strcpy(mret[0]->email, &aaa[5]);
419                                 else if (!strncasecmp(aaa, "hnod=", 5))
420                                         strcpy(mret[0]->hnod, &aaa[5]);
421                                 else if (!strncasecmp(aaa, "room=", 5))
422                                         strcpy(mret[0]->room, &aaa[5]);
423                                 else if (!strncasecmp(aaa, "node=", 5))
424                                         strcpy(mret[0]->node, &aaa[5]);
425                                 else if (!strncasecmp(aaa, "rcpt=", 5))
426                                         strcpy(mret[0]->recipient, &aaa[5]);
427                                 else if (!strncasecmp(aaa, "time=", 5))
428                                         mret[0]->time = atol(&aaa[5]);
429                                 else if (!strncasecmp(aaa, "part=", 5)) {
430                                         struct parts *ptr, *chain;
431         
432                                         ptr = (struct parts *)calloc(1, sizeof (struct parts));
433                                         if (ptr) {
434                                                 extract(ptr->name, &aaa[5], 0);
435                                                 extract(ptr->filename, &aaa[5], 1);
436                                                 extract(ptr->number, &aaa[5], 2);
437                                                 extract(ptr->disposition, &aaa[5], 3);
438                                                 extract(ptr->mimetype, &aaa[5], 4);
439                                                 ptr->length = extract_long(&aaa[5], 5);
440                                                 if (!mret[0]->attachments)
441                                                         mret[0]->attachments = ptr;
442                                                 else {
443                                                         chain = mret[0]->attachments;
444                                                         while (chain->next)
445                                                                 chain = chain->next;
446                                                         chain->next = ptr;
447                                                 }
448                                         }
449                                 }
450                         }
451                 }
452                 if (strlen(bbb)) {
453                         bbb = (char *)realloc(bbb, strlen(bbb) + 1);
454                         mret[0]->text = bbb;
455                 } else {
456                         free(bbb);
457                 }
458         }
459         return ret;
460 }
461
462
463 /* WHOK */
464 int CtdlIPCWhoKnowsRoom(char **listing, char *cret)
465 {
466         register int ret;
467         size_t bytes;
468
469         if (!cret) return -2;
470         if (!listing) return -2;
471         if (*listing) return -2;
472
473         ret = CtdlIPCGenericCommand("WHOK", NULL, 0, listing, &bytes, cret);
474         return ret;
475 }
476
477
478 /* INFO */
479 int CtdlIPCServerInfo(char **listing, char *cret)
480 {
481         register int ret;
482         size_t bytes;
483
484         if (!cret) return -2;
485         if (!listing) return -2;
486         if (*listing) return -2;
487
488         ret = CtdlIPCGenericCommand("INFO", NULL, 0, listing, &bytes, cret);
489         return ret;
490 }
491
492
493 /* RDIR */
494 int CtdlIPCReadDirectory(char **listing, char *cret)
495 {
496         register int ret;
497         size_t bytes;
498
499         if (!cret) return -2;
500         if (!listing) return -2;
501         if (*listing) return -2;
502
503         ret = CtdlIPCGenericCommand("RDIR", NULL, 0, listing, &bytes, cret);
504         return ret;
505 }
506
507
508 /*
509  * Set last-read pointer in this room to msgnum, or 0 for HIGHEST.
510  */
511 int CtdlIPCSetLastRead(long msgnum, char *cret)
512 {
513         register int ret;
514         char aaa[16];
515
516         if (!cret) return -2;
517
518         if (msgnum)
519                 sprintf(aaa, "SLRP %ld", msgnum);
520         else
521                 sprintf(aaa, "SLRP HIGHEST");
522         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
523         return ret;
524 }
525
526
527 /* INVT */
528 int CtdlIPCInviteUserToRoom(const char *username, char *cret)
529 {
530         register int ret;
531         char *aaa;
532
533         if (!cret) return -2;
534         if (!username) return -2;
535
536         aaa = (char *)malloc(strlen(username) + 6);
537         if (!aaa) return -1;
538
539         sprintf(aaa, "INVT %s", username);
540         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
541         free(aaa);
542         return ret;
543 }
544
545
546 /* KICK */
547 int CtdlIPCKickoutUserFromRoom(const char *username, char *cret)
548 {
549         register int ret;
550         char *aaa;
551
552         if (!cret) return -1;
553         if (!username) return -1;
554
555         aaa = (char *)malloc(strlen(username) + 6);
556
557         sprintf(aaa, "KICK %s", username);
558         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
559         free(aaa);
560         return ret;
561 }
562
563
564 /* GETR */
565 int CtdlIPCGetRoomAttributes(struct quickroom **qret, char *cret)
566 {
567         register int ret;
568
569         if (!cret) return -2;
570         if (!qret) return -2;
571         if (!*qret) *qret = (struct quickroom *)calloc(1, sizeof (struct quickroom));
572         if (!*qret) return -1;
573
574         ret = CtdlIPCGenericCommand("GETR", NULL, 0, NULL, NULL, cret);
575         if (ret / 100 == 2) {
576                 extract(qret[0]->QRname, cret, 0);
577                 extract(qret[0]->QRpasswd, cret, 1);
578                 extract(qret[0]->QRdirname, cret, 2);
579                 qret[0]->QRflags = extract_int(cret, 3);
580                 qret[0]->QRfloor = extract_int(cret, 4);
581                 qret[0]->QRorder = extract_int(cret, 5);
582         }
583         return ret;
584 }
585
586
587 /* SETR */
588 /* set forget to kick all users out of room */
589 int CtdlIPCSetRoomAttributes(int forget, struct quickroom *qret, char *cret)
590 {
591         register int ret;
592         char *aaa;
593
594         if (!cret) return -2;
595         if (!qret) return -2;
596
597         aaa = (char *)malloc(strlen(qret->QRname) + strlen(qret->QRpasswd) +
598                         strlen(qret->QRdirname) + 52);
599         if (!aaa) return -1;
600
601         sprintf(aaa, "SETR %s|%s|%s|%d|%d|%d|%d",
602                         qret->QRname, qret->QRpasswd, qret->QRdirname,
603                         qret->QRflags, forget, qret->QRfloor, qret->QRorder);
604         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
605         free(aaa);
606         return ret;
607 }
608
609
610 /* GETA */
611 int CtdlIPCGetRoomAide(char *cret)
612 {
613         if (!cret) return -1;
614
615         return CtdlIPCGenericCommand("GETA", NULL, 0, NULL, NULL, cret);
616 }
617
618
619 /* SETA */
620 int CtdlIPCSetRoomAide(const char *username, char *cret)
621 {
622         register int ret;
623         char *aaa;
624
625         if (!cret) return -2;
626         if (!username) return -2;
627
628         aaa = (char *)malloc(strlen(username) + 6);
629         if (!aaa) return -1;
630
631         sprintf(aaa, "SETA %s", username);
632         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
633         free(aaa);
634         return ret;
635 }
636
637
638 /* ENT0 */
639 int CtdlIPCPostMessage(int flag, const struct ctdlipcmessage *mr, char *cret)
640 {
641         register int ret;
642         char *aaa;
643
644         if (!cret) return -2;
645         if (!mr) return -2;
646
647         aaa = (char *)malloc(strlen(mr->recipient) + strlen(mr->author) + 40);
648         if (!aaa) return -1;
649
650         sprintf(aaa, "ENT0 %d|%s|%d|%d|%s", flag, mr->recipient, mr->anonymous,
651                         mr->type, mr->author);
652         ret = CtdlIPCGenericCommand(aaa, mr->text, strlen(mr->text), NULL,
653                         NULL, cret);
654         free(aaa);
655         return ret;
656 }
657
658
659 /* RINF */
660 int CtdlIPCRoomInfo(char **iret, char *cret)
661 {
662         size_t bytes;
663
664         if (!cret) return -2;
665         if (!iret) return -2;
666         if (*iret) return -2;
667
668         return CtdlIPCGenericCommand("RINF", NULL, 0, iret, &bytes, cret);
669 }
670
671
672 /* DELE */
673 int CtdlIPCDeleteMessage(long msgnum, char *cret)
674 {
675         char aaa[16];
676
677         if (!cret) return -2;
678         if (!msgnum) return -2;
679
680         sprintf(aaa, "DELE %ld", msgnum);
681         return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
682 }
683
684
685 /* MOVE */
686 int CtdlIPCMoveMessage(int copy, long msgnum, const char *destroom, char *cret)
687 {
688         register int ret;
689         char *aaa;
690
691         if (!cret) return -2;
692         if (!destroom) return -2;
693         if (!msgnum) return -2;
694
695         aaa = (char *)malloc(strlen(destroom) + 28);
696         if (!aaa) return -1;
697
698         sprintf(aaa, "MOVE %ld|%s|%d", msgnum, destroom, copy);
699         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
700         free(aaa);
701         return ret;
702 }
703
704
705 /* KILL */
706 int CtdlIPCDeleteRoom(int for_real, char *cret)
707 {
708         char aaa[16];
709
710         if (!cret) return -2;
711
712         sprintf(aaa, "KILL %d", for_real);
713         return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
714 }
715
716
717 /* CRE8 */
718 int CtdlIPCCreateRoom(int for_real, const char *roomname, int type,
719                 const char *password, int floor, char *cret)
720 {
721         register int ret;
722         char *aaa;
723
724         if (!cret) return -2;
725         if (!roomname) return -2;
726
727         if (password) {
728                 aaa = (char *)malloc(strlen(roomname) + strlen(password) + 40);
729                 if (!aaa) return -1;
730                 sprintf(aaa, "CRE8 %d|%s|%d|%s|%d", for_real, roomname, type,
731                                 password, floor);
732         } else {
733                 aaa = (char *)malloc(strlen(roomname) + 40);
734                 if (!aaa) return -1;
735                 sprintf(aaa, "CRE8 %d|%s|%d||%d", for_real, roomname, type,
736                                 floor);
737         }
738         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
739         free(aaa);
740         return ret;
741 }
742
743
744 /* FORG */
745 int CtdlIPCForgetRoom(char *cret)
746 {
747         if (!cret) return -2;
748
749         return CtdlIPCGenericCommand("FORG", NULL, 0, NULL, NULL, cret);
750 }
751
752
753 /* MESG */
754 int CtdlIPCSystemMessage(const char *message, char **mret, char *cret)
755 {
756         register int ret;
757         char *aaa;
758         size_t bytes;
759
760         if (!cret) return -2;
761         if (!mret) return -2;
762         if (*mret) return -2;
763         if (!message) return -2;
764
765         aaa = (char *)malloc(strlen(message) + 6);
766         if (!aaa) return -1;
767
768         sprintf(aaa, "MESG %s", message);
769         ret = CtdlIPCGenericCommand(aaa, NULL, 0, mret, &bytes, cret);
770         free(aaa);
771         return ret;
772 }
773
774
775 /* GNUR */
776 int CtdlIPCNextUnvalidatedUser(char *cret)
777 {
778         if (!cret) return -2;
779
780         return CtdlIPCGenericCommand("GNUR", NULL, 0, NULL, NULL, cret);
781 }
782
783
784 /* GREG */
785 int CtdlIPCGetUserRegistration(const char *username, char **rret, char *cret)
786 {
787         register int ret;
788         char *aaa;
789         size_t bytes;
790
791         if (!cret) return -2;
792         if (!rret) return -2;
793         if (*rret) return -2;
794
795         if (username)
796                 aaa = (char *)malloc(strlen(username) + 6);
797         else
798                 aaa = (char *)malloc(12);
799         if (!aaa) return -1;
800
801         if (username)
802                 sprintf(aaa, "GREG %s", username);
803         else
804                 sprintf(aaa, "GREG _SELF_");
805         ret = CtdlIPCGenericCommand(aaa, NULL, 0, rret, &bytes, cret);
806         free(aaa);
807         return ret;
808 }
809
810
811 /* VALI */
812 int CtdlIPCValidateUser(const char *username, int axlevel, char *cret)
813 {
814         register int ret;
815         char *aaa;
816
817         if (!cret) return -2;
818         if (!username) return -2;
819         if (axlevel < 0 || axlevel > 7) return -2;
820
821         aaa = (char *)malloc(strlen(username) + 17);
822         if (!aaa) return -1;
823
824         sprintf(aaa, "VALI %s|%d", username, axlevel);
825         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
826         free(aaa);
827         return ret;
828 }
829
830
831 /* EINF */
832 int CtdlIPCSetRoomInfo(int for_real, const char *info, char *cret)
833 {
834         char aaa[16];
835
836         if (!cret) return -1;
837         if (!info) return -1;
838
839         sprintf(aaa, "EINF %d", for_real);
840         return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
841 }
842
843
844 /* LIST */
845 int CtdlIPCUserListing(char **listing, char *cret)
846 {
847         size_t bytes;
848
849         if (!cret) return -1;
850         if (!listing) return -1;
851         if (*listing) return -1;
852
853         return CtdlIPCGenericCommand("LIST", NULL, 0, listing, &bytes, cret);
854 }
855
856
857 /* REGI */
858 int CtdlIPCSetRegistration(const char *info, char *cret)
859 {
860         if (!cret) return -1;
861         if (!info) return -1;
862
863         return CtdlIPCGenericCommand("REGI", info, strlen(info),
864                         NULL, NULL, cret);
865 }
866
867
868 /* CHEK */
869 int CtdlIPCMiscCheck(struct ctdlipcmisc *chek, char *cret)
870 {
871         register int ret;
872
873         if (!cret) return -1;
874         if (!chek) return -1;
875
876         ret = CtdlIPCGenericCommand("CHEK", NULL, 0, NULL, NULL, cret);
877         if (ret / 100 == 2) {
878                 chek->newmail = extract_long(cret, 0);
879                 chek->needregis = extract_int(cret, 1);
880                 chek->needvalid = extract_int(cret, 2);
881         }
882         return ret;
883 }
884
885
886 /* DELF */
887 int CtdlIPCDeleteFile(const char *filename, char *cret)
888 {
889         register int ret;
890         char *aaa;
891
892         if (!cret) return -2;
893         if (!filename) return -2;
894         
895         aaa = (char *)malloc(strlen(filename) + 6);
896         if (!aaa) return -1;
897
898         sprintf(aaa, "DELF %s", filename);
899         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
900         free(aaa);
901         return ret;
902 }
903
904
905 /* MOVF */
906 int CtdlIPCMoveFile(const char *filename, const char *destroom, char *cret)
907 {
908         register int ret;
909         char *aaa;
910
911         if (!cret) return -2;
912         if (!filename) return -2;
913         if (!destroom) return -2;
914
915         aaa = (char *)malloc(strlen(filename) + strlen(destroom) + 7);
916         if (!aaa) return -1;
917
918         sprintf(aaa, "MOVF %s|%s", filename, destroom);
919         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
920         free(aaa);
921         return ret;
922 }
923
924
925 /* NETF */
926 int CtdlIPCNetSendFile(const char *filename, const char *destnode, char *cret)
927 {
928         register int ret;
929         char *aaa;
930
931         if (!cret) return -2;
932         if (!filename) return -2;
933         if (!destnode) return -2;
934
935         aaa = (char *)malloc(strlen(filename) + strlen(destnode) + 7);
936         if (!aaa) return -1;
937
938         sprintf(aaa, "NETF %s|%s", filename, destnode);
939         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
940         free(aaa);
941         return ret;
942 }
943
944
945 /* RWHO */
946 int CtdlIPCOnlineUsers(char **listing, time_t *stamp, char *cret)
947 {
948         register int ret;
949         size_t bytes;
950
951         if (!cret) return -1;
952         if (!listing) return -1;
953         if (*listing) return -1;
954
955         *stamp = CtdlIPCServerTime(cret);
956         if (!*stamp)
957                 *stamp = time(NULL);
958         ret = CtdlIPCGenericCommand("RWHO", NULL, 0, listing, &bytes, cret);
959         return ret;
960 }
961
962
963 /* OPEN */
964 int CtdlIPCFileDownload(const char *filename, void **buf, char *cret)
965 {
966         register int ret;
967         size_t bytes;
968         time_t last_mod;
969         char mimetype[256];
970         char *aaa;
971
972         if (!cret) return -2;
973         if (!filename) return -2;
974         if (!buf) return -2;
975         if (*buf) return -2;
976         if (download_in_progress) return -2;
977
978         aaa = (char *)malloc(strlen(filename) + 6);
979         if (!aaa) return -1;
980
981         sprintf(aaa, "OPEN %s", filename);
982         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
983         free(aaa);
984         /* FIXME: Possible race condition */
985         if (ret / 100 == 2) {
986                 download_in_progress = 1;
987                 bytes = extract_long(cret, 0);
988                 last_mod = extract_int(cret, 1);
989                 extract(mimetype, cret, 2);
990                 ret = CtdlIPCReadDownload(buf, bytes, cret);
991                 ret = CtdlIPCEndDownload(cret);
992                 if (ret / 100 == 2)
993                         sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
994                                         filename, mimetype);
995         }
996         return ret;
997 }
998
999
1000 /* OPNA */
1001 int CtdlIPCAttachmentDownload(long msgnum, const char *part, void **buf,
1002                 char *cret)
1003 {
1004         register int ret;
1005         size_t bytes;
1006         time_t last_mod;
1007         char filename[256];
1008         char mimetype[256];
1009         char *aaa;
1010
1011         if (!cret) return -2;
1012         if (!buf) return -2;
1013         if (*buf) return -2;
1014         if (!part) return -2;
1015         if (!msgnum) return -2;
1016         if (download_in_progress) return -2;
1017
1018         aaa = (char *)malloc(strlen(part) + 17);
1019         if (!aaa) return -1;
1020
1021         sprintf(aaa, "OPNA %ld|%s", msgnum, part);
1022         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1023         free(aaa);
1024         /* FIXME: Possible race condition */
1025         if (ret / 100 == 2) {
1026                 download_in_progress = 1;
1027                 bytes = extract_long(cret, 0);
1028                 last_mod = extract_int(cret, 1);
1029                 extract(mimetype, cret, 2);
1030                 ret = CtdlIPCReadDownload(buf, bytes, cret);
1031                 ret = CtdlIPCEndDownload(cret);
1032                 if (ret / 100 == 2)
1033                         sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1034                                         filename, mimetype);
1035         }
1036         return ret;
1037 }
1038
1039
1040 /* OIMG */
1041 int CtdlIPCImageDownload(const char *filename, void **buf, char *cret)
1042 {
1043         register int ret;
1044         size_t bytes;
1045         time_t last_mod;
1046         char mimetype[256];
1047         char *aaa;
1048
1049         if (!cret) return -1;
1050         if (!buf) return -1;
1051         if (*buf) return -1;
1052         if (!filename) return -1;
1053         if (download_in_progress) return -1;
1054
1055         aaa = (char *)malloc(strlen(filename) + 6);
1056         if (!aaa) return -1;
1057
1058         sprintf(aaa, "OIMG %s", filename);
1059         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1060         free(aaa);
1061         /* FIXME: Possible race condition */
1062         if (ret / 100 == 2) {
1063                 download_in_progress = 1;
1064                 bytes = extract_long(cret, 0);
1065                 last_mod = extract_int(cret, 1);
1066                 extract(mimetype, cret, 2);
1067                 ret = CtdlIPCReadDownload(buf, bytes, cret);
1068                 ret = CtdlIPCEndDownload(cret);
1069                 if (ret / 100 == 2)
1070                         sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1071                                         filename, mimetype);
1072         }
1073         return ret;
1074 }
1075
1076
1077 /* UOPN */
1078 int CtdlIPCFileUpload(const char *filename, const char *comment, void *buf,
1079                 size_t bytes, char *cret)
1080 {
1081         register int ret;
1082         char *aaa;
1083
1084         if (!cret) return -1;
1085         if (!filename) return -1;
1086         if (!comment) return -1;
1087         if (upload_in_progress) return -1;
1088
1089         aaa = (char *)malloc(strlen(filename) + strlen(comment) + 7);
1090         if (!aaa) return -1;
1091
1092         sprintf(aaa, "UOPN %s|%s", filename, comment);
1093         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1094         free(aaa);
1095         /* FIXME: Possible race condition */
1096         if (ret / 100 == 2)
1097                 upload_in_progress = 1;
1098         ret = CtdlIPCWriteUpload(buf, bytes, cret);
1099         ret = CtdlIPCEndUpload(cret);
1100         return ret;
1101 }
1102
1103
1104 /* UIMG */
1105 int CtdlIPCImageUpload(int for_real, const char *filename, size_t bytes,
1106                 char *cret)
1107 {
1108         register int ret;
1109         char *aaa;
1110
1111         if (!cret) return -1;
1112         if (!filename) return -1;
1113         if (upload_in_progress) return -1;
1114
1115         aaa = (char *)malloc(strlen(filename) + 17);
1116         if (!aaa) return -1;
1117
1118         sprintf(aaa, "UIMG %d|%s", for_real, filename);
1119         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1120         free(aaa);
1121         /* FIXME: Possible race condition */
1122         if (ret / 100 == 2)
1123                 upload_in_progress = 1;
1124         return ret;
1125 }
1126
1127
1128 /* QUSR */
1129 int CtdlIPCQueryUsername(const char *username, char *cret)
1130 {
1131         register int ret;
1132         char *aaa;
1133
1134         if (!cret) return -2;
1135         if (!username) return -2;
1136
1137         aaa = (char *)malloc(strlen(username) + 6);
1138         if (!aaa) return -1;
1139
1140         sprintf(aaa, "QUSR %s", username);
1141         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1142         free(aaa);
1143         return ret;
1144 }
1145
1146
1147 /* LFLR */
1148 int CtdlIPCFloorListing(char **listing, char *cret)
1149 {
1150         size_t bytes;
1151
1152         if (!cret) return -2;
1153         if (!listing) return -2;
1154         if (*listing) return -2;
1155
1156         return CtdlIPCGenericCommand("LFLR", NULL, 0, listing, &bytes, cret);
1157 }
1158
1159
1160 /* CFLR */
1161 int CtdlIPCCreateFloor(int for_real, const char *name, char *cret)
1162 {
1163         register int ret;
1164         char *aaa;
1165
1166         if (!cret) return -2;
1167         if (!name) return -2;
1168
1169         aaa = (char *)malloc(strlen(name) + 17);
1170         if (!aaa) return -1;
1171
1172         sprintf(aaa, "CFLR %s|%d", name, for_real);
1173         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1174         free(aaa);
1175         return ret;
1176 }
1177
1178
1179 /* KFLR */
1180 int CtdlIPCDeleteFloor(int for_real, int floornum, char *cret)
1181 {
1182         char aaa[27];
1183
1184         if (!cret) return -1;
1185         if (floornum < 0) return -1;
1186
1187         sprintf(aaa, "KFLR %d|%d", floornum, for_real);
1188         return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1189 }
1190
1191
1192 /* EFLR */
1193 int CtdlIPCEditFloor(int floornum, const char *floorname, char *cret)
1194 {
1195         register int ret;
1196         char *aaa;
1197
1198         if (!cret) return -2;
1199         if (!floorname) return -2;
1200         if (floornum < 0) return -2;
1201
1202         aaa = (char *)malloc(strlen(floorname) + 17);
1203         if (!aaa) return -1;
1204
1205         sprintf(aaa, "EFLR %d|%s", floornum, floorname);
1206         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1207         free(aaa);
1208         return ret;
1209 }
1210
1211
1212 /* IDEN */
1213 int CtdlIPCIdentifySoftware(int developerid, int clientid, int revision,
1214                 const char *software_name, const char *hostname, char *cret)
1215 {
1216         register int ret;
1217         char *aaa;
1218
1219         if (developerid < 0) return -2;
1220         if (clientid < 0) return -2;
1221         if (revision < 0) return -2;
1222         if (!software_name) return -2;
1223         if (!hostname) return -2;
1224
1225         aaa = (char *)malloc(strlen(software_name) + strlen(hostname) + 29);
1226         if (!aaa) return -1;
1227
1228         sprintf(aaa, "IDEN %d|%d|%d|%s|%s", developerid, clientid,
1229                         revision, software_name, hostname);
1230         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1231         free(aaa);
1232         return ret;
1233 }
1234
1235
1236 /* SEXP */
1237 int CtdlIPCSendInstantMessage(const char *username, const char *text,
1238                 char *cret)
1239 {
1240         register int ret;
1241         char *aaa;
1242
1243         if (!cret) return -2;
1244         if (!username) return -2;
1245
1246         aaa = (char *)malloc(strlen(username) + 8);
1247         if (!aaa) return -1;
1248
1249         if (text) {
1250                 sprintf(aaa, "SEXP %s|-", username);
1251                 ret = CtdlIPCGenericCommand(aaa, text, strlen(text),
1252                                 NULL, NULL, cret);
1253         } else {
1254                 sprintf(aaa, "SEXP %s||", username);
1255                 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1256         }
1257         free(aaa);
1258         return ret;
1259 }
1260
1261
1262 /* GEXP */
1263 int CtdlIPCGetInstantMessage(char **listing, char *cret)
1264 {
1265         size_t bytes;
1266
1267         if (!cret) return -2;
1268         if (!listing) return -2;
1269         if (*listing) return -2;
1270
1271         return CtdlIPCGenericCommand("GEXP", NULL, 0, listing, &bytes, cret);
1272 }
1273
1274
1275 /* DEXP */
1276 /* mode is 0 = enable, 1 = disable, 2 = status */
1277 int CtdlIPCEnableInstantMessageReceipt(int mode, char *cret)
1278 {
1279         char aaa[16];
1280
1281         if (!cret) return -2;
1282
1283         sprintf(aaa, "DEXP %d", mode);
1284         return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1285 }
1286
1287
1288 /* EBIO */
1289 int CtdlIPCSetBio(char *bio, char *cret)
1290 {
1291         if (!cret) return -2;
1292         if (!bio) return -2;
1293
1294         return CtdlIPCGenericCommand("EBIO", bio, strlen(bio),
1295                         NULL, NULL, cret);
1296 }
1297
1298
1299 /* RBIO */
1300 int CtdlIPCGetBio(const char *username, char **listing, char *cret)
1301 {
1302         register int ret;
1303         size_t bytes;
1304         char *aaa;
1305
1306         if (!cret) return -2;
1307         if (!username) return -2;
1308         if (!listing) return -2;
1309         if (*listing) return -2;
1310
1311         aaa = (char *)malloc(strlen(username) + 6);
1312         if (!aaa) return -1;
1313
1314         sprintf(aaa, "RBIO %s", username);
1315         ret = CtdlIPCGenericCommand(aaa, NULL, 0, listing, &bytes, cret);
1316         free(aaa);
1317         return ret;
1318 }
1319
1320
1321 /* LBIO */
1322 int CtdlIPCListUsersWithBios(char **listing, char *cret)
1323 {
1324         size_t bytes;
1325
1326         if (!cret) return -2;
1327         if (!listing) return -2;
1328         if (*listing) return -2;
1329
1330         return CtdlIPCGenericCommand("LBIO", NULL, 0, listing, &bytes, cret);
1331 }
1332
1333
1334 /* STEL */
1335 int CtdlIPCStealthMode(int mode, char *cret)
1336 {
1337         char aaa[16];
1338
1339         if (!cret) return -1;
1340
1341         sprintf(aaa, "STEL %d", mode ? 1 : 0);
1342         return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1343 }
1344
1345
1346 /* TERM */
1347 int CtdlIPCTerminateSession(int sid, char *cret)
1348 {
1349         char aaa[16];
1350
1351         if (!cret) return -1;
1352
1353         sprintf(aaa, "TERM %d", sid);
1354         return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1355 }
1356
1357
1358 /* DOWN */
1359 int CtdlIPCTerminateServerNow(char *cret)
1360 {
1361         if (!cret) return -1;
1362
1363         return CtdlIPCGenericCommand("DOWN", NULL, 0, NULL, NULL, cret);
1364 }
1365
1366
1367 /* SCDN */
1368 int CtdlIPCTerminateServerScheduled(int mode, char *cret)
1369 {
1370         char aaa[16];
1371
1372         if (!cret) return -1;
1373
1374         sprintf(aaa, "SCDN %d", mode ? 1 : 0);
1375         return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1376 }
1377
1378
1379 /* EMSG */
1380 int CtdlIPCEnterSystemMessage(const char *filename, const char *text,
1381                 char *cret)
1382 {
1383         register int ret;
1384         char *aaa;
1385
1386         if (!cret) return -2;
1387         if (!text) return -2;
1388         if (!filename) return -2;
1389
1390         aaa = (char *)malloc(strlen(filename) + 6);
1391         if (!aaa) return -1;
1392
1393         sprintf(aaa, "EMSG %s", filename);
1394         ret = CtdlIPCGenericCommand(aaa, text, strlen(text), NULL, NULL, cret);
1395         free(aaa);
1396         return ret;
1397 }
1398
1399
1400 /* HCHG */
1401 int CtdlIPCChangeHostname(const char *hostname, char *cret)
1402 {
1403         register int ret;
1404         char *aaa;
1405
1406         if (!cret) return -2;
1407         if (!hostname) return -2;
1408
1409         aaa = (char *)malloc(strlen(hostname) + 6);
1410         if (!aaa) return -1;
1411
1412         sprintf(aaa, "HCHG %s", hostname);
1413         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1414         free(aaa);
1415         return ret;
1416 }
1417
1418
1419 /* RCHG */
1420 int CtdlIPCChangeRoomname(const char *roomname, char *cret)
1421 {
1422         register int ret;
1423         char *aaa;
1424
1425         if (!cret) return -2;
1426         if (!roomname) return -2;
1427
1428         aaa = (char *)malloc(strlen(roomname) + 6);
1429         if (!aaa) return -1;
1430
1431         sprintf(aaa, "RCHG %s", roomname);
1432         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1433         free(aaa);
1434         return ret;
1435 }
1436
1437
1438 /* UCHG */
1439 int CtdlIPCChangeUsername(const char *username, char *cret)
1440 {
1441         register int ret;
1442         char *aaa;
1443
1444         if (!cret) return -2;
1445         if (!username) return -2;
1446
1447         aaa = (char *)malloc(strlen(username) + 6);
1448         if (!aaa) return -1;
1449
1450         sprintf(aaa, "UCHG %s", username);
1451         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1452         free(aaa);
1453         return ret;
1454 }
1455
1456
1457 /* TIME */
1458 /* This function returns the actual server time reported, or 0 if error */
1459 time_t CtdlIPCServerTime(char *cret)
1460 {
1461         register time_t tret;
1462         register int ret;
1463
1464         ret = CtdlIPCGenericCommand("TIME", NULL, 0, NULL, NULL, cret);
1465         if (ret / 100 == 2) {
1466                 tret = extract_long(cret, 0);
1467         } else {
1468                 tret = 0L;
1469         }
1470         return tret;
1471 }
1472
1473
1474 /* AGUP */
1475 int CtdlIPCAideGetUserParameters(struct usersupp **uret, char *cret)
1476 {
1477         register int ret;
1478         char *aaa;
1479
1480         if (!cret) return -2;
1481         if (!uret) return -2;
1482         if (!*uret) return -2;
1483
1484         aaa = (char *)malloc(strlen(uret[0]->fullname) + 6);
1485         if (!aaa) return -1;
1486
1487         sprintf(aaa, "AGUP %s", uret[0]->fullname);
1488         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1489         if (ret / 100 == 2) {
1490                 extract(uret[0]->fullname, cret, 0);
1491                 extract(uret[0]->password, cret, 1);
1492                 uret[0]->flags = extract_int(cret, 2);
1493                 uret[0]->timescalled = extract_long(cret, 3);
1494                 uret[0]->posted = extract_long(cret, 4);
1495                 uret[0]->axlevel = extract_int(cret, 5);
1496                 uret[0]->usernum = extract_long(cret, 6);
1497                 uret[0]->lastcall = extract_long(cret, 7);
1498                 uret[0]->USuserpurge = extract_int(cret, 8);
1499         }
1500         free(aaa);
1501         return ret;
1502 }
1503
1504
1505 /* ASUP */
1506 int CtdlIPCAideSetUserParameters(const struct usersupp *uret, char *cret)
1507 {
1508         register int ret;
1509         char *aaa;
1510
1511         if (!cret) return -2;
1512         if (!uret) return -2;
1513
1514         aaa = (char *)malloc(strlen(uret->fullname) + strlen(uret->password) + 84);
1515         if (!aaa) return -1;
1516
1517         sprintf(aaa, "ASUP %s|%s|%d|%ld|%ld|%d|%ld|%ld|%d",
1518                         uret->fullname, uret->password, uret->flags,
1519                         uret->timescalled, uret->posted, uret->axlevel,
1520                         uret->usernum, uret->lastcall, uret->USuserpurge);
1521         ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1522         free(aaa);
1523         return ret;
1524 }
1525
1526
1527 /* GPEX */
1528 /* which is 0 = room, 1 = floor, 2 = site */
1529 int CtdlIPCGetMessageExpirationPolicy(int which, char *cret)
1530 {
1531         static char *proto[] = {"room", "floor", "site"};
1532         char aaa[11];
1533
1534         if (!cret) return -2;
1535         if (which < 0 || which > 2) return -2;
1536         
1537         sprintf(aaa, "GPEX %s", proto[which]);
1538         return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1539 }
1540
1541
1542 /* SPEX */
1543 /* which is 0 = room, 1 = floor, 2 = site */
1544 /* policy is 0 = inherit, 1 = no purge, 2 = by count, 3 = by age (days) */
1545 int CtdlIPCSetMessageExpirationPolicy(int which, int policy, int value,
1546                 char *cret)
1547 {
1548         char aaa[38];
1549
1550         if (!cret) return -2;
1551         if (which < 0 || which > 2) return -2;
1552         if (policy < 0 || policy > 3) return -2;
1553         if (policy >= 2 && value < 1) return -2;
1554
1555         sprintf(aaa, "SPEX %d|%d|%d", which, policy, value);
1556         return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1557 }
1558
1559
1560 /* CONF GET */
1561 int CtdlGetSystemConfig(char **listing, char *cret)
1562 {
1563         size_t bytes;
1564
1565         if (!cret) return -2;
1566         if (!listing) return -2;
1567         if (*listing) return -2;
1568
1569         return CtdlIPCGenericCommand("CONF GET", NULL, 0,
1570                         listing, &bytes, cret);
1571 }
1572
1573
1574 /* CONF SET */
1575 int CtdlSetSystemConfig(const char *listing, char *cret)
1576 {
1577         if (!cret) return -2;
1578         if (!listing) return -2;
1579
1580         return CtdlIPCGenericCommand("CONF SET", listing, strlen(listing),
1581                         NULL, NULL, cret);
1582 }
1583
1584
1585 /* MMOD */
1586 int CtdlIPCModerateMessage(long msgnum, int level, char *cret)
1587 {
1588         char aaa[27];
1589
1590         if (!cret) return -2;
1591         if (!msgnum) return -2;
1592
1593         sprintf(aaa, "MMOD %ld|%d", msgnum, level);
1594         return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1595 }
1596
1597
1598 /* REQT */
1599 int CtdlIPCRequestClientLogout(int session, char *cret)
1600 {
1601         char aaa[16];
1602
1603         if (!cret) return -2;
1604         if (session < 0) return -2;
1605
1606         sprintf(aaa, "REQT %d", session);
1607         return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1608 }
1609
1610
1611 /* SEEN */
1612 int CtdlIPCSetMessageSeen(long msgnum, int seen, char *cret)
1613 {
1614         char aaa[27];
1615
1616         if (!cret) return -2;
1617         if (msgnum < 0) return -2;
1618
1619         sprintf(aaa, "SEEN %ld|%d", msgnum, seen ? 1 : 0);
1620         return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1621 }
1622
1623
1624 /* STLS */
1625 int CtdlIPCStartEncryption(char *cret)
1626 {
1627         return CtdlIPCGenericCommand("STLS", NULL, 0, NULL, NULL, cret);
1628 }
1629
1630
1631 /*
1632  * Not implemented:
1633  * 
1634  * CHAT
1635  * ETLS
1636  * EXPI
1637  * GTLS
1638  * IGAB
1639  * IPGM
1640  * MSG3
1641  * MSG4
1642  * NDOP
1643  * NETP
1644  * NUOP
1645  * SMTP
1646  */
1647
1648
1649 /* ************************************************************************** */
1650 /*             Stuff below this line is not for public consumption            */
1651 /* ************************************************************************** */
1652
1653
1654 inline void netio_lock(void)
1655 {
1656 #ifdef THREADED_CLIENT
1657         pthread_mutex_lock(&rwlock);
1658 #endif
1659 }
1660
1661
1662 inline void netio_unlock(void)
1663 {
1664 #ifdef THREADED_CLIENT
1665         pthread_mutex_unlock(&rwlock);
1666 #endif
1667 }
1668
1669
1670 /* Read a listing from the server up to 000.  Append to dest if it exists */
1671 char *CtdlIPCReadListing(char *dest)
1672 {
1673         long length = 0;
1674         char *ret;
1675         char aaa[256];
1676
1677         ret = dest;
1678         if (ret) length = strlen(ret);
1679         while (serv_gets(aaa), strcmp(aaa, "000")) {
1680                 ret = (char *)realloc(ret, length + strlen(aaa) + 1);
1681                 if (ret)
1682                         strcpy(&ret[length], aaa);
1683         }
1684         return ret;
1685 }
1686
1687
1688 /* Send a listing to the server; generate the ending 000. */
1689 int CtdlIPCSendListing(const char *listing)
1690 {
1691         char *text;
1692
1693         text = (char *)malloc(strlen(listing) + 5);
1694         if (text) {
1695                 strcpy(text, listing);
1696                 if (text[strlen(text) - 1] == '\n')
1697                         text[strlen(text) - 1] = '\0';
1698                 strcat(text, "000");
1699                 serv_puts(text);
1700                 free(text);
1701                 text = NULL;
1702         } else {
1703                 /* Malloc failed but we are committed to send */
1704                 /* This may result in extra blanks at the bottom */
1705                 serv_puts(text);
1706                 serv_puts("000");
1707         }
1708         return 0;
1709 }
1710
1711
1712 /* Partial read of file from server */
1713 size_t CtdlIPCPartialRead(void **buf, size_t offset, size_t bytes, char *cret)
1714 {
1715         register size_t len = 0;
1716         char aaa[256];
1717
1718         if (!buf) return -1;
1719         if (!cret) return -1;
1720         if (bytes < 1) return -1;
1721         if (offset < 0) return -1;
1722
1723         netio_lock();
1724         sprintf(aaa, "READ %d|%d", offset, bytes);
1725         serv_puts(aaa);
1726         serv_gets(aaa);
1727         if (aaa[0] != '6')
1728                 strcpy(cret, &aaa[4]);
1729         else {
1730                 len = extract_long(&aaa[4], 0);
1731                 *buf = (void *)realloc(*buf, offset + len);
1732                 if (*buf) {
1733                         /* I know what I'm doing */
1734                         serv_read((char *)&buf[offset], len);
1735                 } else {
1736                         /* We have to read regardless */
1737                         serv_read(aaa, len);
1738                         len = -1;
1739                 }
1740         }
1741         netio_unlock();
1742         return len;
1743 }
1744
1745
1746 /* CLOS */
1747 int CtdlIPCEndDownload(char *cret)
1748 {
1749         register int ret;
1750
1751         if (!cret) return -2;
1752         if (!download_in_progress) return -2;
1753
1754         ret = CtdlIPCGenericCommand("CLOS", NULL, 0, NULL, NULL, cret);
1755         if (ret / 100 == 2)
1756                 download_in_progress = 0;
1757         return ret;
1758 }
1759
1760
1761 /* READ */
1762 int CtdlIPCReadDownload(void **buf, size_t bytes, char *cret)
1763 {
1764         register size_t len;
1765
1766         if (!cret) return -1;
1767         if (!buf) return -1;
1768         if (*buf) return -1;
1769         if (!download_in_progress) return -1;
1770
1771         len = 0;
1772         while (len < bytes) {
1773                 len = CtdlIPCPartialRead(buf, len, 4096, cret);
1774                 if (len == -1) {
1775                         free(*buf);
1776                         return 0;
1777                 }
1778         }
1779         return len;
1780 }
1781
1782
1783 /* UCLS */
1784 int CtdlIPCEndUpload(char *cret)
1785 {
1786         register int ret;
1787
1788         if (!cret) return -1;
1789         if (!upload_in_progress) return -1;
1790
1791         ret = CtdlIPCGenericCommand("UCLS", NULL, 0, NULL, NULL, cret);
1792         if (ret / 100 == 2)
1793                 upload_in_progress = 0;
1794         return ret;
1795 }
1796
1797
1798 /* WRIT */
1799 int CtdlIPCWriteUpload(void *buf, size_t bytes, char *cret)
1800 {
1801         register int ret = -1;
1802         register size_t offset;
1803         char aaa[256];
1804
1805         if (!cret) return -1;
1806         if (!buf) return -1;
1807         if (bytes < 1) return -1;
1808
1809         offset = 0;
1810         while (offset < bytes) {
1811                 sprintf(aaa, "WRIT %d", bytes - offset);
1812                 serv_puts(aaa);
1813                 serv_gets(aaa);
1814                 strcpy(cret, &aaa[4]);
1815                 ret = atoi(aaa);
1816                 if (aaa[0] == '7') {
1817                         register size_t to_write;
1818
1819                         to_write = extract_long(&aaa[4], 0);
1820                         serv_write(buf + offset, to_write);
1821                         offset += to_write;
1822                 } else {
1823                         break;
1824                 }
1825         }
1826         return ret;
1827 }
1828
1829
1830 /*
1831  * Generic command method.  This method should handle any server command
1832  * except for CHAT.  It takes the following arguments:
1833  *
1834  * command              Preformatted command to send to server
1835  * to_send              A text or binary file to send to server
1836  *                      (only sent if server requests it)
1837  * bytes_to_send        The number of bytes in to_send (required if
1838  *                      sending binary, optional if sending listing)
1839  * to_receive           Pointer to a NULL pointer, if the server
1840  *                      sends text or binary we will allocate memory
1841  *                      for the file and stuff it here
1842  * bytes_to_receive     If a file is received, we will store its
1843  *                      byte count here
1844  * proto_response       The protocol response.  Caller must provide
1845  *                      this buffer and ensure that it is at least
1846  *                      128 bytes in length.
1847  *
1848  * This function returns a number equal to the protocol response number,
1849  * -1 if an internal error occurred, -2 if caller provided bad values,
1850  * or 0 - the protocol response number if bad values were found during
1851  * the protocol exchange.
1852  * It stores the protocol response string (minus the number) in 
1853  * protocol_response as described above.  Some commands send additional
1854  * data in this string.
1855  */
1856 int CtdlIPCGenericCommand(const char *command, const char *to_send,
1857                 size_t bytes_to_send, char **to_receive, 
1858                 size_t *bytes_to_receive, char *proto_response)
1859 {
1860         char buf[SIZ];
1861         register int ret;
1862
1863         if (!command) return -2;
1864         if (!proto_response) return -2;
1865
1866         netio_lock();
1867         serv_puts((char *)command);
1868         while (1) {
1869                 serv_gets(proto_response);
1870                 if (proto_response[3] == '*')
1871                         express_msgs = 1;
1872                 ret = atoi(proto_response);
1873                 memmove(proto_response, &proto_response[4],
1874                                 strlen(proto_response) - 3);
1875                 switch (ret / 100) {
1876                 default:                        /* Unknown, punt */
1877                 case 2:                         /* OK */
1878                 case 3:                         /* MORE_DATA */
1879                 case 5:                         /* ERROR */
1880                         /* Don't need to do anything */
1881                         break;
1882                 case 1:                         /* LISTING_FOLLOWS */
1883                         if (to_receive && !*to_receive && bytes_to_receive) {
1884                                 *to_receive = CtdlIPCReadListing(NULL);
1885                         } else { /* Drain */
1886                                 while (serv_gets(buf), strcmp(buf, "000")) ;
1887                                 ret = -ret;
1888                         }
1889                         break;
1890                 case 4:                         /* SEND_LISTING */
1891                         if (to_send) {
1892                                 CtdlIPCSendListing(to_send);
1893                         } else {
1894                                 /* No listing given, fake it */
1895                                 serv_puts("000");
1896                                 ret = -ret;
1897                         }
1898                         break;
1899                 case 6:                         /* BINARY_FOLLOWS */
1900                         if (to_receive && !*to_receive && bytes_to_receive) {
1901                                 *bytes_to_receive =
1902                                         extract_long(proto_response, 0);
1903                                 *to_receive = (char *)malloc(*bytes_to_receive);
1904                                 if (!*to_receive) {
1905                                         ret = -1;
1906                                 } else {
1907                                         serv_read(*to_receive,
1908                                                         *bytes_to_receive);
1909                                 }
1910                         } else {
1911                                 /* Drain */
1912                                 size_t drain;
1913
1914                                 drain = extract_long(proto_response, 0);
1915                                 while (drain > SIZ) {
1916                                         serv_read(buf, SIZ);
1917                                         drain -= SIZ;
1918                                 }
1919                                 serv_read(buf, drain);
1920                                 ret = -ret;
1921                         }
1922                         break;
1923                 case 7:                         /* SEND_BINARY */
1924                         if (to_send && bytes_to_send) {
1925                                 serv_write((char *)to_send, bytes_to_send);
1926                         } else if (bytes_to_send) {
1927                                 /* Fake it, send nulls */
1928                                 size_t fake;
1929
1930                                 fake = bytes_to_send;
1931                                 memset(buf, '\0', SIZ);
1932                                 while (fake > SIZ) {
1933                                         serv_write(buf, SIZ);
1934                                         fake -= SIZ;
1935                                 }
1936                                 serv_write(buf, fake);
1937                                 ret = -ret;
1938                         } /* else who knows?  DANGER WILL ROBINSON */
1939                         break;
1940                 case 8:                         /* START_CHAT_MODE */
1941                         if (!strncasecmp(command, "CHAT", 4)) {
1942                                 /* Don't call chatmode with generic! */
1943                                 serv_puts("/quit");
1944                                 ret = -ret;
1945                         } else {
1946                                 /* In this mode we send then receive listing */
1947                                 if (to_send) {
1948                                         CtdlIPCSendListing(to_send);
1949                                 } else {
1950                                         /* No listing given, fake it */
1951                                         serv_puts("000");
1952                                         ret = -ret;
1953                                 }
1954                                 if (to_receive && !*to_receive
1955                                                 && bytes_to_receive) {
1956                                         *to_receive = CtdlIPCReadListing(NULL);
1957                                 } else { /* Drain */
1958                                         while (serv_gets(buf),
1959                                                         strcmp(buf, "000")) ;
1960                                         ret = -ret;
1961                                 }
1962                         }
1963                         break;
1964                 case 9:                         /* ASYNC_MSG */
1965                         /* CtdlIPCDoAsync(ret, proto_response); */
1966                         free(CtdlIPCReadListing(NULL)); /* STUB FIXME */
1967                         break;
1968                 }
1969                 if (ret / 100 != 9)
1970                         break;
1971         }
1972         netio_unlock();
1973         return ret;
1974 }