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 char express_msgs = 0;
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.
45 return CtdlIPCGenericCommand("NOOP", NULL, 0, NULL, NULL, aaa);
50 * Does nothing interesting. The server should always return 200
51 * along with your string.
53 int CtdlIPCEcho(const char *arg, char *cret)
61 aaa = (char *)malloc(strlen(arg) + 6);
64 sprintf(aaa, "ECHO %s", arg);
65 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
72 * Asks the server to close the connecction.
73 * Should always return 200.
90 * Asks the server to logout. Should always return 200, even if no user
91 * was logged in. The user will not be logged in after this!
93 int CtdlIPCLogout(void)
108 * First stage of authentication - pass the username. Returns 300 if the
109 * username is able to log in, with the username correctly spelled in cret.
110 * Returns various 500 error codes if the user doesn't exist, etc.
112 int CtdlIPCTryLogin(const char *username, char *cret)
117 if (!username) return -2;
118 if (!cret) return -2;
120 aaa = (char *)malloc(strlen(username) + 6);
123 sprintf(aaa, "USER %s", username);
124 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
131 * Second stage of authentication - provide password. The server returns
132 * 200 and several arguments in cret relating to the user's account.
134 int CtdlIPCTryPassword(const char *passwd, char *cret)
139 if (!passwd) return -2;
140 if (!cret) return -2;
142 aaa = (char *)malloc(strlen(passwd) + 6);
145 sprintf(aaa, "PASS %s", passwd);
146 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
153 * Create a new user. This returns 200 plus the same arguments as TryPassword
154 * if selfservice is nonzero, unless there was a problem creating the account.
155 * If selfservice is zero, creates a new user but does not log out the existing
156 * user - intended for use by system administrators to create accounts on
157 * behalf of other users.
159 int CtdlIPCCreateUser(const char *username, int selfservice, char *cret)
164 if (!username) return -2;
165 if (!cret) return -2;
167 aaa = (char *)malloc(strlen(username) + 6);
170 sprintf(aaa, "%s %s", selfservice ? "NEWU" : "CREU", username);
171 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
178 * Changes the user's password. Returns 200 if changed, errors otherwise.
180 int CtdlIPCChangePassword(const char *passwd, char *cret)
185 if (!passwd) return -2;
186 if (!cret) return -2;
188 aaa = (char *)malloc(strlen(passwd) + 6);
191 sprintf(aaa, "SETP %s", passwd);
192 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
199 /* Caller must free the march list */
200 /* which is 0 = LRMS, 1 = LKRN, 2 = LKRO, 3 = LKRA, 4 = LZRM */
201 /* floor is -1 for all, or floornum */
202 int CtdlIPCKnownRooms(int which, int floor, struct march **listing, char *cret)
205 struct march *march = NULL;
206 static char *proto[] = {"LRMS", "LKRN", "LKRO", "LKRA", "LZRM" };
211 if (!listing) return -2;
212 if (*listing) return -2; /* Free the listing first */
213 if (!cret) return -2;
214 if (which < 0 || which > 4) return -2;
215 if (floor < -1) return -2; /* Can't validate upper bound, sorry */
217 sprintf(aaa, "%s %d", proto[which], floor);
218 ret = CtdlIPCGenericCommand(aaa, NULL, 0, &bbb, &bbbsize, cret);
219 if (ret / 100 == 1) {
222 while (bbb && strlen(bbb)) {
225 extract_token(aaa, bbb, 0, '\n');
227 memmove(bbb, bbb + a + 1, strlen(bbb) - a);
228 mptr = (struct march *) malloc(sizeof (struct march));
231 extract(mptr->march_name, aaa, 0);
232 mptr->march_floor = (char) extract_int(aaa, 2);
233 mptr->march_order = (char) extract_int(aaa, 3);
240 while (mptr2->next != NULL)
253 /* Caller must free the struct usersupp; caller may pass an existing one */
254 int CtdlIPCGetConfig(struct usersupp **uret, char *cret)
258 if (!cret) return -2;
259 if (!uret) return -2;
260 if (!*uret) *uret = (struct usersupp *)calloc(1, sizeof (struct usersupp));
261 if (!*uret) return -1;
263 ret = CtdlIPCGenericCommand("GETU", NULL, 0, NULL, NULL, cret);
264 if (ret / 100 == 2) {
265 uret[0]->USscreenwidth = extract_int(cret, 0);
266 uret[0]->USscreenheight = extract_int(cret, 1);
267 uret[0]->flags = extract_int(cret, 2);
274 int CtdlIPCSetConfig(struct usersupp *uret, char *cret)
278 if (!uret) return -2;
279 if (!cret) return -2;
281 sprintf(aaa, "SETU %d|%d|%d",
282 uret->USscreenwidth, uret->USscreenheight,
284 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
289 int CtdlIPCGotoRoom(const char *room, const char *passwd,
290 struct ctdlipcroom **rret, char *cret)
295 if (!cret) return -2;
296 if (!rret) return -2;
297 if (!*rret) *rret = (struct ctdlipcroom *)calloc(1, sizeof (struct ctdlipcroom));
298 if (!*rret) return -1;
301 aaa = (char *)malloc(strlen(room) + strlen(passwd) + 7);
306 sprintf(aaa, "GOTO %s|%s", room, passwd);
308 aaa = (char *)malloc(strlen(room) + 6);
313 sprintf(aaa, "GOTO %s", room);
315 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
316 if (ret / 100 == 2) {
317 extract(rret[0]->RRname, cret, 0);
318 rret[0]->RRunread = extract_long(cret, 1);
319 rret[0]->RRtotal = extract_long(cret, 2);
320 rret[0]->RRinfoupdated = extract_int(cret, 3);
321 rret[0]->RRflags = extract_int(cret, 4);
322 rret[0]->RRhighest = extract_long(cret, 5);
323 rret[0]->RRlastread = extract_long(cret, 6);
324 rret[0]->RRismailbox = extract_int(cret, 7);
325 rret[0]->RRaide = extract_int(cret, 8);
326 rret[0]->RRnewmail = extract_long(cret, 9);
327 rret[0]->RRfloor = extract_int(cret, 10);
336 /* which is 0 = all, 1 = old, 2 = new, 3 = last, 4 = first, 5 = gt, 6 = lt */
337 /* whicharg is number of messages, applies to last, first, gt, lt */
338 int CtdlIPCGetMessages(int which, int whicharg, const char *template,
339 long **mret, char *cret)
342 register long count = 0;
343 static char *proto[] =
344 { "ALL", "OLD", "NEW", "LAST", "FIRST", "GT", "LT" };
349 if (!cret) return -2;
350 if (!mret) return -2;
351 if (*mret) return -2;
352 if (which < 0 || which > 6) return -2;
355 sprintf(aaa, "MSGS %s||%d", proto[which],
358 sprintf(aaa, "MSGS %s|%d|%d", proto[which], whicharg,
360 if (template) count = strlen(template);
361 ret = CtdlIPCGenericCommand(aaa, template, count, &bbb, &bbbsize, cret);
363 while (strlen(bbb)) {
366 extract_token(aaa, bbb, 0, '\n');
368 memmove(aaa, bbb + a + 1, strlen(bbb) - a - 1);
369 *mret = (long *)realloc(mret, (count + 1) * sizeof (long));
371 *mret[count++] = atol(aaa);
379 int CtdlIPCGetSingleMessage(long msgnum, int headers, int as_mime,
380 struct ctdlipcmessage **mret, char *cret)
387 if (!cret) return -1;
388 if (!mret) return -1;
389 if (!*mret) *mret = (struct ctdlipcmessage *)calloc(1, sizeof (struct ctdlipcmessage));
390 if (!*mret) return -1;
391 if (!msgnum) return -1;
393 sprintf(aaa, "MSG%c %ld|%d", as_mime ? '2' : '0', msgnum, headers);
394 ret = CtdlIPCGenericCommand(aaa, NULL, 0, &bbb, &bbbsize, cret);
395 if (ret / 100 == 1) {
397 while (strlen(bbb) > 4 && bbb[4] == '=') {
398 extract_token(aaa, bbb, 0, '\n');
399 remove_token(bbb, 0, '\n');
401 if (!strncasecmp(aaa, "nhdr=yes", 8))
403 else if (!strncasecmp(aaa, "from=", 5))
404 strcpy(mret[0]->author, &aaa[5]);
405 else if (!strncasecmp(aaa, "type=", 5))
406 mret[0]->type = atoi(&aaa[5]);
407 else if (!strncasecmp(aaa, "msgn=", 5))
408 strcpy(mret[0]->msgid, &aaa[5]);
409 else if (!strncasecmp(aaa, "subj=", 5))
410 strcpy(mret[0]->subject, &aaa[5]);
411 else if (!strncasecmp(aaa, "rfca=", 5))
412 strcpy(mret[0]->email, &aaa[5]);
413 else if (!strncasecmp(aaa, "hnod=", 5))
414 strcpy(mret[0]->hnod, &aaa[5]);
415 else if (!strncasecmp(aaa, "room=", 5))
416 strcpy(mret[0]->room, &aaa[5]);
417 else if (!strncasecmp(aaa, "node=", 5))
418 strcpy(mret[0]->node, &aaa[5]);
419 else if (!strncasecmp(aaa, "rcpt=", 5))
420 strcpy(mret[0]->recipient, &aaa[5]);
421 else if (!strncasecmp(aaa, "time=", 5))
422 mret[0]->time = atol(&aaa[5]);
423 else if (!strncasecmp(aaa, "part=", 5)) {
424 struct parts *ptr, *chain;
426 ptr = (struct parts *)calloc(1, sizeof (struct parts));
428 extract(ptr->name, &aaa[5], 0);
429 extract(ptr->filename, &aaa[5], 1);
430 extract(ptr->number, &aaa[5], 2);
431 extract(ptr->disposition, &aaa[5], 3);
432 extract(ptr->mimetype, &aaa[5], 4);
433 ptr->length = extract_long(&aaa[5], 5);
434 if (!mret[0]->attachments)
435 mret[0]->attachments = ptr;
437 chain = mret[0]->attachments;
445 /* Eliminate "text\n" */
446 remove_token(bbb, 0, '\n');
449 /* Strip trailing whitespace */
450 bbb = (char *)realloc(bbb, strlen(bbb) + 1);
452 bbb = (char *)realloc(bbb, 1);
462 int CtdlIPCWhoKnowsRoom(char **listing, char *cret)
467 if (!cret) return -2;
468 if (!listing) return -2;
469 if (*listing) return -2;
471 ret = CtdlIPCGenericCommand("WHOK", NULL, 0, listing, &bytes, cret);
477 int CtdlIPCServerInfo(struct CtdlServInfo *ServInfo, char *cret)
481 char *listing = NULL;
484 if (!cret) return -2;
485 if (!ServInfo) return -2;
487 ret = CtdlIPCGenericCommand("INFO", NULL, 0, &listing, &bytes, cret);
488 if (ret / 100 == 1) {
491 while (*listing && strlen(listing)) {
492 extract_token(buf, listing, 0, '\n');
493 remove_token(listing, 0, '\n');
495 case 0: ServInfo->serv_pid = atoi(buf);
497 case 1: strcpy(ServInfo->serv_nodename,buf);
499 case 2: strcpy(ServInfo->serv_humannode,buf);
501 case 3: strcpy(ServInfo->serv_fqdn,buf);
503 case 4: strcpy(ServInfo->serv_software,buf);
505 case 5: ServInfo->serv_rev_level = atoi(buf);
507 case 6: strcpy(ServInfo->serv_bbs_city,buf);
509 case 7: strcpy(ServInfo->serv_sysadm,buf);
511 case 9: strcpy(ServInfo->serv_moreprompt,buf);
513 case 10: ServInfo->serv_ok_floors = atoi(buf);
515 case 11: ServInfo->serv_paging_level = atoi(buf);
517 case 13: ServInfo->serv_supports_qnop = atoi(buf);
528 int CtdlIPCReadDirectory(char **listing, char *cret)
533 if (!cret) return -2;
534 if (!listing) return -2;
535 if (*listing) return -2;
537 ret = CtdlIPCGenericCommand("RDIR", NULL, 0, listing, &bytes, cret);
543 * Set last-read pointer in this room to msgnum, or 0 for HIGHEST.
545 int CtdlIPCSetLastRead(long msgnum, char *cret)
550 if (!cret) return -2;
553 sprintf(aaa, "SLRP %ld", msgnum);
555 sprintf(aaa, "SLRP HIGHEST");
556 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
562 int CtdlIPCInviteUserToRoom(const char *username, char *cret)
567 if (!cret) return -2;
568 if (!username) return -2;
570 aaa = (char *)malloc(strlen(username) + 6);
573 sprintf(aaa, "INVT %s", username);
574 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
581 int CtdlIPCKickoutUserFromRoom(const char *username, char *cret)
586 if (!cret) return -1;
587 if (!username) return -1;
589 aaa = (char *)malloc(strlen(username) + 6);
591 sprintf(aaa, "KICK %s", username);
592 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
599 int CtdlIPCGetRoomAttributes(struct quickroom **qret, char *cret)
603 if (!cret) return -2;
604 if (!qret) return -2;
605 if (!*qret) *qret = (struct quickroom *)calloc(1, sizeof (struct quickroom));
606 if (!*qret) return -1;
608 ret = CtdlIPCGenericCommand("GETR", NULL, 0, NULL, NULL, cret);
609 if (ret / 100 == 2) {
610 extract(qret[0]->QRname, cret, 0);
611 extract(qret[0]->QRpasswd, cret, 1);
612 extract(qret[0]->QRdirname, cret, 2);
613 qret[0]->QRflags = extract_int(cret, 3);
614 qret[0]->QRfloor = extract_int(cret, 4);
615 qret[0]->QRorder = extract_int(cret, 5);
622 /* set forget to kick all users out of room */
623 int CtdlIPCSetRoomAttributes(int forget, struct quickroom *qret, char *cret)
628 if (!cret) return -2;
629 if (!qret) return -2;
631 aaa = (char *)malloc(strlen(qret->QRname) + strlen(qret->QRpasswd) +
632 strlen(qret->QRdirname) + 52);
635 sprintf(aaa, "SETR %s|%s|%s|%d|%d|%d|%d",
636 qret->QRname, qret->QRpasswd, qret->QRdirname,
637 qret->QRflags, forget, qret->QRfloor, qret->QRorder);
638 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
645 int CtdlIPCGetRoomAide(char *cret)
647 if (!cret) return -1;
649 return CtdlIPCGenericCommand("GETA", NULL, 0, NULL, NULL, cret);
654 int CtdlIPCSetRoomAide(const char *username, char *cret)
659 if (!cret) return -2;
660 if (!username) return -2;
662 aaa = (char *)malloc(strlen(username) + 6);
665 sprintf(aaa, "SETA %s", username);
666 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
673 int CtdlIPCPostMessage(int flag, const struct ctdlipcmessage *mr, char *cret)
678 if (!cret) return -2;
681 aaa = (char *)malloc(strlen(mr->recipient) + strlen(mr->author) + 40);
684 sprintf(aaa, "ENT0 %d|%s|%d|%d|%s", flag, mr->recipient, mr->anonymous,
685 mr->type, mr->author);
686 ret = CtdlIPCGenericCommand(aaa, mr->text, strlen(mr->text), NULL,
694 int CtdlIPCRoomInfo(char **iret, char *cret)
698 if (!cret) return -2;
699 if (!iret) return -2;
700 if (*iret) return -2;
702 return CtdlIPCGenericCommand("RINF", NULL, 0, iret, &bytes, cret);
707 int CtdlIPCDeleteMessage(long msgnum, char *cret)
711 if (!cret) return -2;
712 if (!msgnum) return -2;
714 sprintf(aaa, "DELE %ld", msgnum);
715 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
720 int CtdlIPCMoveMessage(int copy, long msgnum, const char *destroom, char *cret)
725 if (!cret) return -2;
726 if (!destroom) return -2;
727 if (!msgnum) return -2;
729 aaa = (char *)malloc(strlen(destroom) + 28);
732 sprintf(aaa, "MOVE %ld|%s|%d", msgnum, destroom, copy);
733 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
740 int CtdlIPCDeleteRoom(int for_real, char *cret)
744 if (!cret) return -2;
746 sprintf(aaa, "KILL %d", for_real);
747 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
752 int CtdlIPCCreateRoom(int for_real, const char *roomname, int type,
753 const char *password, int floor, char *cret)
758 if (!cret) return -2;
759 if (!roomname) return -2;
762 aaa = (char *)malloc(strlen(roomname) + strlen(password) + 40);
764 sprintf(aaa, "CRE8 %d|%s|%d|%s|%d", for_real, roomname, type,
767 aaa = (char *)malloc(strlen(roomname) + 40);
769 sprintf(aaa, "CRE8 %d|%s|%d||%d", for_real, roomname, type,
772 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
779 int CtdlIPCForgetRoom(char *cret)
781 if (!cret) return -2;
783 return CtdlIPCGenericCommand("FORG", NULL, 0, NULL, NULL, cret);
788 int CtdlIPCSystemMessage(const char *message, char **mret, char *cret)
794 if (!cret) return -2;
795 if (!mret) return -2;
796 if (*mret) return -2;
797 if (!message) return -2;
799 aaa = (char *)malloc(strlen(message) + 6);
802 sprintf(aaa, "MESG %s", message);
803 ret = CtdlIPCGenericCommand(aaa, NULL, 0, mret, &bytes, cret);
810 int CtdlIPCNextUnvalidatedUser(char *cret)
812 if (!cret) return -2;
814 return CtdlIPCGenericCommand("GNUR", NULL, 0, NULL, NULL, cret);
819 int CtdlIPCGetUserRegistration(const char *username, char **rret, char *cret)
825 if (!cret) return -2;
826 if (!rret) return -2;
827 if (*rret) return -2;
830 aaa = (char *)malloc(strlen(username) + 6);
832 aaa = (char *)malloc(12);
836 sprintf(aaa, "GREG %s", username);
838 sprintf(aaa, "GREG _SELF_");
839 ret = CtdlIPCGenericCommand(aaa, NULL, 0, rret, &bytes, cret);
846 int CtdlIPCValidateUser(const char *username, int axlevel, char *cret)
851 if (!cret) return -2;
852 if (!username) return -2;
853 if (axlevel < 0 || axlevel > 7) return -2;
855 aaa = (char *)malloc(strlen(username) + 17);
858 sprintf(aaa, "VALI %s|%d", username, axlevel);
859 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
866 int CtdlIPCSetRoomInfo(int for_real, const char *info, char *cret)
870 if (!cret) return -1;
871 if (!info) return -1;
873 sprintf(aaa, "EINF %d", for_real);
874 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
879 int CtdlIPCUserListing(char **listing, char *cret)
883 if (!cret) return -1;
884 if (!listing) return -1;
885 if (*listing) return -1;
887 return CtdlIPCGenericCommand("LIST", NULL, 0, listing, &bytes, cret);
892 int CtdlIPCSetRegistration(const char *info, char *cret)
894 if (!cret) return -1;
895 if (!info) return -1;
897 return CtdlIPCGenericCommand("REGI", info, strlen(info),
903 int CtdlIPCMiscCheck(struct ctdlipcmisc *chek, char *cret)
907 if (!cret) return -1;
908 if (!chek) return -1;
910 ret = CtdlIPCGenericCommand("CHEK", NULL, 0, NULL, NULL, cret);
911 if (ret / 100 == 2) {
912 chek->newmail = extract_long(cret, 0);
913 chek->needregis = extract_int(cret, 1);
914 chek->needvalid = extract_int(cret, 2);
921 int CtdlIPCDeleteFile(const char *filename, char *cret)
926 if (!cret) return -2;
927 if (!filename) return -2;
929 aaa = (char *)malloc(strlen(filename) + 6);
932 sprintf(aaa, "DELF %s", filename);
933 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
940 int CtdlIPCMoveFile(const char *filename, const char *destroom, char *cret)
945 if (!cret) return -2;
946 if (!filename) return -2;
947 if (!destroom) return -2;
949 aaa = (char *)malloc(strlen(filename) + strlen(destroom) + 7);
952 sprintf(aaa, "MOVF %s|%s", filename, destroom);
953 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
960 int CtdlIPCNetSendFile(const char *filename, const char *destnode, char *cret)
965 if (!cret) return -2;
966 if (!filename) return -2;
967 if (!destnode) return -2;
969 aaa = (char *)malloc(strlen(filename) + strlen(destnode) + 7);
972 sprintf(aaa, "NETF %s|%s", filename, destnode);
973 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
980 int CtdlIPCOnlineUsers(char **listing, time_t *stamp, char *cret)
985 if (!cret) return -1;
986 if (!listing) return -1;
987 if (*listing) return -1;
989 *stamp = CtdlIPCServerTime(cret);
992 ret = CtdlIPCGenericCommand("RWHO", NULL, 0, listing, &bytes, cret);
998 int CtdlIPCFileDownload(const char *filename, void **buf, char *cret)
1006 if (!cret) return -2;
1007 if (!filename) return -2;
1008 if (!buf) return -2;
1009 if (*buf) return -2;
1010 if (download_in_progress) return -2;
1012 aaa = (char *)malloc(strlen(filename) + 6);
1013 if (!aaa) return -1;
1015 sprintf(aaa, "OPEN %s", filename);
1016 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1018 /* FIXME: Possible race condition */
1019 if (ret / 100 == 2) {
1020 download_in_progress = 1;
1021 bytes = extract_long(cret, 0);
1022 last_mod = extract_int(cret, 1);
1023 extract(mimetype, cret, 2);
1024 ret = CtdlIPCReadDownload(buf, bytes, cret);
1025 ret = CtdlIPCEndDownload(cret);
1027 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1028 filename, mimetype);
1035 int CtdlIPCAttachmentDownload(long msgnum, const char *part, void **buf,
1045 if (!cret) return -2;
1046 if (!buf) return -2;
1047 if (*buf) return -2;
1048 if (!part) return -2;
1049 if (!msgnum) return -2;
1050 if (download_in_progress) return -2;
1052 aaa = (char *)malloc(strlen(part) + 17);
1053 if (!aaa) return -1;
1055 sprintf(aaa, "OPNA %ld|%s", msgnum, part);
1056 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1058 /* FIXME: Possible race condition */
1059 if (ret / 100 == 2) {
1060 download_in_progress = 1;
1061 bytes = extract_long(cret, 0);
1062 last_mod = extract_int(cret, 1);
1063 extract(mimetype, cret, 2);
1064 ret = CtdlIPCReadDownload(buf, bytes, cret);
1065 ret = CtdlIPCEndDownload(cret);
1067 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1068 filename, mimetype);
1075 int CtdlIPCImageDownload(const char *filename, void **buf, char *cret)
1083 if (!cret) return -1;
1084 if (!buf) return -1;
1085 if (*buf) return -1;
1086 if (!filename) return -1;
1087 if (download_in_progress) return -1;
1089 aaa = (char *)malloc(strlen(filename) + 6);
1090 if (!aaa) return -1;
1092 sprintf(aaa, "OIMG %s", filename);
1093 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1095 /* FIXME: Possible race condition */
1096 if (ret / 100 == 2) {
1097 download_in_progress = 1;
1098 bytes = extract_long(cret, 0);
1099 last_mod = extract_int(cret, 1);
1100 extract(mimetype, cret, 2);
1101 ret = CtdlIPCReadDownload(buf, bytes, cret);
1102 ret = CtdlIPCEndDownload(cret);
1104 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1105 filename, mimetype);
1112 int CtdlIPCFileUpload(const char *filename, const char *comment, void *buf,
1113 size_t bytes, char *cret)
1118 if (!cret) return -1;
1119 if (!filename) return -1;
1120 if (!comment) return -1;
1121 if (upload_in_progress) return -1;
1123 aaa = (char *)malloc(strlen(filename) + strlen(comment) + 7);
1124 if (!aaa) return -1;
1126 sprintf(aaa, "UOPN %s|%s", filename, comment);
1127 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1129 /* FIXME: Possible race condition */
1131 upload_in_progress = 1;
1132 ret = CtdlIPCWriteUpload(buf, bytes, cret);
1133 ret = CtdlIPCEndUpload(cret);
1139 int CtdlIPCImageUpload(int for_real, const char *filename, size_t bytes,
1145 if (!cret) return -1;
1146 if (!filename) return -1;
1147 if (upload_in_progress) return -1;
1149 aaa = (char *)malloc(strlen(filename) + 17);
1150 if (!aaa) return -1;
1152 sprintf(aaa, "UIMG %d|%s", for_real, filename);
1153 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1155 /* FIXME: Possible race condition */
1157 upload_in_progress = 1;
1163 int CtdlIPCQueryUsername(const char *username, char *cret)
1168 if (!cret) return -2;
1169 if (!username) return -2;
1171 aaa = (char *)malloc(strlen(username) + 6);
1172 if (!aaa) return -1;
1174 sprintf(aaa, "QUSR %s", username);
1175 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1182 int CtdlIPCFloorListing(char **listing, char *cret)
1186 if (!cret) return -2;
1187 if (!listing) return -2;
1188 if (*listing) return -2;
1190 return CtdlIPCGenericCommand("LFLR", NULL, 0, listing, &bytes, cret);
1195 int CtdlIPCCreateFloor(int for_real, const char *name, char *cret)
1200 if (!cret) return -2;
1201 if (!name) return -2;
1203 aaa = (char *)malloc(strlen(name) + 17);
1204 if (!aaa) return -1;
1206 sprintf(aaa, "CFLR %s|%d", name, for_real);
1207 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1214 int CtdlIPCDeleteFloor(int for_real, int floornum, char *cret)
1218 if (!cret) return -1;
1219 if (floornum < 0) return -1;
1221 sprintf(aaa, "KFLR %d|%d", floornum, for_real);
1222 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1227 int CtdlIPCEditFloor(int floornum, const char *floorname, char *cret)
1232 if (!cret) return -2;
1233 if (!floorname) return -2;
1234 if (floornum < 0) return -2;
1236 aaa = (char *)malloc(strlen(floorname) + 17);
1237 if (!aaa) return -1;
1239 sprintf(aaa, "EFLR %d|%s", floornum, floorname);
1240 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1247 int CtdlIPCIdentifySoftware(int developerid, int clientid, int revision,
1248 const char *software_name, const char *hostname, char *cret)
1253 if (developerid < 0) return -2;
1254 if (clientid < 0) return -2;
1255 if (revision < 0) return -2;
1256 if (!software_name) return -2;
1257 if (!hostname) return -2;
1259 aaa = (char *)malloc(strlen(software_name) + strlen(hostname) + 29);
1260 if (!aaa) return -1;
1262 sprintf(aaa, "IDEN %d|%d|%d|%s|%s", developerid, clientid,
1263 revision, software_name, hostname);
1264 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1271 int CtdlIPCSendInstantMessage(const char *username, const char *text,
1277 if (!cret) return -2;
1278 if (!username) return -2;
1280 aaa = (char *)malloc(strlen(username) + 8);
1281 if (!aaa) return -1;
1284 sprintf(aaa, "SEXP %s|-", username);
1285 ret = CtdlIPCGenericCommand(aaa, text, strlen(text),
1288 sprintf(aaa, "SEXP %s||", username);
1289 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1297 int CtdlIPCGetInstantMessage(char **listing, char *cret)
1301 if (!cret) return -2;
1302 if (!listing) return -2;
1303 if (*listing) return -2;
1305 return CtdlIPCGenericCommand("GEXP", NULL, 0, listing, &bytes, cret);
1310 /* mode is 0 = enable, 1 = disable, 2 = status */
1311 int CtdlIPCEnableInstantMessageReceipt(int mode, char *cret)
1315 if (!cret) return -2;
1317 sprintf(aaa, "DEXP %d", mode);
1318 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1323 int CtdlIPCSetBio(char *bio, char *cret)
1325 if (!cret) return -2;
1326 if (!bio) return -2;
1328 return CtdlIPCGenericCommand("EBIO", bio, strlen(bio),
1334 int CtdlIPCGetBio(const char *username, char **listing, char *cret)
1340 if (!cret) return -2;
1341 if (!username) return -2;
1342 if (!listing) return -2;
1343 if (*listing) return -2;
1345 aaa = (char *)malloc(strlen(username) + 6);
1346 if (!aaa) return -1;
1348 sprintf(aaa, "RBIO %s", username);
1349 ret = CtdlIPCGenericCommand(aaa, NULL, 0, listing, &bytes, cret);
1356 int CtdlIPCListUsersWithBios(char **listing, char *cret)
1360 if (!cret) return -2;
1361 if (!listing) return -2;
1362 if (*listing) return -2;
1364 return CtdlIPCGenericCommand("LBIO", NULL, 0, listing, &bytes, cret);
1369 int CtdlIPCStealthMode(int mode, char *cret)
1373 if (!cret) return -1;
1375 sprintf(aaa, "STEL %d", mode ? 1 : 0);
1376 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1381 int CtdlIPCTerminateSession(int sid, char *cret)
1385 if (!cret) return -1;
1387 sprintf(aaa, "TERM %d", sid);
1388 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1393 int CtdlIPCTerminateServerNow(char *cret)
1395 if (!cret) return -1;
1397 return CtdlIPCGenericCommand("DOWN", NULL, 0, NULL, NULL, cret);
1402 int CtdlIPCTerminateServerScheduled(int mode, char *cret)
1406 if (!cret) return -1;
1408 sprintf(aaa, "SCDN %d", mode ? 1 : 0);
1409 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1414 int CtdlIPCEnterSystemMessage(const char *filename, const char *text,
1420 if (!cret) return -2;
1421 if (!text) return -2;
1422 if (!filename) return -2;
1424 aaa = (char *)malloc(strlen(filename) + 6);
1425 if (!aaa) return -1;
1427 sprintf(aaa, "EMSG %s", filename);
1428 ret = CtdlIPCGenericCommand(aaa, text, strlen(text), NULL, NULL, cret);
1435 int CtdlIPCChangeHostname(const char *hostname, char *cret)
1440 if (!cret) return -2;
1441 if (!hostname) return -2;
1443 aaa = (char *)malloc(strlen(hostname) + 6);
1444 if (!aaa) return -1;
1446 sprintf(aaa, "HCHG %s", hostname);
1447 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1454 int CtdlIPCChangeRoomname(const char *roomname, char *cret)
1459 if (!cret) return -2;
1460 if (!roomname) return -2;
1462 aaa = (char *)malloc(strlen(roomname) + 6);
1463 if (!aaa) return -1;
1465 sprintf(aaa, "RCHG %s", roomname);
1466 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1473 int CtdlIPCChangeUsername(const char *username, char *cret)
1478 if (!cret) return -2;
1479 if (!username) return -2;
1481 aaa = (char *)malloc(strlen(username) + 6);
1482 if (!aaa) return -1;
1484 sprintf(aaa, "UCHG %s", username);
1485 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1492 /* This function returns the actual server time reported, or 0 if error */
1493 time_t CtdlIPCServerTime(char *cret)
1495 register time_t tret;
1498 ret = CtdlIPCGenericCommand("TIME", NULL, 0, NULL, NULL, cret);
1499 if (ret / 100 == 2) {
1500 tret = extract_long(cret, 0);
1509 int CtdlIPCAideGetUserParameters(const char *who,
1510 struct usersupp **uret, char *cret)
1515 if (!cret) return -2;
1516 if (!uret) return -2;
1517 if (!*uret) *uret = (struct usersupp *)calloc(1, sizeof(struct usersupp));
1518 if (!*uret) return -1;
1520 aaa = (char *)malloc(strlen(uret[0]->fullname) + 6);
1521 if (!aaa) return -1;
1523 sprintf(aaa, "AGUP %s", who);
1524 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1525 if (ret / 100 == 2) {
1526 extract(uret[0]->fullname, cret, 0);
1527 extract(uret[0]->password, cret, 1);
1528 uret[0]->flags = extract_int(cret, 2);
1529 uret[0]->timescalled = extract_long(cret, 3);
1530 uret[0]->posted = extract_long(cret, 4);
1531 uret[0]->axlevel = extract_int(cret, 5);
1532 uret[0]->usernum = extract_long(cret, 6);
1533 uret[0]->lastcall = extract_long(cret, 7);
1534 uret[0]->USuserpurge = extract_int(cret, 8);
1542 int CtdlIPCAideSetUserParameters(const struct usersupp *uret, char *cret)
1547 if (!cret) return -2;
1548 if (!uret) return -2;
1550 aaa = (char *)malloc(strlen(uret->fullname) + strlen(uret->password) + 84);
1551 if (!aaa) return -1;
1553 sprintf(aaa, "ASUP %s|%s|%d|%ld|%ld|%d|%ld|%ld|%d",
1554 uret->fullname, uret->password, uret->flags,
1555 uret->timescalled, uret->posted, uret->axlevel,
1556 uret->usernum, uret->lastcall, uret->USuserpurge);
1557 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1564 /* which is 0 = room, 1 = floor, 2 = site */
1565 int CtdlIPCGetMessageExpirationPolicy(int which, char *cret)
1567 static char *proto[] = {"room", "floor", "site"};
1570 if (!cret) return -2;
1571 if (which < 0 || which > 2) return -2;
1573 sprintf(aaa, "GPEX %s", proto[which]);
1574 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1579 /* which is 0 = room, 1 = floor, 2 = site */
1580 /* policy is 0 = inherit, 1 = no purge, 2 = by count, 3 = by age (days) */
1581 int CtdlIPCSetMessageExpirationPolicy(int which, int policy, int value,
1586 if (!cret) return -2;
1587 if (which < 0 || which > 2) return -2;
1588 if (policy < 0 || policy > 3) return -2;
1589 if (policy >= 2 && value < 1) return -2;
1591 sprintf(aaa, "SPEX %d|%d|%d", which, policy, value);
1592 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1597 int CtdlGetSystemConfig(char **listing, char *cret)
1601 if (!cret) return -2;
1602 if (!listing) return -2;
1603 if (*listing) return -2;
1605 return CtdlIPCGenericCommand("CONF GET", NULL, 0,
1606 listing, &bytes, cret);
1611 int CtdlSetSystemConfig(const char *listing, char *cret)
1613 if (!cret) return -2;
1614 if (!listing) return -2;
1616 return CtdlIPCGenericCommand("CONF SET", listing, strlen(listing),
1622 int CtdlIPCModerateMessage(long msgnum, int level, char *cret)
1626 if (!cret) return -2;
1627 if (!msgnum) return -2;
1629 sprintf(aaa, "MMOD %ld|%d", msgnum, level);
1630 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1635 int CtdlIPCRequestClientLogout(int session, char *cret)
1639 if (!cret) return -2;
1640 if (session < 0) return -2;
1642 sprintf(aaa, "REQT %d", session);
1643 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1648 int CtdlIPCSetMessageSeen(long msgnum, int seen, char *cret)
1652 if (!cret) return -2;
1653 if (msgnum < 0) return -2;
1655 sprintf(aaa, "SEEN %ld|%d", msgnum, seen ? 1 : 0);
1656 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1661 int CtdlIPCStartEncryption(char *cret)
1663 return CtdlIPCGenericCommand("STLS", NULL, 0, NULL, NULL, cret);
1668 int CtdlIPCDirectoryLookup(const char *address, char *cret)
1672 if (!address) return -2;
1673 if (!cret) return -2;
1675 aaa = (char *)malloc(strlen(address) + 6);
1676 if (!aaa) return -1;
1678 sprintf(aaa, "QDIR %s", address);
1679 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1701 /* ************************************************************************** */
1702 /* Stuff below this line is not for public consumption */
1703 /* ************************************************************************** */
1706 inline void netio_lock(void)
1708 #ifdef THREADED_CLIENT
1709 pthread_mutex_lock(&rwlock);
1714 inline void netio_unlock(void)
1716 #ifdef THREADED_CLIENT
1717 pthread_mutex_unlock(&rwlock);
1722 /* Read a listing from the server up to 000. Append to dest if it exists */
1723 char *CtdlIPCReadListing(char *dest)
1730 if (ret) length = strlen(ret);
1731 while (serv_gets(aaa), strcmp(aaa, "000")) {
1732 ret = (char *)realloc(ret, length + strlen(aaa) + 2);
1734 strcpy(&ret[length], aaa);
1735 length += strlen(aaa);
1736 strcpy(&ret[length++], "\n");
1743 /* Send a listing to the server; generate the ending 000. */
1744 int CtdlIPCSendListing(const char *listing)
1748 text = (char *)malloc(strlen(listing) + 6);
1750 strcpy(text, listing);
1751 while (text[strlen(text) - 1] == '\n')
1752 text[strlen(text) - 1] = '\0';
1753 strcat(text, "\n000");
1758 /* Malloc failed but we are committed to send */
1759 /* This may result in extra blanks at the bottom */
1767 /* Partial read of file from server */
1768 size_t CtdlIPCPartialRead(void **buf, size_t offset, size_t bytes, char *cret)
1770 register size_t len = 0;
1773 if (!buf) return -1;
1774 if (!cret) return -1;
1775 if (bytes < 1) return -1;
1776 if (offset < 0) return -1;
1779 sprintf(aaa, "READ %d|%d", offset, bytes);
1783 strcpy(cret, &aaa[4]);
1785 len = extract_long(&aaa[4], 0);
1786 *buf = (void *)realloc(*buf, offset + len);
1788 /* I know what I'm doing */
1789 serv_read((char *)&buf[offset], len);
1791 /* We have to read regardless */
1792 serv_read(aaa, len);
1802 int CtdlIPCEndDownload(char *cret)
1806 if (!cret) return -2;
1807 if (!download_in_progress) return -2;
1809 ret = CtdlIPCGenericCommand("CLOS", NULL, 0, NULL, NULL, cret);
1811 download_in_progress = 0;
1817 int CtdlIPCReadDownload(void **buf, size_t bytes, char *cret)
1819 register size_t len;
1821 if (!cret) return -1;
1822 if (!buf) return -1;
1823 if (*buf) return -1;
1824 if (!download_in_progress) return -1;
1827 while (len < bytes) {
1828 len = CtdlIPCPartialRead(buf, len, 4096, cret);
1839 int CtdlIPCEndUpload(char *cret)
1843 if (!cret) return -1;
1844 if (!upload_in_progress) return -1;
1846 ret = CtdlIPCGenericCommand("UCLS", NULL, 0, NULL, NULL, cret);
1848 upload_in_progress = 0;
1854 int CtdlIPCWriteUpload(void *buf, size_t bytes, char *cret)
1856 register int ret = -1;
1857 register size_t offset;
1860 if (!cret) return -1;
1861 if (!buf) return -1;
1862 if (bytes < 1) return -1;
1865 while (offset < bytes) {
1866 sprintf(aaa, "WRIT %d", bytes - offset);
1869 strcpy(cret, &aaa[4]);
1871 if (aaa[0] == '7') {
1872 register size_t to_write;
1874 to_write = extract_long(&aaa[4], 0);
1875 serv_write(buf + offset, to_write);
1886 * Generic command method. This method should handle any server command
1887 * except for CHAT. It takes the following arguments:
1889 * command Preformatted command to send to server
1890 * to_send A text or binary file to send to server
1891 * (only sent if server requests it)
1892 * bytes_to_send The number of bytes in to_send (required if
1893 * sending binary, optional if sending listing)
1894 * to_receive Pointer to a NULL pointer, if the server
1895 * sends text or binary we will allocate memory
1896 * for the file and stuff it here
1897 * bytes_to_receive If a file is received, we will store its
1899 * proto_response The protocol response. Caller must provide
1900 * this buffer and ensure that it is at least
1901 * 128 bytes in length.
1903 * This function returns a number equal to the protocol response number,
1904 * -1 if an internal error occurred, -2 if caller provided bad values,
1905 * or 0 - the protocol response number if bad values were found during
1906 * the protocol exchange.
1907 * It stores the protocol response string (minus the number) in
1908 * protocol_response as described above. Some commands send additional
1909 * data in this string.
1911 int CtdlIPCGenericCommand(const char *command, const char *to_send,
1912 size_t bytes_to_send, char **to_receive,
1913 size_t *bytes_to_receive, char *proto_response)
1918 if (!command) return -2;
1919 if (!proto_response) return -2;
1922 serv_puts((char *)command);
1924 serv_gets(proto_response);
1925 if (proto_response[3] == '*')
1927 ret = atoi(proto_response);
1928 memmove(proto_response, &proto_response[4],
1929 strlen(proto_response) - 3);
1930 switch (ret / 100) {
1931 default: /* Unknown, punt */
1933 case 3: /* MORE_DATA */
1935 /* Don't need to do anything */
1937 case 1: /* LISTING_FOLLOWS */
1938 if (to_receive && !*to_receive && bytes_to_receive) {
1939 *to_receive = CtdlIPCReadListing(NULL);
1940 } else { /* Drain */
1941 while (serv_gets(buf), strcmp(buf, "000")) ;
1945 case 4: /* SEND_LISTING */
1947 CtdlIPCSendListing(to_send);
1949 /* No listing given, fake it */
1954 case 6: /* BINARY_FOLLOWS */
1955 if (to_receive && !*to_receive && bytes_to_receive) {
1957 extract_long(proto_response, 0);
1958 *to_receive = (char *)malloc(*bytes_to_receive);
1962 serv_read(*to_receive,
1969 drain = extract_long(proto_response, 0);
1970 while (drain > SIZ) {
1971 serv_read(buf, SIZ);
1974 serv_read(buf, drain);
1978 case 7: /* SEND_BINARY */
1979 if (to_send && bytes_to_send) {
1980 serv_write((char *)to_send, bytes_to_send);
1981 } else if (bytes_to_send) {
1982 /* Fake it, send nulls */
1985 fake = bytes_to_send;
1986 memset(buf, '\0', SIZ);
1987 while (fake > SIZ) {
1988 serv_write(buf, SIZ);
1991 serv_write(buf, fake);
1993 } /* else who knows? DANGER WILL ROBINSON */
1995 case 8: /* START_CHAT_MODE */
1996 if (!strncasecmp(command, "CHAT", 4)) {
1997 /* Don't call chatmode with generic! */
2001 /* In this mode we send then receive listing */
2003 CtdlIPCSendListing(to_send);
2005 /* No listing given, fake it */
2009 if (to_receive && !*to_receive
2010 && bytes_to_receive) {
2011 *to_receive = CtdlIPCReadListing(NULL);
2012 } else { /* Drain */
2013 while (serv_gets(buf),
2014 strcmp(buf, "000")) ;
2019 case 9: /* ASYNC_MSG */
2020 /* CtdlIPCDoAsync(ret, proto_response); */
2021 free(CtdlIPCReadListing(NULL)); /* STUB FIXME */