16 #include <sys/types.h>
21 #ifdef THREADED_CLIENT
25 #include "citadel_ipc.h"
26 #include "client_crypto.h"
29 #ifdef THREADED_CLIENT
30 pthread_mutex_t rwlock;
32 extern char express_msgs;
34 static volatile int download_in_progress = 0; /* download file open */
35 static volatile int upload_in_progress = 0; /* upload file open */
36 /* static volatile int serv_sock; /* Socket on which we talk to server */
40 * Does nothing. The server should always return 200.
58 * Does nothing interesting. The server should always return 200
59 * along with your string.
61 int CtdlIPCEcho(const char *arg, char *cret)
69 aaa = (char *)malloc(strlen(arg) + 6);
72 sprintf(aaa, "ECHO %s", arg);
73 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
80 * Asks the server to close the connecction.
81 * Should always return 200.
98 * Asks the server to logout. Should always return 200, even if no user
99 * was logged in. The user will not be logged in after this!
101 int CtdlIPCLogout(void)
116 * First stage of authentication - pass the username. Returns 300 if the
117 * username is able to log in, with the username correctly spelled in cret.
118 * Returns various 500 error codes if the user doesn't exist, etc.
120 int CtdlIPCTryLogin(const char *username, char *cret)
125 if (!username) return -2;
126 if (!cret) return -2;
128 aaa = (char *)malloc(strlen(username) + 6);
131 sprintf(aaa, "USER %s", username);
132 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
139 * Second stage of authentication - provide password. The server returns
140 * 200 and several arguments in cret relating to the user's account.
142 int CtdlIPCTryPassword(const char *passwd, char *cret)
147 if (!passwd) return -2;
148 if (!cret) return -2;
150 aaa = (char *)malloc(strlen(passwd) + 6);
153 sprintf(aaa, "PASS %s", passwd);
154 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
161 * Create a new user. This returns 200 plus the same arguments as TryPassword
162 * unless there was a problem creating the account.
164 int CtdlIPCCreateUser(const char *username, char *cret)
169 if (!username) return -2;
170 if (!cret) return -2;
172 aaa = (char *)malloc(strlen(username) + 6);
175 sprintf(aaa, "NEWU %s", username);
176 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
183 * Changes the user's password. Returns 200 if changed, errors otherwise.
185 int CtdlIPCChangePassword(const char *passwd, char *cret)
190 if (!passwd) return -2;
191 if (!cret) return -2;
193 aaa = (char *)malloc(strlen(passwd) + 6);
196 sprintf(aaa, "SETP %s", passwd);
197 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
204 /* Caller must free the march list */
205 /* which is 0 = LRMS, 1 = LKRN, 2 = LKRO, 3 = LKRA, 4 = LZRM */
206 /* floor is -1 for all, or floornum */
207 int CtdlIPCKnownRooms(int which, int floor, char *cret, struct march **listing)
210 struct march *march = NULL;
211 static char *proto[] = {"LRMS", "LKRN", "LKRO", "LKRA", "LZRM" };
216 if (!listing) return -2;
217 if (*listing) return -2; /* Free the listing first */
218 if (!cret) return -2;
219 if (which < 0 || which > 4) return -2;
220 if (floor < -1) return -2; /* Can't validate upper bound, sorry */
222 sprintf(aaa, "%s %d", proto[which], floor);
223 ret = CtdlIPCGenericCommand(aaa, NULL, 0, &bbb, &bbbsize, cret);
224 if (ret / 100 == 1) {
227 while (strlen(bbb)) {
230 extract_token(aaa, bbb, 0, '\n');
232 memmove(aaa, bbb + a + 1, strlen(bbb) - a - 1);
233 mptr = (struct march *) malloc(sizeof (struct march));
236 extract(mptr->march_name, aaa, 0);
237 mptr->march_floor = (char) extract_int(aaa, 2);
238 mptr->march_order = (char) extract_int(aaa, 3);
245 while (mptr2->next != NULL)
258 /* Caller must free the struct usersupp; caller may pass an existing one */
259 int CtdlIPCGetConfig(struct usersupp **uret, char *cret)
263 if (!cret) return -2;
264 if (!uret) return -2;
265 if (!*uret) *uret = (struct usersupp *)calloc(1, sizeof (struct usersupp));
266 if (!*uret) return -1;
268 ret = CtdlIPCGenericCommand("GETU", NULL, 0, NULL, NULL, cret);
269 if (ret / 100 == 2) {
270 uret[0]->USscreenwidth = extract_int(cret, 0);
271 uret[0]->USscreenheight = extract_int(cret, 1);
272 uret[0]->flags = extract_int(cret, 2);
279 int CtdlIPCSetConfig(struct usersupp *uret, char *cret)
283 if (!uret) return -2;
284 if (!cret) return -2;
286 sprintf(aaa, "SETU %d|%d|%d",
287 uret->USscreenwidth, uret->USscreenheight,
289 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
294 int CtdlIPCGotoRoom(const char *room, const char *passwd,
295 struct ctdlipcroom **rret, char *cret)
300 if (!cret) return -2;
301 if (!rret) return -2;
302 if (!*rret) *rret = (struct ctdlipcroom *)calloc(1, sizeof (struct ctdlipcroom));
303 if (!*rret) return -1;
306 aaa = (char *)malloc(strlen(room) + strlen(passwd) + 7);
311 sprintf(aaa, "GOTO %s|%s", room, passwd);
313 aaa = (char *)malloc(strlen(room) + 6);
318 sprintf(aaa, "GOTO %s", room);
320 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
321 if (ret / 100 == 2) {
322 extract(rret[0]->RRname, cret, 0);
323 rret[0]->RRunread = extract_long(cret, 1);
324 rret[0]->RRtotal = extract_long(cret, 2);
325 rret[0]->RRinfoupdated = extract_int(cret, 3);
326 rret[0]->RRflags = extract_int(cret, 4);
327 rret[0]->RRhighest = extract_long(cret, 5);
328 rret[0]->RRlastread = extract_long(cret, 6);
329 rret[0]->RRismailbox = extract_int(cret, 7);
330 rret[0]->RRaide = extract_int(cret, 8);
331 rret[0]->RRnewmail = extract_long(cret, 9);
332 rret[0]->RRfloor = extract_int(cret, 10);
341 /* which is 0 = all, 1 = old, 2 = new, 3 = last, 4 = first, 5 = gt, 6 = lt */
342 /* whicharg is number of messages, applies to last, first, gt, lt */
343 int CtdlIPCGetMessages(int which, int whicharg, const char *template,
344 long **mret, char *cret)
347 register long count = 0;
348 static char *proto[] =
349 { "ALL", "OLD", "NEW", "LAST", "FIRST", "GT", "LT" };
354 if (!cret) return -2;
355 if (!mret) return -2;
356 if (*mret) return -2;
357 if (which < 0 || which > 6) return -2;
360 sprintf(aaa, "MSGS %s||%d", proto[which],
363 sprintf(aaa, "MSGS %s|%d|%d", proto[which], whicharg,
365 if (template) count = strlen(template);
366 ret = CtdlIPCGenericCommand(aaa, template, count, &bbb, &bbbsize, cret);
368 while (strlen(bbb)) {
371 extract_token(aaa, bbb, 0, '\n');
373 memmove(aaa, bbb + a + 1, strlen(bbb) - a - 1);
374 *mret = (long *)realloc(mret, (count + 1) * sizeof (long));
376 *mret[count++] = atol(aaa);
384 int CtdlIPCGetSingleMessage(long msgnum, int headers, int as_mime,
385 struct ctdlipcmessage **mret, char *cret)
392 if (!cret) return -1;
393 if (!mret) return -1;
394 if (!*mret) *mret = (struct ctdlipcmessage *)calloc(1, sizeof (struct ctdlipcmessage));
395 if (!*mret) return -1;
396 if (!msgnum) return -1;
398 sprintf(aaa, "MSG%c %ld|%d", as_mime ? '2' : '0', msgnum, headers);
399 ret = CtdlIPCGenericCommand(aaa, NULL, 0, &bbb, &bbbsize, cret);
400 if (ret / 100 == 1) {
402 while (strlen(bbb) > 4 && bbb[4] == '=') {
405 extract_token(aaa, bbb, 0, '\n');
408 safestrncpy(bbb, &bbb[a + 1], strlen(bbb) - a);
410 if (!strncasecmp(aaa, "nhdr=yes", 8))
412 else if (!strncasecmp(aaa, "from=", 5))
413 strcpy(mret[0]->author, &aaa[5]);
414 else if (!strncasecmp(aaa, "type=", 5))
415 mret[0]->type = atoi(&aaa[5]);
416 else if (!strncasecmp(aaa, "msgn=", 5))
417 strcpy(mret[0]->msgid, &aaa[5]);
418 else if (!strncasecmp(aaa, "subj=", 5))
419 strcpy(mret[0]->subject, &aaa[5]);
420 else if (!strncasecmp(aaa, "rfca=", 5))
421 strcpy(mret[0]->email, &aaa[5]);
422 else if (!strncasecmp(aaa, "hnod=", 5))
423 strcpy(mret[0]->hnod, &aaa[5]);
424 else if (!strncasecmp(aaa, "room=", 5))
425 strcpy(mret[0]->room, &aaa[5]);
426 else if (!strncasecmp(aaa, "node=", 5))
427 strcpy(mret[0]->node, &aaa[5]);
428 else if (!strncasecmp(aaa, "rcpt=", 5))
429 strcpy(mret[0]->recipient, &aaa[5]);
430 else if (!strncasecmp(aaa, "time=", 5))
431 mret[0]->time = atol(&aaa[5]);
432 else if (!strncasecmp(aaa, "part=", 5)) {
433 struct parts *ptr, *chain;
435 ptr = (struct parts *)calloc(1, sizeof (struct parts));
437 extract(ptr->name, &aaa[5], 0);
438 extract(ptr->filename, &aaa[5], 1);
439 extract(ptr->number, &aaa[5], 2);
440 extract(ptr->disposition, &aaa[5], 3);
441 extract(ptr->mimetype, &aaa[5], 4);
442 ptr->length = extract_long(&aaa[5], 5);
443 if (!mret[0]->attachments)
444 mret[0]->attachments = ptr;
446 chain = mret[0]->attachments;
454 /* Eliminate "text\n" */
455 safestrncpy(bbb, &bbb[5], strlen(bbb) - 4);
458 /* Strip trailing whitespace */
459 bbb = (char *)realloc(bbb, strlen(bbb) + 1);
470 int CtdlIPCWhoKnowsRoom(char **listing, char *cret)
475 if (!cret) return -2;
476 if (!listing) return -2;
477 if (*listing) return -2;
479 ret = CtdlIPCGenericCommand("WHOK", NULL, 0, listing, &bytes, cret);
485 int CtdlIPCServerInfo(char **listing, char *cret)
490 if (!cret) return -2;
491 if (!listing) return -2;
492 if (*listing) return -2;
494 ret = CtdlIPCGenericCommand("INFO", NULL, 0, listing, &bytes, cret);
500 int CtdlIPCReadDirectory(char **listing, char *cret)
505 if (!cret) return -2;
506 if (!listing) return -2;
507 if (*listing) return -2;
509 ret = CtdlIPCGenericCommand("RDIR", NULL, 0, listing, &bytes, cret);
515 * Set last-read pointer in this room to msgnum, or 0 for HIGHEST.
517 int CtdlIPCSetLastRead(long msgnum, char *cret)
522 if (!cret) return -2;
525 sprintf(aaa, "SLRP %ld", msgnum);
527 sprintf(aaa, "SLRP HIGHEST");
528 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
534 int CtdlIPCInviteUserToRoom(const char *username, char *cret)
539 if (!cret) return -2;
540 if (!username) return -2;
542 aaa = (char *)malloc(strlen(username) + 6);
545 sprintf(aaa, "INVT %s", username);
546 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
553 int CtdlIPCKickoutUserFromRoom(const char *username, char *cret)
558 if (!cret) return -1;
559 if (!username) return -1;
561 aaa = (char *)malloc(strlen(username) + 6);
563 sprintf(aaa, "KICK %s", username);
564 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
571 int CtdlIPCGetRoomAttributes(struct quickroom **qret, char *cret)
575 if (!cret) return -2;
576 if (!qret) return -2;
577 if (!*qret) *qret = (struct quickroom *)calloc(1, sizeof (struct quickroom));
578 if (!*qret) return -1;
580 ret = CtdlIPCGenericCommand("GETR", NULL, 0, NULL, NULL, cret);
581 if (ret / 100 == 2) {
582 extract(qret[0]->QRname, cret, 0);
583 extract(qret[0]->QRpasswd, cret, 1);
584 extract(qret[0]->QRdirname, cret, 2);
585 qret[0]->QRflags = extract_int(cret, 3);
586 qret[0]->QRfloor = extract_int(cret, 4);
587 qret[0]->QRorder = extract_int(cret, 5);
594 /* set forget to kick all users out of room */
595 int CtdlIPCSetRoomAttributes(int forget, struct quickroom *qret, char *cret)
600 if (!cret) return -2;
601 if (!qret) return -2;
603 aaa = (char *)malloc(strlen(qret->QRname) + strlen(qret->QRpasswd) +
604 strlen(qret->QRdirname) + 52);
607 sprintf(aaa, "SETR %s|%s|%s|%d|%d|%d|%d",
608 qret->QRname, qret->QRpasswd, qret->QRdirname,
609 qret->QRflags, forget, qret->QRfloor, qret->QRorder);
610 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
617 int CtdlIPCGetRoomAide(char *cret)
619 if (!cret) return -1;
621 return CtdlIPCGenericCommand("GETA", NULL, 0, NULL, NULL, cret);
626 int CtdlIPCSetRoomAide(const char *username, char *cret)
631 if (!cret) return -2;
632 if (!username) return -2;
634 aaa = (char *)malloc(strlen(username) + 6);
637 sprintf(aaa, "SETA %s", username);
638 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
645 int CtdlIPCPostMessage(int flag, const struct ctdlipcmessage *mr, char *cret)
650 if (!cret) return -2;
653 aaa = (char *)malloc(strlen(mr->recipient) + strlen(mr->author) + 40);
656 sprintf(aaa, "ENT0 %d|%s|%d|%d|%s", flag, mr->recipient, mr->anonymous,
657 mr->type, mr->author);
658 ret = CtdlIPCGenericCommand(aaa, mr->text, strlen(mr->text), NULL,
666 int CtdlIPCRoomInfo(char **iret, char *cret)
670 if (!cret) return -2;
671 if (!iret) return -2;
672 if (*iret) return -2;
674 return CtdlIPCGenericCommand("RINF", NULL, 0, iret, &bytes, cret);
679 int CtdlIPCDeleteMessage(long msgnum, char *cret)
683 if (!cret) return -2;
684 if (!msgnum) return -2;
686 sprintf(aaa, "DELE %ld", msgnum);
687 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
692 int CtdlIPCMoveMessage(int copy, long msgnum, const char *destroom, char *cret)
697 if (!cret) return -2;
698 if (!destroom) return -2;
699 if (!msgnum) return -2;
701 aaa = (char *)malloc(strlen(destroom) + 28);
704 sprintf(aaa, "MOVE %ld|%s|%d", msgnum, destroom, copy);
705 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
712 int CtdlIPCDeleteRoom(int for_real, char *cret)
716 if (!cret) return -2;
718 sprintf(aaa, "KILL %d", for_real);
719 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
724 int CtdlIPCCreateRoom(int for_real, const char *roomname, int type,
725 const char *password, int floor, char *cret)
730 if (!cret) return -2;
731 if (!roomname) return -2;
734 aaa = (char *)malloc(strlen(roomname) + strlen(password) + 40);
736 sprintf(aaa, "CRE8 %d|%s|%d|%s|%d", for_real, roomname, type,
739 aaa = (char *)malloc(strlen(roomname) + 40);
741 sprintf(aaa, "CRE8 %d|%s|%d||%d", for_real, roomname, type,
744 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
751 int CtdlIPCForgetRoom(char *cret)
753 if (!cret) return -2;
755 return CtdlIPCGenericCommand("FORG", NULL, 0, NULL, NULL, cret);
760 int CtdlIPCSystemMessage(const char *message, char **mret, char *cret)
766 if (!cret) return -2;
767 if (!mret) return -2;
768 if (*mret) return -2;
769 if (!message) return -2;
771 aaa = (char *)malloc(strlen(message) + 6);
774 sprintf(aaa, "MESG %s", message);
775 ret = CtdlIPCGenericCommand(aaa, NULL, 0, mret, &bytes, cret);
782 int CtdlIPCNextUnvalidatedUser(char *cret)
784 if (!cret) return -2;
786 return CtdlIPCGenericCommand("GNUR", NULL, 0, NULL, NULL, cret);
791 int CtdlIPCGetUserRegistration(const char *username, char **rret, char *cret)
797 if (!cret) return -2;
798 if (!rret) return -2;
799 if (*rret) return -2;
802 aaa = (char *)malloc(strlen(username) + 6);
804 aaa = (char *)malloc(12);
808 sprintf(aaa, "GREG %s", username);
810 sprintf(aaa, "GREG _SELF_");
811 ret = CtdlIPCGenericCommand(aaa, NULL, 0, rret, &bytes, cret);
818 int CtdlIPCValidateUser(const char *username, int axlevel, char *cret)
823 if (!cret) return -2;
824 if (!username) return -2;
825 if (axlevel < 0 || axlevel > 7) return -2;
827 aaa = (char *)malloc(strlen(username) + 17);
830 sprintf(aaa, "VALI %s|%d", username, axlevel);
831 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
838 int CtdlIPCSetRoomInfo(int for_real, const char *info, char *cret)
842 if (!cret) return -1;
843 if (!info) return -1;
845 sprintf(aaa, "EINF %d", for_real);
846 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
851 int CtdlIPCUserListing(char **listing, char *cret)
855 if (!cret) return -1;
856 if (!listing) return -1;
857 if (*listing) return -1;
859 return CtdlIPCGenericCommand("LIST", NULL, 0, listing, &bytes, cret);
864 int CtdlIPCSetRegistration(const char *info, char *cret)
866 if (!cret) return -1;
867 if (!info) return -1;
869 return CtdlIPCGenericCommand("REGI", info, strlen(info),
875 int CtdlIPCMiscCheck(struct ctdlipcmisc *chek, char *cret)
879 if (!cret) return -1;
880 if (!chek) return -1;
882 ret = CtdlIPCGenericCommand("CHEK", NULL, 0, NULL, NULL, cret);
883 if (ret / 100 == 2) {
884 chek->newmail = extract_long(cret, 0);
885 chek->needregis = extract_int(cret, 1);
886 chek->needvalid = extract_int(cret, 2);
893 int CtdlIPCDeleteFile(const char *filename, char *cret)
898 if (!cret) return -2;
899 if (!filename) return -2;
901 aaa = (char *)malloc(strlen(filename) + 6);
904 sprintf(aaa, "DELF %s", filename);
905 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
912 int CtdlIPCMoveFile(const char *filename, const char *destroom, char *cret)
917 if (!cret) return -2;
918 if (!filename) return -2;
919 if (!destroom) return -2;
921 aaa = (char *)malloc(strlen(filename) + strlen(destroom) + 7);
924 sprintf(aaa, "MOVF %s|%s", filename, destroom);
925 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
932 int CtdlIPCNetSendFile(const char *filename, const char *destnode, char *cret)
937 if (!cret) return -2;
938 if (!filename) return -2;
939 if (!destnode) return -2;
941 aaa = (char *)malloc(strlen(filename) + strlen(destnode) + 7);
944 sprintf(aaa, "NETF %s|%s", filename, destnode);
945 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
952 int CtdlIPCOnlineUsers(char **listing, time_t *stamp, char *cret)
957 if (!cret) return -1;
958 if (!listing) return -1;
959 if (*listing) return -1;
961 *stamp = CtdlIPCServerTime(cret);
964 ret = CtdlIPCGenericCommand("RWHO", NULL, 0, listing, &bytes, cret);
970 int CtdlIPCFileDownload(const char *filename, void **buf, char *cret)
978 if (!cret) return -2;
979 if (!filename) return -2;
982 if (download_in_progress) return -2;
984 aaa = (char *)malloc(strlen(filename) + 6);
987 sprintf(aaa, "OPEN %s", filename);
988 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
990 /* FIXME: Possible race condition */
991 if (ret / 100 == 2) {
992 download_in_progress = 1;
993 bytes = extract_long(cret, 0);
994 last_mod = extract_int(cret, 1);
995 extract(mimetype, cret, 2);
996 ret = CtdlIPCReadDownload(buf, bytes, cret);
997 ret = CtdlIPCEndDownload(cret);
999 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1000 filename, mimetype);
1007 int CtdlIPCAttachmentDownload(long msgnum, const char *part, void **buf,
1017 if (!cret) return -2;
1018 if (!buf) return -2;
1019 if (*buf) return -2;
1020 if (!part) return -2;
1021 if (!msgnum) return -2;
1022 if (download_in_progress) return -2;
1024 aaa = (char *)malloc(strlen(part) + 17);
1025 if (!aaa) return -1;
1027 sprintf(aaa, "OPNA %ld|%s", msgnum, part);
1028 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1030 /* FIXME: Possible race condition */
1031 if (ret / 100 == 2) {
1032 download_in_progress = 1;
1033 bytes = extract_long(cret, 0);
1034 last_mod = extract_int(cret, 1);
1035 extract(mimetype, cret, 2);
1036 ret = CtdlIPCReadDownload(buf, bytes, cret);
1037 ret = CtdlIPCEndDownload(cret);
1039 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1040 filename, mimetype);
1047 int CtdlIPCImageDownload(const char *filename, void **buf, char *cret)
1055 if (!cret) return -1;
1056 if (!buf) return -1;
1057 if (*buf) return -1;
1058 if (!filename) return -1;
1059 if (download_in_progress) return -1;
1061 aaa = (char *)malloc(strlen(filename) + 6);
1062 if (!aaa) return -1;
1064 sprintf(aaa, "OIMG %s", filename);
1065 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1067 /* FIXME: Possible race condition */
1068 if (ret / 100 == 2) {
1069 download_in_progress = 1;
1070 bytes = extract_long(cret, 0);
1071 last_mod = extract_int(cret, 1);
1072 extract(mimetype, cret, 2);
1073 ret = CtdlIPCReadDownload(buf, bytes, cret);
1074 ret = CtdlIPCEndDownload(cret);
1076 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1077 filename, mimetype);
1084 int CtdlIPCFileUpload(const char *filename, const char *comment, void *buf,
1085 size_t bytes, char *cret)
1090 if (!cret) return -1;
1091 if (!filename) return -1;
1092 if (!comment) return -1;
1093 if (upload_in_progress) return -1;
1095 aaa = (char *)malloc(strlen(filename) + strlen(comment) + 7);
1096 if (!aaa) return -1;
1098 sprintf(aaa, "UOPN %s|%s", filename, comment);
1099 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1101 /* FIXME: Possible race condition */
1103 upload_in_progress = 1;
1104 ret = CtdlIPCWriteUpload(buf, bytes, cret);
1105 ret = CtdlIPCEndUpload(cret);
1111 int CtdlIPCImageUpload(int for_real, const char *filename, size_t bytes,
1117 if (!cret) return -1;
1118 if (!filename) return -1;
1119 if (upload_in_progress) return -1;
1121 aaa = (char *)malloc(strlen(filename) + 17);
1122 if (!aaa) return -1;
1124 sprintf(aaa, "UIMG %d|%s", for_real, filename);
1125 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1127 /* FIXME: Possible race condition */
1129 upload_in_progress = 1;
1135 int CtdlIPCQueryUsername(const char *username, char *cret)
1140 if (!cret) return -2;
1141 if (!username) return -2;
1143 aaa = (char *)malloc(strlen(username) + 6);
1144 if (!aaa) return -1;
1146 sprintf(aaa, "QUSR %s", username);
1147 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1154 int CtdlIPCFloorListing(char **listing, char *cret)
1158 if (!cret) return -2;
1159 if (!listing) return -2;
1160 if (*listing) return -2;
1162 return CtdlIPCGenericCommand("LFLR", NULL, 0, listing, &bytes, cret);
1167 int CtdlIPCCreateFloor(int for_real, const char *name, char *cret)
1172 if (!cret) return -2;
1173 if (!name) return -2;
1175 aaa = (char *)malloc(strlen(name) + 17);
1176 if (!aaa) return -1;
1178 sprintf(aaa, "CFLR %s|%d", name, for_real);
1179 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1186 int CtdlIPCDeleteFloor(int for_real, int floornum, char *cret)
1190 if (!cret) return -1;
1191 if (floornum < 0) return -1;
1193 sprintf(aaa, "KFLR %d|%d", floornum, for_real);
1194 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1199 int CtdlIPCEditFloor(int floornum, const char *floorname, char *cret)
1204 if (!cret) return -2;
1205 if (!floorname) return -2;
1206 if (floornum < 0) return -2;
1208 aaa = (char *)malloc(strlen(floorname) + 17);
1209 if (!aaa) return -1;
1211 sprintf(aaa, "EFLR %d|%s", floornum, floorname);
1212 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1219 int CtdlIPCIdentifySoftware(int developerid, int clientid, int revision,
1220 const char *software_name, const char *hostname, char *cret)
1225 if (developerid < 0) return -2;
1226 if (clientid < 0) return -2;
1227 if (revision < 0) return -2;
1228 if (!software_name) return -2;
1229 if (!hostname) return -2;
1231 aaa = (char *)malloc(strlen(software_name) + strlen(hostname) + 29);
1232 if (!aaa) return -1;
1234 sprintf(aaa, "IDEN %d|%d|%d|%s|%s", developerid, clientid,
1235 revision, software_name, hostname);
1236 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1243 int CtdlIPCSendInstantMessage(const char *username, const char *text,
1249 if (!cret) return -2;
1250 if (!username) return -2;
1252 aaa = (char *)malloc(strlen(username) + 8);
1253 if (!aaa) return -1;
1256 sprintf(aaa, "SEXP %s|-", username);
1257 ret = CtdlIPCGenericCommand(aaa, text, strlen(text),
1260 sprintf(aaa, "SEXP %s||", username);
1261 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1269 int CtdlIPCGetInstantMessage(char **listing, char *cret)
1273 if (!cret) return -2;
1274 if (!listing) return -2;
1275 if (*listing) return -2;
1277 return CtdlIPCGenericCommand("GEXP", NULL, 0, listing, &bytes, cret);
1282 /* mode is 0 = enable, 1 = disable, 2 = status */
1283 int CtdlIPCEnableInstantMessageReceipt(int mode, char *cret)
1287 if (!cret) return -2;
1289 sprintf(aaa, "DEXP %d", mode);
1290 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1295 int CtdlIPCSetBio(char *bio, char *cret)
1297 if (!cret) return -2;
1298 if (!bio) return -2;
1300 return CtdlIPCGenericCommand("EBIO", bio, strlen(bio),
1306 int CtdlIPCGetBio(const char *username, char **listing, char *cret)
1312 if (!cret) return -2;
1313 if (!username) return -2;
1314 if (!listing) return -2;
1315 if (*listing) return -2;
1317 aaa = (char *)malloc(strlen(username) + 6);
1318 if (!aaa) return -1;
1320 sprintf(aaa, "RBIO %s", username);
1321 ret = CtdlIPCGenericCommand(aaa, NULL, 0, listing, &bytes, cret);
1328 int CtdlIPCListUsersWithBios(char **listing, char *cret)
1332 if (!cret) return -2;
1333 if (!listing) return -2;
1334 if (*listing) return -2;
1336 return CtdlIPCGenericCommand("LBIO", NULL, 0, listing, &bytes, cret);
1341 int CtdlIPCStealthMode(int mode, char *cret)
1345 if (!cret) return -1;
1347 sprintf(aaa, "STEL %d", mode ? 1 : 0);
1348 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1353 int CtdlIPCTerminateSession(int sid, char *cret)
1357 if (!cret) return -1;
1359 sprintf(aaa, "TERM %d", sid);
1360 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1365 int CtdlIPCTerminateServerNow(char *cret)
1367 if (!cret) return -1;
1369 return CtdlIPCGenericCommand("DOWN", NULL, 0, NULL, NULL, cret);
1374 int CtdlIPCTerminateServerScheduled(int mode, char *cret)
1378 if (!cret) return -1;
1380 sprintf(aaa, "SCDN %d", mode ? 1 : 0);
1381 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1386 int CtdlIPCEnterSystemMessage(const char *filename, const char *text,
1392 if (!cret) return -2;
1393 if (!text) return -2;
1394 if (!filename) return -2;
1396 aaa = (char *)malloc(strlen(filename) + 6);
1397 if (!aaa) return -1;
1399 sprintf(aaa, "EMSG %s", filename);
1400 ret = CtdlIPCGenericCommand(aaa, text, strlen(text), NULL, NULL, cret);
1407 int CtdlIPCChangeHostname(const char *hostname, char *cret)
1412 if (!cret) return -2;
1413 if (!hostname) return -2;
1415 aaa = (char *)malloc(strlen(hostname) + 6);
1416 if (!aaa) return -1;
1418 sprintf(aaa, "HCHG %s", hostname);
1419 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1426 int CtdlIPCChangeRoomname(const char *roomname, char *cret)
1431 if (!cret) return -2;
1432 if (!roomname) return -2;
1434 aaa = (char *)malloc(strlen(roomname) + 6);
1435 if (!aaa) return -1;
1437 sprintf(aaa, "RCHG %s", roomname);
1438 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1445 int CtdlIPCChangeUsername(const char *username, char *cret)
1450 if (!cret) return -2;
1451 if (!username) return -2;
1453 aaa = (char *)malloc(strlen(username) + 6);
1454 if (!aaa) return -1;
1456 sprintf(aaa, "UCHG %s", username);
1457 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1464 /* This function returns the actual server time reported, or 0 if error */
1465 time_t CtdlIPCServerTime(char *cret)
1467 register time_t tret;
1470 ret = CtdlIPCGenericCommand("TIME", NULL, 0, NULL, NULL, cret);
1471 if (ret / 100 == 2) {
1472 tret = extract_long(cret, 0);
1481 int CtdlIPCAideGetUserParameters(struct usersupp **uret, char *cret)
1486 if (!cret) return -2;
1487 if (!uret) return -2;
1488 if (!*uret) return -2;
1490 aaa = (char *)malloc(strlen(uret[0]->fullname) + 6);
1491 if (!aaa) return -1;
1493 sprintf(aaa, "AGUP %s", uret[0]->fullname);
1494 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1495 if (ret / 100 == 2) {
1496 extract(uret[0]->fullname, cret, 0);
1497 extract(uret[0]->password, cret, 1);
1498 uret[0]->flags = extract_int(cret, 2);
1499 uret[0]->timescalled = extract_long(cret, 3);
1500 uret[0]->posted = extract_long(cret, 4);
1501 uret[0]->axlevel = extract_int(cret, 5);
1502 uret[0]->usernum = extract_long(cret, 6);
1503 uret[0]->lastcall = extract_long(cret, 7);
1504 uret[0]->USuserpurge = extract_int(cret, 8);
1512 int CtdlIPCAideSetUserParameters(const struct usersupp *uret, char *cret)
1517 if (!cret) return -2;
1518 if (!uret) return -2;
1520 aaa = (char *)malloc(strlen(uret->fullname) + strlen(uret->password) + 84);
1521 if (!aaa) return -1;
1523 sprintf(aaa, "ASUP %s|%s|%d|%ld|%ld|%d|%ld|%ld|%d",
1524 uret->fullname, uret->password, uret->flags,
1525 uret->timescalled, uret->posted, uret->axlevel,
1526 uret->usernum, uret->lastcall, uret->USuserpurge);
1527 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1534 /* which is 0 = room, 1 = floor, 2 = site */
1535 int CtdlIPCGetMessageExpirationPolicy(int which, char *cret)
1537 static char *proto[] = {"room", "floor", "site"};
1540 if (!cret) return -2;
1541 if (which < 0 || which > 2) return -2;
1543 sprintf(aaa, "GPEX %s", proto[which]);
1544 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1549 /* which is 0 = room, 1 = floor, 2 = site */
1550 /* policy is 0 = inherit, 1 = no purge, 2 = by count, 3 = by age (days) */
1551 int CtdlIPCSetMessageExpirationPolicy(int which, int policy, int value,
1556 if (!cret) return -2;
1557 if (which < 0 || which > 2) return -2;
1558 if (policy < 0 || policy > 3) return -2;
1559 if (policy >= 2 && value < 1) return -2;
1561 sprintf(aaa, "SPEX %d|%d|%d", which, policy, value);
1562 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1567 int CtdlGetSystemConfig(char **listing, char *cret)
1571 if (!cret) return -2;
1572 if (!listing) return -2;
1573 if (*listing) return -2;
1575 return CtdlIPCGenericCommand("CONF GET", NULL, 0,
1576 listing, &bytes, cret);
1581 int CtdlSetSystemConfig(const char *listing, char *cret)
1583 if (!cret) return -2;
1584 if (!listing) return -2;
1586 return CtdlIPCGenericCommand("CONF SET", listing, strlen(listing),
1592 int CtdlIPCModerateMessage(long msgnum, int level, char *cret)
1596 if (!cret) return -2;
1597 if (!msgnum) return -2;
1599 sprintf(aaa, "MMOD %ld|%d", msgnum, level);
1600 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1605 int CtdlIPCRequestClientLogout(int session, char *cret)
1609 if (!cret) return -2;
1610 if (session < 0) return -2;
1612 sprintf(aaa, "REQT %d", session);
1613 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1618 int CtdlIPCSetMessageSeen(long msgnum, int seen, char *cret)
1622 if (!cret) return -2;
1623 if (msgnum < 0) return -2;
1625 sprintf(aaa, "SEEN %ld|%d", msgnum, seen ? 1 : 0);
1626 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1631 int CtdlIPCStartEncryption(char *cret)
1633 return CtdlIPCGenericCommand("STLS", NULL, 0, NULL, NULL, cret);
1655 /* ************************************************************************** */
1656 /* Stuff below this line is not for public consumption */
1657 /* ************************************************************************** */
1660 inline void netio_lock(void)
1662 #ifdef THREADED_CLIENT
1663 pthread_mutex_lock(&rwlock);
1668 inline void netio_unlock(void)
1670 #ifdef THREADED_CLIENT
1671 pthread_mutex_unlock(&rwlock);
1676 /* Read a listing from the server up to 000. Append to dest if it exists */
1677 char *CtdlIPCReadListing(char *dest)
1684 if (ret) length = strlen(ret);
1685 while (serv_gets(aaa), strcmp(aaa, "000")) {
1686 ret = (char *)realloc(ret, length + strlen(aaa) + 2);
1688 strcpy(&ret[length], aaa);
1689 length += strlen(aaa);
1690 strcpy(&ret[length++], "\n");
1697 /* Send a listing to the server; generate the ending 000. */
1698 int CtdlIPCSendListing(const char *listing)
1702 text = (char *)malloc(strlen(listing) + 5);
1704 strcpy(text, listing);
1705 if (text[strlen(text) - 1] == '\n')
1706 text[strlen(text) - 1] = '\0';
1707 strcat(text, "000");
1712 /* Malloc failed but we are committed to send */
1713 /* This may result in extra blanks at the bottom */
1721 /* Partial read of file from server */
1722 size_t CtdlIPCPartialRead(void **buf, size_t offset, size_t bytes, char *cret)
1724 register size_t len = 0;
1727 if (!buf) return -1;
1728 if (!cret) return -1;
1729 if (bytes < 1) return -1;
1730 if (offset < 0) return -1;
1733 sprintf(aaa, "READ %d|%d", offset, bytes);
1737 strcpy(cret, &aaa[4]);
1739 len = extract_long(&aaa[4], 0);
1740 *buf = (void *)realloc(*buf, offset + len);
1742 /* I know what I'm doing */
1743 serv_read((char *)&buf[offset], len);
1745 /* We have to read regardless */
1746 serv_read(aaa, len);
1756 int CtdlIPCEndDownload(char *cret)
1760 if (!cret) return -2;
1761 if (!download_in_progress) return -2;
1763 ret = CtdlIPCGenericCommand("CLOS", NULL, 0, NULL, NULL, cret);
1765 download_in_progress = 0;
1771 int CtdlIPCReadDownload(void **buf, size_t bytes, char *cret)
1773 register size_t len;
1775 if (!cret) return -1;
1776 if (!buf) return -1;
1777 if (*buf) return -1;
1778 if (!download_in_progress) return -1;
1781 while (len < bytes) {
1782 len = CtdlIPCPartialRead(buf, len, 4096, cret);
1793 int CtdlIPCEndUpload(char *cret)
1797 if (!cret) return -1;
1798 if (!upload_in_progress) return -1;
1800 ret = CtdlIPCGenericCommand("UCLS", NULL, 0, NULL, NULL, cret);
1802 upload_in_progress = 0;
1808 int CtdlIPCWriteUpload(void *buf, size_t bytes, char *cret)
1810 register int ret = -1;
1811 register size_t offset;
1814 if (!cret) return -1;
1815 if (!buf) return -1;
1816 if (bytes < 1) return -1;
1819 while (offset < bytes) {
1820 sprintf(aaa, "WRIT %d", bytes - offset);
1823 strcpy(cret, &aaa[4]);
1825 if (aaa[0] == '7') {
1826 register size_t to_write;
1828 to_write = extract_long(&aaa[4], 0);
1829 serv_write(buf + offset, to_write);
1840 * Generic command method. This method should handle any server command
1841 * except for CHAT. It takes the following arguments:
1843 * command Preformatted command to send to server
1844 * to_send A text or binary file to send to server
1845 * (only sent if server requests it)
1846 * bytes_to_send The number of bytes in to_send (required if
1847 * sending binary, optional if sending listing)
1848 * to_receive Pointer to a NULL pointer, if the server
1849 * sends text or binary we will allocate memory
1850 * for the file and stuff it here
1851 * bytes_to_receive If a file is received, we will store its
1853 * proto_response The protocol response. Caller must provide
1854 * this buffer and ensure that it is at least
1855 * 128 bytes in length.
1857 * This function returns a number equal to the protocol response number,
1858 * -1 if an internal error occurred, -2 if caller provided bad values,
1859 * or 0 - the protocol response number if bad values were found during
1860 * the protocol exchange.
1861 * It stores the protocol response string (minus the number) in
1862 * protocol_response as described above. Some commands send additional
1863 * data in this string.
1865 int CtdlIPCGenericCommand(const char *command, const char *to_send,
1866 size_t bytes_to_send, char **to_receive,
1867 size_t *bytes_to_receive, char *proto_response)
1872 if (!command) return -2;
1873 if (!proto_response) return -2;
1876 serv_puts((char *)command);
1878 serv_gets(proto_response);
1879 if (proto_response[3] == '*')
1881 ret = atoi(proto_response);
1882 memmove(proto_response, &proto_response[4],
1883 strlen(proto_response) - 3);
1884 switch (ret / 100) {
1885 default: /* Unknown, punt */
1887 case 3: /* MORE_DATA */
1889 /* Don't need to do anything */
1891 case 1: /* LISTING_FOLLOWS */
1892 if (to_receive && !*to_receive && bytes_to_receive) {
1893 *to_receive = CtdlIPCReadListing(NULL);
1894 } else { /* Drain */
1895 while (serv_gets(buf), strcmp(buf, "000")) ;
1899 case 4: /* SEND_LISTING */
1901 CtdlIPCSendListing(to_send);
1903 /* No listing given, fake it */
1908 case 6: /* BINARY_FOLLOWS */
1909 if (to_receive && !*to_receive && bytes_to_receive) {
1911 extract_long(proto_response, 0);
1912 *to_receive = (char *)malloc(*bytes_to_receive);
1916 serv_read(*to_receive,
1923 drain = extract_long(proto_response, 0);
1924 while (drain > SIZ) {
1925 serv_read(buf, SIZ);
1928 serv_read(buf, drain);
1932 case 7: /* SEND_BINARY */
1933 if (to_send && bytes_to_send) {
1934 serv_write((char *)to_send, bytes_to_send);
1935 } else if (bytes_to_send) {
1936 /* Fake it, send nulls */
1939 fake = bytes_to_send;
1940 memset(buf, '\0', SIZ);
1941 while (fake > SIZ) {
1942 serv_write(buf, SIZ);
1945 serv_write(buf, fake);
1947 } /* else who knows? DANGER WILL ROBINSON */
1949 case 8: /* START_CHAT_MODE */
1950 if (!strncasecmp(command, "CHAT", 4)) {
1951 /* Don't call chatmode with generic! */
1955 /* In this mode we send then receive listing */
1957 CtdlIPCSendListing(to_send);
1959 /* No listing given, fake it */
1963 if (to_receive && !*to_receive
1964 && bytes_to_receive) {
1965 *to_receive = CtdlIPCReadListing(NULL);
1966 } else { /* Drain */
1967 while (serv_gets(buf),
1968 strcmp(buf, "000")) ;
1973 case 9: /* ASYNC_MSG */
1974 /* CtdlIPCDoAsync(ret, proto_response); */
1975 free(CtdlIPCReadListing(NULL)); /* STUB FIXME */