15 #include <sys/types.h>
20 #ifdef THREADED_CLIENT
24 #include "citadel_ipc.h"
25 #include "client_crypto.h"
28 #ifdef THREADED_CLIENT
29 pthread_mutex_t rwlock;
31 extern char express_msgs;
33 static volatile int download_in_progress = 0; /* download file open */
34 static volatile int upload_in_progress = 0; /* upload file open */
35 /* static volatile int serv_sock; /* Socket on which we talk to server */
39 * Does nothing. The server should always return 200.
57 * Does nothing interesting. The server should always return 200
58 * along with your string.
60 int CtdlIPCEcho(const char *arg, char *cret)
68 aaa = (char *)malloc(strlen(arg) + 6);
71 sprintf(aaa, "ECHO %s", arg);
72 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
79 * Asks the server to close the connecction.
80 * Should always return 200.
97 * Asks the server to logout. Should always return 200, even if no user
98 * was logged in. The user will not be logged in after this!
100 int CtdlIPCLogout(void)
115 * First stage of authentication - pass the username. Returns 300 if the
116 * username is able to log in, with the username correctly spelled in cret.
117 * Returns various 500 error codes if the user doesn't exist, etc.
119 int CtdlIPCTryLogin(const char *username, char *cret)
124 if (!username) return -2;
125 if (!cret) return -2;
127 aaa = (char *)malloc(strlen(username) + 6);
130 sprintf(aaa, "USER %s", username);
131 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
138 * Second stage of authentication - provide password. The server returns
139 * 200 and several arguments in cret relating to the user's account.
141 int CtdlIPCTryPassword(const char *passwd, char *cret)
146 if (!passwd) return -2;
147 if (!cret) return -2;
149 aaa = (char *)malloc(strlen(passwd) + 6);
152 sprintf(aaa, "PASS %s", passwd);
153 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
160 * Create a new user. This returns 200 plus the same arguments as TryPassword
161 * unless there was a problem creating the account.
163 int CtdlIPCCreateUser(const char *username, char *cret)
168 if (!username) return -2;
169 if (!cret) return -2;
171 aaa = (char *)malloc(strlen(username) + 6);
174 sprintf(aaa, "NEWU %s", username);
175 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
182 * Changes the user's password. Returns 200 if changed, errors otherwise.
184 int CtdlIPCChangePassword(const char *passwd, char *cret)
189 if (!passwd) return -2;
190 if (!cret) return -2;
192 aaa = (char *)malloc(strlen(passwd) + 6);
195 sprintf(aaa, "SETP %s", passwd);
196 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
203 /* Caller must free the march list */
204 /* which is 0 = LRMS, 1 = LKRN, 2 = LKRO, 3 = LKRA, 4 = LZRM */
205 /* floor is -1 for all, or floornum */
206 int CtdlIPCKnownRooms(int which, int floor, char *cret, struct march **listing)
209 struct march *march = NULL;
210 static char *proto[] = {"LRMS", "LKRN", "LKRO", "LKRA", "LZRM" };
215 if (!listing) return -2;
216 if (*listing) return -2; /* Free the listing first */
217 if (!cret) return -2;
218 if (which < 0 || which > 4) return -2;
219 if (floor < -1) return -2; /* Can't validate upper bound, sorry */
221 sprintf(aaa, "%s %d", proto[which], floor);
222 ret = CtdlIPCGenericCommand(aaa, NULL, 0, &bbb, &bbbsize, cret);
223 if (ret / 100 == 1) {
226 while (strlen(bbb)) {
229 extract_token(aaa, bbb, 0, '\n');
231 memmove(aaa, bbb + a + 1, strlen(bbb) - a - 1);
232 mptr = (struct march *) malloc(sizeof (struct march));
235 extract(mptr->march_name, aaa, 0);
236 mptr->march_floor = (char) extract_int(aaa, 2);
237 mptr->march_order = (char) extract_int(aaa, 3);
244 while (mptr2->next != NULL)
257 /* Caller must free the struct usersupp; caller may pass an existing one */
258 int CtdlIPCGetConfig(struct usersupp **uret, char *cret)
262 if (!cret) return -2;
263 if (!uret) return -2;
264 if (!*uret) *uret = (struct usersupp *)calloc(1, sizeof (struct usersupp));
265 if (!*uret) return -1;
267 ret = CtdlIPCGenericCommand("GETU", NULL, 0, NULL, NULL, cret);
268 if (ret / 100 == 2) {
269 uret[0]->USscreenwidth = extract_int(cret, 0);
270 uret[0]->USscreenheight = extract_int(cret, 1);
271 uret[0]->flags = extract_int(cret, 2);
278 int CtdlIPCSetConfig(struct usersupp *uret, char *cret)
282 if (!uret) return -2;
283 if (!cret) return -2;
285 sprintf(aaa, "SETU %d|%d|%d",
286 uret->USscreenwidth, uret->USscreenheight,
288 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
293 int CtdlIPCGotoRoom(const char *room, const char *passwd,
294 struct ctdlipcroom **rret, char *cret)
299 if (!cret) return -2;
300 if (!rret) return -2;
301 if (!*rret) *rret = (struct ctdlipcroom *)calloc(1, sizeof (struct ctdlipcroom));
302 if (!*rret) return -1;
305 aaa = (char *)malloc(strlen(room) + strlen(passwd) + 7);
310 sprintf(aaa, "GOTO %s|%s", room, passwd);
312 aaa = (char *)malloc(strlen(room) + 6);
317 sprintf(aaa, "GOTO %s", room);
319 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
320 if (ret / 100 == 2) {
321 extract(rret[0]->RRname, cret, 0);
322 rret[0]->RRunread = extract_long(cret, 1);
323 rret[0]->RRtotal = extract_long(cret, 2);
324 rret[0]->RRinfoupdated = extract_int(cret, 3);
325 rret[0]->RRflags = extract_int(cret, 4);
326 rret[0]->RRhighest = extract_long(cret, 5);
327 rret[0]->RRlastread = extract_long(cret, 6);
328 rret[0]->RRismailbox = extract_int(cret, 7);
329 rret[0]->RRaide = extract_int(cret, 8);
330 rret[0]->RRnewmail = extract_long(cret, 9);
331 rret[0]->RRfloor = extract_int(cret, 10);
340 /* which is 0 = all, 1 = old, 2 = new, 3 = last, 4 = first, 5 = gt, 6 = lt */
341 /* whicharg is number of messages, applies to last, first, gt, lt */
342 int CtdlIPCGetMessages(int which, int whicharg, const char *template,
343 long **mret, char *cret)
346 register long count = 0;
347 static char *proto[] =
348 { "ALL", "OLD", "NEW", "LAST", "FIRST", "GT", "LT" };
353 if (!cret) return -2;
354 if (!mret) return -2;
355 if (*mret) return -2;
356 if (which < 0 || which > 6) return -2;
359 sprintf(aaa, "MSGS %s||%d", proto[which],
362 sprintf(aaa, "MSGS %s|%d|%d", proto[which], whicharg,
364 if (template) count = strlen(template);
365 ret = CtdlIPCGenericCommand(aaa, template, count, &bbb, &bbbsize, cret);
367 while (strlen(bbb)) {
370 extract_token(aaa, bbb, 0, '\n');
372 memmove(aaa, bbb + a + 1, strlen(bbb) - a - 1);
373 *mret = (long *)realloc(mret, (count + 1) * sizeof (long));
375 *mret[count++] = atol(aaa);
383 int CtdlIPCGetSingleMessage(long msgnum, int headers, int as_mime,
384 struct ctdlipcmessage **mret, char *cret)
391 if (!cret) return -1;
392 if (!mret) return -1;
393 if (!*mret) *mret = (struct ctdlipcmessage *)calloc(1, sizeof (struct ctdlipcmessage));
394 if (!*mret) return -1;
395 if (!msgnum) return -1;
397 sprintf(aaa, "MSG%c %ld|%d", as_mime ? '2' : '0', msgnum, headers);
398 ret = CtdlIPCGenericCommand(aaa, NULL, 0, &bbb, &bbbsize, cret);
399 if (ret / 100 == 1) {
401 while (strlen(bbb) > 4 && bbb[4] == '=') {
404 extract_token(aaa, bbb, 0, '\n');
406 safestrncpy(bbb, &bbb[a + 1], strlen(bbb) - a);
408 if (!strncasecmp(aaa, "nhdr=yes", 8))
410 else if (!strncasecmp(aaa, "from=", 5))
411 strcpy(mret[0]->author, &aaa[5]);
412 else if (!strncasecmp(aaa, "type=", 5))
413 mret[0]->type = atoi(&aaa[5]);
414 else if (!strncasecmp(aaa, "msgn=", 5))
415 strcpy(mret[0]->msgid, &aaa[5]);
416 else if (!strncasecmp(aaa, "subj=", 5))
417 strcpy(mret[0]->subject, &aaa[5]);
418 else if (!strncasecmp(aaa, "rfca=", 5))
419 strcpy(mret[0]->email, &aaa[5]);
420 else if (!strncasecmp(aaa, "hnod=", 5))
421 strcpy(mret[0]->hnod, &aaa[5]);
422 else if (!strncasecmp(aaa, "room=", 5))
423 strcpy(mret[0]->room, &aaa[5]);
424 else if (!strncasecmp(aaa, "node=", 5))
425 strcpy(mret[0]->node, &aaa[5]);
426 else if (!strncasecmp(aaa, "rcpt=", 5))
427 strcpy(mret[0]->recipient, &aaa[5]);
428 else if (!strncasecmp(aaa, "time=", 5))
429 mret[0]->time = atol(&aaa[5]);
430 else if (!strncasecmp(aaa, "part=", 5)) {
431 struct parts *ptr, *chain;
433 ptr = (struct parts *)calloc(1, sizeof (struct parts));
435 extract(ptr->name, &aaa[5], 0);
436 extract(ptr->filename, &aaa[5], 1);
437 extract(ptr->number, &aaa[5], 2);
438 extract(ptr->disposition, &aaa[5], 3);
439 extract(ptr->mimetype, &aaa[5], 4);
440 ptr->length = extract_long(&aaa[5], 5);
441 if (!mret[0]->attachments)
442 mret[0]->attachments = ptr;
444 chain = mret[0]->attachments;
452 /* Eliminate "text\n" */
453 safestrncpy(bbb, &bbb[5], strlen(bbb) - 4);
456 /* Strip trailing whitespace */
457 bbb = (char *)realloc(bbb, strlen(bbb) + 1);
468 int CtdlIPCWhoKnowsRoom(char **listing, char *cret)
473 if (!cret) return -2;
474 if (!listing) return -2;
475 if (*listing) return -2;
477 ret = CtdlIPCGenericCommand("WHOK", NULL, 0, listing, &bytes, cret);
483 int CtdlIPCServerInfo(char **listing, char *cret)
488 if (!cret) return -2;
489 if (!listing) return -2;
490 if (*listing) return -2;
492 ret = CtdlIPCGenericCommand("INFO", NULL, 0, listing, &bytes, cret);
498 int CtdlIPCReadDirectory(char **listing, char *cret)
503 if (!cret) return -2;
504 if (!listing) return -2;
505 if (*listing) return -2;
507 ret = CtdlIPCGenericCommand("RDIR", NULL, 0, listing, &bytes, cret);
513 * Set last-read pointer in this room to msgnum, or 0 for HIGHEST.
515 int CtdlIPCSetLastRead(long msgnum, char *cret)
520 if (!cret) return -2;
523 sprintf(aaa, "SLRP %ld", msgnum);
525 sprintf(aaa, "SLRP HIGHEST");
526 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
532 int CtdlIPCInviteUserToRoom(const char *username, char *cret)
537 if (!cret) return -2;
538 if (!username) return -2;
540 aaa = (char *)malloc(strlen(username) + 6);
543 sprintf(aaa, "INVT %s", username);
544 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
551 int CtdlIPCKickoutUserFromRoom(const char *username, char *cret)
556 if (!cret) return -1;
557 if (!username) return -1;
559 aaa = (char *)malloc(strlen(username) + 6);
561 sprintf(aaa, "KICK %s", username);
562 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
569 int CtdlIPCGetRoomAttributes(struct quickroom **qret, char *cret)
573 if (!cret) return -2;
574 if (!qret) return -2;
575 if (!*qret) *qret = (struct quickroom *)calloc(1, sizeof (struct quickroom));
576 if (!*qret) return -1;
578 ret = CtdlIPCGenericCommand("GETR", NULL, 0, NULL, NULL, cret);
579 if (ret / 100 == 2) {
580 extract(qret[0]->QRname, cret, 0);
581 extract(qret[0]->QRpasswd, cret, 1);
582 extract(qret[0]->QRdirname, cret, 2);
583 qret[0]->QRflags = extract_int(cret, 3);
584 qret[0]->QRfloor = extract_int(cret, 4);
585 qret[0]->QRorder = extract_int(cret, 5);
592 /* set forget to kick all users out of room */
593 int CtdlIPCSetRoomAttributes(int forget, struct quickroom *qret, char *cret)
598 if (!cret) return -2;
599 if (!qret) return -2;
601 aaa = (char *)malloc(strlen(qret->QRname) + strlen(qret->QRpasswd) +
602 strlen(qret->QRdirname) + 52);
605 sprintf(aaa, "SETR %s|%s|%s|%d|%d|%d|%d",
606 qret->QRname, qret->QRpasswd, qret->QRdirname,
607 qret->QRflags, forget, qret->QRfloor, qret->QRorder);
608 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
615 int CtdlIPCGetRoomAide(char *cret)
617 if (!cret) return -1;
619 return CtdlIPCGenericCommand("GETA", NULL, 0, NULL, NULL, cret);
624 int CtdlIPCSetRoomAide(const char *username, char *cret)
629 if (!cret) return -2;
630 if (!username) return -2;
632 aaa = (char *)malloc(strlen(username) + 6);
635 sprintf(aaa, "SETA %s", username);
636 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
643 int CtdlIPCPostMessage(int flag, const struct ctdlipcmessage *mr, char *cret)
648 if (!cret) return -2;
651 aaa = (char *)malloc(strlen(mr->recipient) + strlen(mr->author) + 40);
654 sprintf(aaa, "ENT0 %d|%s|%d|%d|%s", flag, mr->recipient, mr->anonymous,
655 mr->type, mr->author);
656 ret = CtdlIPCGenericCommand(aaa, mr->text, strlen(mr->text), NULL,
664 int CtdlIPCRoomInfo(char **iret, char *cret)
668 if (!cret) return -2;
669 if (!iret) return -2;
670 if (*iret) return -2;
672 return CtdlIPCGenericCommand("RINF", NULL, 0, iret, &bytes, cret);
677 int CtdlIPCDeleteMessage(long msgnum, char *cret)
681 if (!cret) return -2;
682 if (!msgnum) return -2;
684 sprintf(aaa, "DELE %ld", msgnum);
685 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
690 int CtdlIPCMoveMessage(int copy, long msgnum, const char *destroom, char *cret)
695 if (!cret) return -2;
696 if (!destroom) return -2;
697 if (!msgnum) return -2;
699 aaa = (char *)malloc(strlen(destroom) + 28);
702 sprintf(aaa, "MOVE %ld|%s|%d", msgnum, destroom, copy);
703 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
710 int CtdlIPCDeleteRoom(int for_real, char *cret)
714 if (!cret) return -2;
716 sprintf(aaa, "KILL %d", for_real);
717 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
722 int CtdlIPCCreateRoom(int for_real, const char *roomname, int type,
723 const char *password, int floor, char *cret)
728 if (!cret) return -2;
729 if (!roomname) return -2;
732 aaa = (char *)malloc(strlen(roomname) + strlen(password) + 40);
734 sprintf(aaa, "CRE8 %d|%s|%d|%s|%d", for_real, roomname, type,
737 aaa = (char *)malloc(strlen(roomname) + 40);
739 sprintf(aaa, "CRE8 %d|%s|%d||%d", for_real, roomname, type,
742 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
749 int CtdlIPCForgetRoom(char *cret)
751 if (!cret) return -2;
753 return CtdlIPCGenericCommand("FORG", NULL, 0, NULL, NULL, cret);
758 int CtdlIPCSystemMessage(const char *message, char **mret, char *cret)
764 if (!cret) return -2;
765 if (!mret) return -2;
766 if (*mret) return -2;
767 if (!message) return -2;
769 aaa = (char *)malloc(strlen(message) + 6);
772 sprintf(aaa, "MESG %s", message);
773 ret = CtdlIPCGenericCommand(aaa, NULL, 0, mret, &bytes, cret);
780 int CtdlIPCNextUnvalidatedUser(char *cret)
782 if (!cret) return -2;
784 return CtdlIPCGenericCommand("GNUR", NULL, 0, NULL, NULL, cret);
789 int CtdlIPCGetUserRegistration(const char *username, char **rret, char *cret)
795 if (!cret) return -2;
796 if (!rret) return -2;
797 if (*rret) return -2;
800 aaa = (char *)malloc(strlen(username) + 6);
802 aaa = (char *)malloc(12);
806 sprintf(aaa, "GREG %s", username);
808 sprintf(aaa, "GREG _SELF_");
809 ret = CtdlIPCGenericCommand(aaa, NULL, 0, rret, &bytes, cret);
816 int CtdlIPCValidateUser(const char *username, int axlevel, char *cret)
821 if (!cret) return -2;
822 if (!username) return -2;
823 if (axlevel < 0 || axlevel > 7) return -2;
825 aaa = (char *)malloc(strlen(username) + 17);
828 sprintf(aaa, "VALI %s|%d", username, axlevel);
829 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
836 int CtdlIPCSetRoomInfo(int for_real, const char *info, char *cret)
840 if (!cret) return -1;
841 if (!info) return -1;
843 sprintf(aaa, "EINF %d", for_real);
844 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
849 int CtdlIPCUserListing(char **listing, char *cret)
853 if (!cret) return -1;
854 if (!listing) return -1;
855 if (*listing) return -1;
857 return CtdlIPCGenericCommand("LIST", NULL, 0, listing, &bytes, cret);
862 int CtdlIPCSetRegistration(const char *info, char *cret)
864 if (!cret) return -1;
865 if (!info) return -1;
867 return CtdlIPCGenericCommand("REGI", info, strlen(info),
873 int CtdlIPCMiscCheck(struct ctdlipcmisc *chek, char *cret)
877 if (!cret) return -1;
878 if (!chek) return -1;
880 ret = CtdlIPCGenericCommand("CHEK", NULL, 0, NULL, NULL, cret);
881 if (ret / 100 == 2) {
882 chek->newmail = extract_long(cret, 0);
883 chek->needregis = extract_int(cret, 1);
884 chek->needvalid = extract_int(cret, 2);
891 int CtdlIPCDeleteFile(const char *filename, char *cret)
896 if (!cret) return -2;
897 if (!filename) return -2;
899 aaa = (char *)malloc(strlen(filename) + 6);
902 sprintf(aaa, "DELF %s", filename);
903 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
910 int CtdlIPCMoveFile(const char *filename, const char *destroom, char *cret)
915 if (!cret) return -2;
916 if (!filename) return -2;
917 if (!destroom) return -2;
919 aaa = (char *)malloc(strlen(filename) + strlen(destroom) + 7);
922 sprintf(aaa, "MOVF %s|%s", filename, destroom);
923 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
930 int CtdlIPCNetSendFile(const char *filename, const char *destnode, char *cret)
935 if (!cret) return -2;
936 if (!filename) return -2;
937 if (!destnode) return -2;
939 aaa = (char *)malloc(strlen(filename) + strlen(destnode) + 7);
942 sprintf(aaa, "NETF %s|%s", filename, destnode);
943 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
950 int CtdlIPCOnlineUsers(char **listing, time_t *stamp, char *cret)
955 if (!cret) return -1;
956 if (!listing) return -1;
957 if (*listing) return -1;
959 *stamp = CtdlIPCServerTime(cret);
962 ret = CtdlIPCGenericCommand("RWHO", NULL, 0, listing, &bytes, cret);
968 int CtdlIPCFileDownload(const char *filename, void **buf, char *cret)
976 if (!cret) return -2;
977 if (!filename) return -2;
980 if (download_in_progress) return -2;
982 aaa = (char *)malloc(strlen(filename) + 6);
985 sprintf(aaa, "OPEN %s", filename);
986 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
988 /* FIXME: Possible race condition */
989 if (ret / 100 == 2) {
990 download_in_progress = 1;
991 bytes = extract_long(cret, 0);
992 last_mod = extract_int(cret, 1);
993 extract(mimetype, cret, 2);
994 ret = CtdlIPCReadDownload(buf, bytes, cret);
995 ret = CtdlIPCEndDownload(cret);
997 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1005 int CtdlIPCAttachmentDownload(long msgnum, const char *part, void **buf,
1015 if (!cret) return -2;
1016 if (!buf) return -2;
1017 if (*buf) return -2;
1018 if (!part) return -2;
1019 if (!msgnum) return -2;
1020 if (download_in_progress) return -2;
1022 aaa = (char *)malloc(strlen(part) + 17);
1023 if (!aaa) return -1;
1025 sprintf(aaa, "OPNA %ld|%s", msgnum, part);
1026 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1028 /* FIXME: Possible race condition */
1029 if (ret / 100 == 2) {
1030 download_in_progress = 1;
1031 bytes = extract_long(cret, 0);
1032 last_mod = extract_int(cret, 1);
1033 extract(mimetype, cret, 2);
1034 ret = CtdlIPCReadDownload(buf, bytes, cret);
1035 ret = CtdlIPCEndDownload(cret);
1037 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1038 filename, mimetype);
1045 int CtdlIPCImageDownload(const char *filename, void **buf, char *cret)
1053 if (!cret) return -1;
1054 if (!buf) return -1;
1055 if (*buf) return -1;
1056 if (!filename) return -1;
1057 if (download_in_progress) return -1;
1059 aaa = (char *)malloc(strlen(filename) + 6);
1060 if (!aaa) return -1;
1062 sprintf(aaa, "OIMG %s", filename);
1063 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1065 /* FIXME: Possible race condition */
1066 if (ret / 100 == 2) {
1067 download_in_progress = 1;
1068 bytes = extract_long(cret, 0);
1069 last_mod = extract_int(cret, 1);
1070 extract(mimetype, cret, 2);
1071 ret = CtdlIPCReadDownload(buf, bytes, cret);
1072 ret = CtdlIPCEndDownload(cret);
1074 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1075 filename, mimetype);
1082 int CtdlIPCFileUpload(const char *filename, const char *comment, void *buf,
1083 size_t bytes, char *cret)
1088 if (!cret) return -1;
1089 if (!filename) return -1;
1090 if (!comment) return -1;
1091 if (upload_in_progress) return -1;
1093 aaa = (char *)malloc(strlen(filename) + strlen(comment) + 7);
1094 if (!aaa) return -1;
1096 sprintf(aaa, "UOPN %s|%s", filename, comment);
1097 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1099 /* FIXME: Possible race condition */
1101 upload_in_progress = 1;
1102 ret = CtdlIPCWriteUpload(buf, bytes, cret);
1103 ret = CtdlIPCEndUpload(cret);
1109 int CtdlIPCImageUpload(int for_real, const char *filename, size_t bytes,
1115 if (!cret) return -1;
1116 if (!filename) return -1;
1117 if (upload_in_progress) return -1;
1119 aaa = (char *)malloc(strlen(filename) + 17);
1120 if (!aaa) return -1;
1122 sprintf(aaa, "UIMG %d|%s", for_real, filename);
1123 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1125 /* FIXME: Possible race condition */
1127 upload_in_progress = 1;
1133 int CtdlIPCQueryUsername(const char *username, char *cret)
1138 if (!cret) return -2;
1139 if (!username) return -2;
1141 aaa = (char *)malloc(strlen(username) + 6);
1142 if (!aaa) return -1;
1144 sprintf(aaa, "QUSR %s", username);
1145 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1152 int CtdlIPCFloorListing(char **listing, char *cret)
1156 if (!cret) return -2;
1157 if (!listing) return -2;
1158 if (*listing) return -2;
1160 return CtdlIPCGenericCommand("LFLR", NULL, 0, listing, &bytes, cret);
1165 int CtdlIPCCreateFloor(int for_real, const char *name, char *cret)
1170 if (!cret) return -2;
1171 if (!name) return -2;
1173 aaa = (char *)malloc(strlen(name) + 17);
1174 if (!aaa) return -1;
1176 sprintf(aaa, "CFLR %s|%d", name, for_real);
1177 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1184 int CtdlIPCDeleteFloor(int for_real, int floornum, char *cret)
1188 if (!cret) return -1;
1189 if (floornum < 0) return -1;
1191 sprintf(aaa, "KFLR %d|%d", floornum, for_real);
1192 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1197 int CtdlIPCEditFloor(int floornum, const char *floorname, char *cret)
1202 if (!cret) return -2;
1203 if (!floorname) return -2;
1204 if (floornum < 0) return -2;
1206 aaa = (char *)malloc(strlen(floorname) + 17);
1207 if (!aaa) return -1;
1209 sprintf(aaa, "EFLR %d|%s", floornum, floorname);
1210 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1217 int CtdlIPCIdentifySoftware(int developerid, int clientid, int revision,
1218 const char *software_name, const char *hostname, char *cret)
1223 if (developerid < 0) return -2;
1224 if (clientid < 0) return -2;
1225 if (revision < 0) return -2;
1226 if (!software_name) return -2;
1227 if (!hostname) return -2;
1229 aaa = (char *)malloc(strlen(software_name) + strlen(hostname) + 29);
1230 if (!aaa) return -1;
1232 sprintf(aaa, "IDEN %d|%d|%d|%s|%s", developerid, clientid,
1233 revision, software_name, hostname);
1234 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1241 int CtdlIPCSendInstantMessage(const char *username, const char *text,
1247 if (!cret) return -2;
1248 if (!username) return -2;
1250 aaa = (char *)malloc(strlen(username) + 8);
1251 if (!aaa) return -1;
1254 sprintf(aaa, "SEXP %s|-", username);
1255 ret = CtdlIPCGenericCommand(aaa, text, strlen(text),
1258 sprintf(aaa, "SEXP %s||", username);
1259 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1267 int CtdlIPCGetInstantMessage(char **listing, char *cret)
1271 if (!cret) return -2;
1272 if (!listing) return -2;
1273 if (*listing) return -2;
1275 return CtdlIPCGenericCommand("GEXP", NULL, 0, listing, &bytes, cret);
1280 /* mode is 0 = enable, 1 = disable, 2 = status */
1281 int CtdlIPCEnableInstantMessageReceipt(int mode, char *cret)
1285 if (!cret) return -2;
1287 sprintf(aaa, "DEXP %d", mode);
1288 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1293 int CtdlIPCSetBio(char *bio, char *cret)
1295 if (!cret) return -2;
1296 if (!bio) return -2;
1298 return CtdlIPCGenericCommand("EBIO", bio, strlen(bio),
1304 int CtdlIPCGetBio(const char *username, char **listing, char *cret)
1310 if (!cret) return -2;
1311 if (!username) return -2;
1312 if (!listing) return -2;
1313 if (*listing) return -2;
1315 aaa = (char *)malloc(strlen(username) + 6);
1316 if (!aaa) return -1;
1318 sprintf(aaa, "RBIO %s", username);
1319 ret = CtdlIPCGenericCommand(aaa, NULL, 0, listing, &bytes, cret);
1326 int CtdlIPCListUsersWithBios(char **listing, char *cret)
1330 if (!cret) return -2;
1331 if (!listing) return -2;
1332 if (*listing) return -2;
1334 return CtdlIPCGenericCommand("LBIO", NULL, 0, listing, &bytes, cret);
1339 int CtdlIPCStealthMode(int mode, char *cret)
1343 if (!cret) return -1;
1345 sprintf(aaa, "STEL %d", mode ? 1 : 0);
1346 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1351 int CtdlIPCTerminateSession(int sid, char *cret)
1355 if (!cret) return -1;
1357 sprintf(aaa, "TERM %d", sid);
1358 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1363 int CtdlIPCTerminateServerNow(char *cret)
1365 if (!cret) return -1;
1367 return CtdlIPCGenericCommand("DOWN", NULL, 0, NULL, NULL, cret);
1372 int CtdlIPCTerminateServerScheduled(int mode, char *cret)
1376 if (!cret) return -1;
1378 sprintf(aaa, "SCDN %d", mode ? 1 : 0);
1379 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1384 int CtdlIPCEnterSystemMessage(const char *filename, const char *text,
1390 if (!cret) return -2;
1391 if (!text) return -2;
1392 if (!filename) return -2;
1394 aaa = (char *)malloc(strlen(filename) + 6);
1395 if (!aaa) return -1;
1397 sprintf(aaa, "EMSG %s", filename);
1398 ret = CtdlIPCGenericCommand(aaa, text, strlen(text), NULL, NULL, cret);
1405 int CtdlIPCChangeHostname(const char *hostname, char *cret)
1410 if (!cret) return -2;
1411 if (!hostname) return -2;
1413 aaa = (char *)malloc(strlen(hostname) + 6);
1414 if (!aaa) return -1;
1416 sprintf(aaa, "HCHG %s", hostname);
1417 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1424 int CtdlIPCChangeRoomname(const char *roomname, char *cret)
1429 if (!cret) return -2;
1430 if (!roomname) return -2;
1432 aaa = (char *)malloc(strlen(roomname) + 6);
1433 if (!aaa) return -1;
1435 sprintf(aaa, "RCHG %s", roomname);
1436 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1443 int CtdlIPCChangeUsername(const char *username, char *cret)
1448 if (!cret) return -2;
1449 if (!username) return -2;
1451 aaa = (char *)malloc(strlen(username) + 6);
1452 if (!aaa) return -1;
1454 sprintf(aaa, "UCHG %s", username);
1455 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1462 /* This function returns the actual server time reported, or 0 if error */
1463 time_t CtdlIPCServerTime(char *cret)
1465 register time_t tret;
1468 ret = CtdlIPCGenericCommand("TIME", NULL, 0, NULL, NULL, cret);
1469 if (ret / 100 == 2) {
1470 tret = extract_long(cret, 0);
1479 int CtdlIPCAideGetUserParameters(struct usersupp **uret, char *cret)
1484 if (!cret) return -2;
1485 if (!uret) return -2;
1486 if (!*uret) return -2;
1488 aaa = (char *)malloc(strlen(uret[0]->fullname) + 6);
1489 if (!aaa) return -1;
1491 sprintf(aaa, "AGUP %s", uret[0]->fullname);
1492 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1493 if (ret / 100 == 2) {
1494 extract(uret[0]->fullname, cret, 0);
1495 extract(uret[0]->password, cret, 1);
1496 uret[0]->flags = extract_int(cret, 2);
1497 uret[0]->timescalled = extract_long(cret, 3);
1498 uret[0]->posted = extract_long(cret, 4);
1499 uret[0]->axlevel = extract_int(cret, 5);
1500 uret[0]->usernum = extract_long(cret, 6);
1501 uret[0]->lastcall = extract_long(cret, 7);
1502 uret[0]->USuserpurge = extract_int(cret, 8);
1510 int CtdlIPCAideSetUserParameters(const struct usersupp *uret, char *cret)
1515 if (!cret) return -2;
1516 if (!uret) return -2;
1518 aaa = (char *)malloc(strlen(uret->fullname) + strlen(uret->password) + 84);
1519 if (!aaa) return -1;
1521 sprintf(aaa, "ASUP %s|%s|%d|%ld|%ld|%d|%ld|%ld|%d",
1522 uret->fullname, uret->password, uret->flags,
1523 uret->timescalled, uret->posted, uret->axlevel,
1524 uret->usernum, uret->lastcall, uret->USuserpurge);
1525 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1532 /* which is 0 = room, 1 = floor, 2 = site */
1533 int CtdlIPCGetMessageExpirationPolicy(int which, char *cret)
1535 static char *proto[] = {"room", "floor", "site"};
1538 if (!cret) return -2;
1539 if (which < 0 || which > 2) return -2;
1541 sprintf(aaa, "GPEX %s", proto[which]);
1542 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1547 /* which is 0 = room, 1 = floor, 2 = site */
1548 /* policy is 0 = inherit, 1 = no purge, 2 = by count, 3 = by age (days) */
1549 int CtdlIPCSetMessageExpirationPolicy(int which, int policy, int value,
1554 if (!cret) return -2;
1555 if (which < 0 || which > 2) return -2;
1556 if (policy < 0 || policy > 3) return -2;
1557 if (policy >= 2 && value < 1) return -2;
1559 sprintf(aaa, "SPEX %d|%d|%d", which, policy, value);
1560 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1565 int CtdlGetSystemConfig(char **listing, char *cret)
1569 if (!cret) return -2;
1570 if (!listing) return -2;
1571 if (*listing) return -2;
1573 return CtdlIPCGenericCommand("CONF GET", NULL, 0,
1574 listing, &bytes, cret);
1579 int CtdlSetSystemConfig(const char *listing, char *cret)
1581 if (!cret) return -2;
1582 if (!listing) return -2;
1584 return CtdlIPCGenericCommand("CONF SET", listing, strlen(listing),
1590 int CtdlIPCModerateMessage(long msgnum, int level, char *cret)
1594 if (!cret) return -2;
1595 if (!msgnum) return -2;
1597 sprintf(aaa, "MMOD %ld|%d", msgnum, level);
1598 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1603 int CtdlIPCRequestClientLogout(int session, char *cret)
1607 if (!cret) return -2;
1608 if (session < 0) return -2;
1610 sprintf(aaa, "REQT %d", session);
1611 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1616 int CtdlIPCSetMessageSeen(long msgnum, int seen, char *cret)
1620 if (!cret) return -2;
1621 if (msgnum < 0) return -2;
1623 sprintf(aaa, "SEEN %ld|%d", msgnum, seen ? 1 : 0);
1624 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1629 int CtdlIPCStartEncryption(char *cret)
1631 return CtdlIPCGenericCommand("STLS", NULL, 0, NULL, NULL, cret);
1653 /* ************************************************************************** */
1654 /* Stuff below this line is not for public consumption */
1655 /* ************************************************************************** */
1658 inline void netio_lock(void)
1660 #ifdef THREADED_CLIENT
1661 pthread_mutex_lock(&rwlock);
1666 inline void netio_unlock(void)
1668 #ifdef THREADED_CLIENT
1669 pthread_mutex_unlock(&rwlock);
1674 /* Read a listing from the server up to 000. Append to dest if it exists */
1675 char *CtdlIPCReadListing(char *dest)
1682 if (ret) length = strlen(ret);
1683 while (serv_gets(aaa), strcmp(aaa, "000")) {
1684 ret = (char *)realloc(ret, length + strlen(aaa) + 2);
1686 strcpy(&ret[length], aaa);
1687 length += strlen(aaa);
1688 strcpy(&ret[length++], "\n");
1695 /* Send a listing to the server; generate the ending 000. */
1696 int CtdlIPCSendListing(const char *listing)
1700 text = (char *)malloc(strlen(listing) + 5);
1702 strcpy(text, listing);
1703 if (text[strlen(text) - 1] == '\n')
1704 text[strlen(text) - 1] = '\0';
1705 strcat(text, "000");
1710 /* Malloc failed but we are committed to send */
1711 /* This may result in extra blanks at the bottom */
1719 /* Partial read of file from server */
1720 size_t CtdlIPCPartialRead(void **buf, size_t offset, size_t bytes, char *cret)
1722 register size_t len = 0;
1725 if (!buf) return -1;
1726 if (!cret) return -1;
1727 if (bytes < 1) return -1;
1728 if (offset < 0) return -1;
1731 sprintf(aaa, "READ %d|%d", offset, bytes);
1735 strcpy(cret, &aaa[4]);
1737 len = extract_long(&aaa[4], 0);
1738 *buf = (void *)realloc(*buf, offset + len);
1740 /* I know what I'm doing */
1741 serv_read((char *)&buf[offset], len);
1743 /* We have to read regardless */
1744 serv_read(aaa, len);
1754 int CtdlIPCEndDownload(char *cret)
1758 if (!cret) return -2;
1759 if (!download_in_progress) return -2;
1761 ret = CtdlIPCGenericCommand("CLOS", NULL, 0, NULL, NULL, cret);
1763 download_in_progress = 0;
1769 int CtdlIPCReadDownload(void **buf, size_t bytes, char *cret)
1771 register size_t len;
1773 if (!cret) return -1;
1774 if (!buf) return -1;
1775 if (*buf) return -1;
1776 if (!download_in_progress) return -1;
1779 while (len < bytes) {
1780 len = CtdlIPCPartialRead(buf, len, 4096, cret);
1791 int CtdlIPCEndUpload(char *cret)
1795 if (!cret) return -1;
1796 if (!upload_in_progress) return -1;
1798 ret = CtdlIPCGenericCommand("UCLS", NULL, 0, NULL, NULL, cret);
1800 upload_in_progress = 0;
1806 int CtdlIPCWriteUpload(void *buf, size_t bytes, char *cret)
1808 register int ret = -1;
1809 register size_t offset;
1812 if (!cret) return -1;
1813 if (!buf) return -1;
1814 if (bytes < 1) return -1;
1817 while (offset < bytes) {
1818 sprintf(aaa, "WRIT %d", bytes - offset);
1821 strcpy(cret, &aaa[4]);
1823 if (aaa[0] == '7') {
1824 register size_t to_write;
1826 to_write = extract_long(&aaa[4], 0);
1827 serv_write(buf + offset, to_write);
1838 * Generic command method. This method should handle any server command
1839 * except for CHAT. It takes the following arguments:
1841 * command Preformatted command to send to server
1842 * to_send A text or binary file to send to server
1843 * (only sent if server requests it)
1844 * bytes_to_send The number of bytes in to_send (required if
1845 * sending binary, optional if sending listing)
1846 * to_receive Pointer to a NULL pointer, if the server
1847 * sends text or binary we will allocate memory
1848 * for the file and stuff it here
1849 * bytes_to_receive If a file is received, we will store its
1851 * proto_response The protocol response. Caller must provide
1852 * this buffer and ensure that it is at least
1853 * 128 bytes in length.
1855 * This function returns a number equal to the protocol response number,
1856 * -1 if an internal error occurred, -2 if caller provided bad values,
1857 * or 0 - the protocol response number if bad values were found during
1858 * the protocol exchange.
1859 * It stores the protocol response string (minus the number) in
1860 * protocol_response as described above. Some commands send additional
1861 * data in this string.
1863 int CtdlIPCGenericCommand(const char *command, const char *to_send,
1864 size_t bytes_to_send, char **to_receive,
1865 size_t *bytes_to_receive, char *proto_response)
1870 if (!command) return -2;
1871 if (!proto_response) return -2;
1874 serv_puts((char *)command);
1876 serv_gets(proto_response);
1877 if (proto_response[3] == '*')
1879 ret = atoi(proto_response);
1880 memmove(proto_response, &proto_response[4],
1881 strlen(proto_response) - 3);
1882 switch (ret / 100) {
1883 default: /* Unknown, punt */
1885 case 3: /* MORE_DATA */
1887 /* Don't need to do anything */
1889 case 1: /* LISTING_FOLLOWS */
1890 if (to_receive && !*to_receive && bytes_to_receive) {
1891 *to_receive = CtdlIPCReadListing(NULL);
1892 } else { /* Drain */
1893 while (serv_gets(buf), strcmp(buf, "000")) ;
1897 case 4: /* SEND_LISTING */
1899 CtdlIPCSendListing(to_send);
1901 /* No listing given, fake it */
1906 case 6: /* BINARY_FOLLOWS */
1907 if (to_receive && !*to_receive && bytes_to_receive) {
1909 extract_long(proto_response, 0);
1910 *to_receive = (char *)malloc(*bytes_to_receive);
1914 serv_read(*to_receive,
1921 drain = extract_long(proto_response, 0);
1922 while (drain > SIZ) {
1923 serv_read(buf, SIZ);
1926 serv_read(buf, drain);
1930 case 7: /* SEND_BINARY */
1931 if (to_send && bytes_to_send) {
1932 serv_write((char *)to_send, bytes_to_send);
1933 } else if (bytes_to_send) {
1934 /* Fake it, send nulls */
1937 fake = bytes_to_send;
1938 memset(buf, '\0', SIZ);
1939 while (fake > SIZ) {
1940 serv_write(buf, SIZ);
1943 serv_write(buf, fake);
1945 } /* else who knows? DANGER WILL ROBINSON */
1947 case 8: /* START_CHAT_MODE */
1948 if (!strncasecmp(command, "CHAT", 4)) {
1949 /* Don't call chatmode with generic! */
1953 /* In this mode we send then receive listing */
1955 CtdlIPCSendListing(to_send);
1957 /* No listing given, fake it */
1961 if (to_receive && !*to_receive
1962 && bytes_to_receive) {
1963 *to_receive = CtdlIPCReadListing(NULL);
1964 } else { /* Drain */
1965 while (serv_gets(buf),
1966 strcmp(buf, "000")) ;
1971 case 9: /* ASYNC_MSG */
1972 /* CtdlIPCDoAsync(ret, proto_response); */
1973 free(CtdlIPCReadListing(NULL)); /* STUB FIXME */