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((size_t)(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((size_t)(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((size_t)(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((size_t)(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((size_t)(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,
370 (size_t)((count + 1) * sizeof (long)));
372 *mret[count++] = atol(aaa);
380 int CtdlIPCGetSingleMessage(long msgnum, int headers, int as_mime,
381 struct ctdlipcmessage **mret, char *cret)
387 int multipart_hunting = 0;
388 char multipart_prefix[SIZ];
390 if (!cret) return -1;
391 if (!mret) return -1;
392 if (!*mret) *mret = (struct ctdlipcmessage *)calloc(1, sizeof (struct ctdlipcmessage));
393 if (!*mret) return -1;
394 if (!msgnum) return -1;
396 sprintf(aaa, "MSG%c %ld|%d", as_mime ? '2' : '0', msgnum, headers);
397 ret = CtdlIPCGenericCommand(aaa, NULL, 0, &bbb, &bbbsize, cret);
398 if (ret / 100 == 1) {
400 strcpy(mret[0]->mime_chosen, "1"); /* Default chosen-part is "1" */
401 while (strlen(bbb) > 4 && bbb[4] == '=') {
402 extract_token(aaa, bbb, 0, '\n');
403 remove_token(bbb, 0, '\n');
405 if (!strncasecmp(aaa, "nhdr=yes", 8))
407 else if (!strncasecmp(aaa, "from=", 5))
408 strcpy(mret[0]->author, &aaa[5]);
409 else if (!strncasecmp(aaa, "type=", 5))
410 mret[0]->type = atoi(&aaa[5]);
411 else if (!strncasecmp(aaa, "msgn=", 5))
412 strcpy(mret[0]->msgid, &aaa[5]);
413 else if (!strncasecmp(aaa, "subj=", 5))
414 strcpy(mret[0]->subject, &aaa[5]);
415 else if (!strncasecmp(aaa, "rfca=", 5))
416 strcpy(mret[0]->email, &aaa[5]);
417 else if (!strncasecmp(aaa, "hnod=", 5))
418 strcpy(mret[0]->hnod, &aaa[5]);
419 else if (!strncasecmp(aaa, "room=", 5))
420 strcpy(mret[0]->room, &aaa[5]);
421 else if (!strncasecmp(aaa, "node=", 5))
422 strcpy(mret[0]->node, &aaa[5]);
423 else if (!strncasecmp(aaa, "rcpt=", 5))
424 strcpy(mret[0]->recipient, &aaa[5]);
425 else if (!strncasecmp(aaa, "time=", 5))
426 mret[0]->time = atol(&aaa[5]);
428 /* Multipart/alternative prefix & suffix strings help
429 * us to determine which part we want to download.
431 else if (!strncasecmp(aaa, "pref=", 5)) {
432 extract(multipart_prefix, &aaa[5], 1);
433 if (!strcasecmp(multipart_prefix,
434 "multipart/alternative")) {
438 else if (!strncasecmp(aaa, "suff=", 5)) {
439 extract(multipart_prefix, &aaa[5], 1);
440 if (!strcasecmp(multipart_prefix,
441 "multipart/alternative")) {
446 else if (!strncasecmp(aaa, "part=", 5)) {
447 struct parts *ptr, *chain;
449 ptr = (struct parts *)calloc(1, sizeof (struct parts));
452 /* Fill the buffers for the caller */
453 extract(ptr->name, &aaa[5], 0);
454 extract(ptr->filename, &aaa[5], 1);
455 extract(ptr->number, &aaa[5], 2);
456 extract(ptr->disposition, &aaa[5], 3);
457 extract(ptr->mimetype, &aaa[5], 4);
458 ptr->length = extract_long(&aaa[5], 5);
459 if (!mret[0]->attachments)
460 mret[0]->attachments = ptr;
462 chain = mret[0]->attachments;
468 /* Now handle multipart/alternative */
469 if (multipart_hunting > 0) {
470 if ( (!strcasecmp(ptr->mimetype,
472 || (!strcasecmp(ptr->mimetype,
474 strcpy(mret[0]->mime_chosen,
482 /* Eliminate "text\n" */
483 remove_token(bbb, 0, '\n');
486 /* Strip trailing whitespace */
487 bbb = (char *)realloc(bbb, (size_t)(strlen(bbb) + 1));
489 bbb = (char *)realloc(bbb, 1);
499 int CtdlIPCWhoKnowsRoom(char **listing, char *cret)
504 if (!cret) return -2;
505 if (!listing) return -2;
506 if (*listing) return -2;
508 ret = CtdlIPCGenericCommand("WHOK", NULL, 0, listing, &bytes, cret);
514 int CtdlIPCServerInfo(struct CtdlServInfo *ServInfo, char *cret)
518 char *listing = NULL;
521 if (!cret) return -2;
522 if (!ServInfo) return -2;
524 ret = CtdlIPCGenericCommand("INFO", NULL, 0, &listing, &bytes, cret);
525 if (ret / 100 == 1) {
528 while (*listing && strlen(listing)) {
529 extract_token(buf, listing, 0, '\n');
530 remove_token(listing, 0, '\n');
532 case 0: ServInfo->serv_pid = atoi(buf);
534 case 1: strcpy(ServInfo->serv_nodename,buf);
536 case 2: strcpy(ServInfo->serv_humannode,buf);
538 case 3: strcpy(ServInfo->serv_fqdn,buf);
540 case 4: strcpy(ServInfo->serv_software,buf);
542 case 5: ServInfo->serv_rev_level = atoi(buf);
544 case 6: strcpy(ServInfo->serv_bbs_city,buf);
546 case 7: strcpy(ServInfo->serv_sysadm,buf);
548 case 9: strcpy(ServInfo->serv_moreprompt,buf);
550 case 10: ServInfo->serv_ok_floors = atoi(buf);
552 case 11: ServInfo->serv_paging_level = atoi(buf);
554 case 13: ServInfo->serv_supports_qnop = atoi(buf);
565 int CtdlIPCReadDirectory(char **listing, char *cret)
570 if (!cret) return -2;
571 if (!listing) return -2;
572 if (*listing) return -2;
574 ret = CtdlIPCGenericCommand("RDIR", NULL, 0, listing, &bytes, cret);
580 * Set last-read pointer in this room to msgnum, or 0 for HIGHEST.
582 int CtdlIPCSetLastRead(long msgnum, char *cret)
587 if (!cret) return -2;
590 sprintf(aaa, "SLRP %ld", msgnum);
592 sprintf(aaa, "SLRP HIGHEST");
593 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
599 int CtdlIPCInviteUserToRoom(const char *username, char *cret)
604 if (!cret) return -2;
605 if (!username) return -2;
607 aaa = (char *)malloc(strlen(username) + 6);
610 sprintf(aaa, "INVT %s", username);
611 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
618 int CtdlIPCKickoutUserFromRoom(const char *username, char *cret)
623 if (!cret) return -1;
624 if (!username) return -1;
626 aaa = (char *)malloc(strlen(username) + 6);
628 sprintf(aaa, "KICK %s", username);
629 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
636 int CtdlIPCGetRoomAttributes(struct quickroom **qret, char *cret)
640 if (!cret) return -2;
641 if (!qret) return -2;
642 if (!*qret) *qret = (struct quickroom *)calloc(1, sizeof (struct quickroom));
643 if (!*qret) return -1;
645 ret = CtdlIPCGenericCommand("GETR", NULL, 0, NULL, NULL, cret);
646 if (ret / 100 == 2) {
647 extract(qret[0]->QRname, cret, 0);
648 extract(qret[0]->QRpasswd, cret, 1);
649 extract(qret[0]->QRdirname, cret, 2);
650 qret[0]->QRflags = extract_int(cret, 3);
651 qret[0]->QRfloor = extract_int(cret, 4);
652 qret[0]->QRorder = extract_int(cret, 5);
659 /* set forget to kick all users out of room */
660 int CtdlIPCSetRoomAttributes(int forget, struct quickroom *qret, char *cret)
665 if (!cret) return -2;
666 if (!qret) return -2;
668 aaa = (char *)malloc(strlen(qret->QRname) + strlen(qret->QRpasswd) +
669 strlen(qret->QRdirname) + 52);
672 sprintf(aaa, "SETR %s|%s|%s|%d|%d|%d|%d",
673 qret->QRname, qret->QRpasswd, qret->QRdirname,
674 qret->QRflags, forget, qret->QRfloor, qret->QRorder);
675 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
682 int CtdlIPCGetRoomAide(char *cret)
684 if (!cret) return -1;
686 return CtdlIPCGenericCommand("GETA", NULL, 0, NULL, NULL, cret);
691 int CtdlIPCSetRoomAide(const char *username, char *cret)
696 if (!cret) return -2;
697 if (!username) return -2;
699 aaa = (char *)malloc(strlen(username) + 6);
702 sprintf(aaa, "SETA %s", username);
703 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
710 int CtdlIPCPostMessage(int flag, const struct ctdlipcmessage *mr, char *cret)
715 if (!cret) return -2;
718 aaa = (char *)malloc(strlen(mr->recipient) + strlen(mr->author) + 40);
721 sprintf(aaa, "ENT0 %d|%s|%d|%d|%s", flag, mr->recipient, mr->anonymous,
722 mr->type, mr->author);
723 ret = CtdlIPCGenericCommand(aaa, mr->text, strlen(mr->text), NULL,
731 int CtdlIPCRoomInfo(char **iret, char *cret)
735 if (!cret) return -2;
736 if (!iret) return -2;
737 if (*iret) return -2;
739 return CtdlIPCGenericCommand("RINF", NULL, 0, iret, &bytes, cret);
744 int CtdlIPCDeleteMessage(long msgnum, char *cret)
748 if (!cret) return -2;
749 if (!msgnum) return -2;
751 sprintf(aaa, "DELE %ld", msgnum);
752 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
757 int CtdlIPCMoveMessage(int copy, long msgnum, const char *destroom, char *cret)
762 if (!cret) return -2;
763 if (!destroom) return -2;
764 if (!msgnum) return -2;
766 aaa = (char *)malloc(strlen(destroom) + 28);
769 sprintf(aaa, "MOVE %ld|%s|%d", msgnum, destroom, copy);
770 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
777 int CtdlIPCDeleteRoom(int for_real, char *cret)
781 if (!cret) return -2;
783 sprintf(aaa, "KILL %d", for_real);
784 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
789 int CtdlIPCCreateRoom(int for_real, const char *roomname, int type,
790 const char *password, int floor, char *cret)
795 if (!cret) return -2;
796 if (!roomname) return -2;
799 aaa = (char *)malloc(strlen(roomname) + strlen(password) + 40);
801 sprintf(aaa, "CRE8 %d|%s|%d|%s|%d", for_real, roomname, type,
804 aaa = (char *)malloc(strlen(roomname) + 40);
806 sprintf(aaa, "CRE8 %d|%s|%d||%d", for_real, roomname, type,
809 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
816 int CtdlIPCForgetRoom(char *cret)
818 if (!cret) return -2;
820 return CtdlIPCGenericCommand("FORG", NULL, 0, NULL, NULL, cret);
825 int CtdlIPCSystemMessage(const char *message, char **mret, char *cret)
831 if (!cret) return -2;
832 if (!mret) return -2;
833 if (*mret) return -2;
834 if (!message) return -2;
836 aaa = (char *)malloc(strlen(message) + 6);
839 sprintf(aaa, "MESG %s", message);
840 ret = CtdlIPCGenericCommand(aaa, NULL, 0, mret, &bytes, cret);
847 int CtdlIPCNextUnvalidatedUser(char *cret)
849 if (!cret) return -2;
851 return CtdlIPCGenericCommand("GNUR", NULL, 0, NULL, NULL, cret);
856 int CtdlIPCGetUserRegistration(const char *username, char **rret, char *cret)
862 if (!cret) return -2;
863 if (!rret) return -2;
864 if (*rret) return -2;
867 aaa = (char *)malloc(strlen(username) + 6);
869 aaa = (char *)malloc(12);
873 sprintf(aaa, "GREG %s", username);
875 sprintf(aaa, "GREG _SELF_");
876 ret = CtdlIPCGenericCommand(aaa, NULL, 0, rret, &bytes, cret);
883 int CtdlIPCValidateUser(const char *username, int axlevel, char *cret)
888 if (!cret) return -2;
889 if (!username) return -2;
890 if (axlevel < 0 || axlevel > 7) return -2;
892 aaa = (char *)malloc(strlen(username) + 17);
895 sprintf(aaa, "VALI %s|%d", username, axlevel);
896 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
903 int CtdlIPCSetRoomInfo(int for_real, const char *info, char *cret)
907 if (!cret) return -1;
908 if (!info) return -1;
910 sprintf(aaa, "EINF %d", for_real);
911 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
916 int CtdlIPCUserListing(char **listing, char *cret)
920 if (!cret) return -1;
921 if (!listing) return -1;
922 if (*listing) return -1;
924 return CtdlIPCGenericCommand("LIST", NULL, 0, listing, &bytes, cret);
929 int CtdlIPCSetRegistration(const char *info, char *cret)
931 if (!cret) return -1;
932 if (!info) return -1;
934 return CtdlIPCGenericCommand("REGI", info, strlen(info),
940 int CtdlIPCMiscCheck(struct ctdlipcmisc *chek, char *cret)
944 if (!cret) return -1;
945 if (!chek) return -1;
947 ret = CtdlIPCGenericCommand("CHEK", NULL, 0, NULL, NULL, cret);
948 if (ret / 100 == 2) {
949 chek->newmail = extract_long(cret, 0);
950 chek->needregis = extract_int(cret, 1);
951 chek->needvalid = extract_int(cret, 2);
958 int CtdlIPCDeleteFile(const char *filename, char *cret)
963 if (!cret) return -2;
964 if (!filename) return -2;
966 aaa = (char *)malloc(strlen(filename) + 6);
969 sprintf(aaa, "DELF %s", filename);
970 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
977 int CtdlIPCMoveFile(const char *filename, const char *destroom, char *cret)
982 if (!cret) return -2;
983 if (!filename) return -2;
984 if (!destroom) return -2;
986 aaa = (char *)malloc(strlen(filename) + strlen(destroom) + 7);
989 sprintf(aaa, "MOVF %s|%s", filename, destroom);
990 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
997 int CtdlIPCNetSendFile(const char *filename, const char *destnode, char *cret)
1002 if (!cret) return -2;
1003 if (!filename) return -2;
1004 if (!destnode) return -2;
1006 aaa = (char *)malloc(strlen(filename) + strlen(destnode) + 7);
1007 if (!aaa) return -1;
1009 sprintf(aaa, "NETF %s|%s", filename, destnode);
1010 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1017 int CtdlIPCOnlineUsers(char **listing, time_t *stamp, char *cret)
1022 if (!cret) return -1;
1023 if (!listing) return -1;
1024 if (*listing) return -1;
1026 *stamp = CtdlIPCServerTime(cret);
1028 *stamp = time(NULL);
1029 ret = CtdlIPCGenericCommand("RWHO", NULL, 0, listing, &bytes, cret);
1035 int CtdlIPCFileDownload(const char *filename, void **buf, char *cret)
1043 if (!cret) return -2;
1044 if (!filename) return -2;
1045 if (!buf) return -2;
1046 if (*buf) return -2;
1047 if (download_in_progress) return -2;
1049 aaa = (char *)malloc(strlen(filename) + 6);
1050 if (!aaa) return -1;
1052 sprintf(aaa, "OPEN %s", filename);
1053 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1055 /* FIXME: Possible race condition */
1056 if (ret / 100 == 2) {
1057 download_in_progress = 1;
1058 bytes = extract_long(cret, 0);
1059 last_mod = extract_int(cret, 1);
1060 extract(mimetype, cret, 2);
1061 ret = CtdlIPCReadDownload(buf, bytes, cret);
1062 ret = CtdlIPCEndDownload(cret);
1064 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1065 filename, mimetype);
1072 int CtdlIPCAttachmentDownload(long msgnum, const char *part, void **buf,
1082 if (!cret) return -2;
1083 if (!buf) return -2;
1084 if (*buf) return -2;
1085 if (!part) return -2;
1086 if (!msgnum) return -2;
1087 if (download_in_progress) return -2;
1089 aaa = (char *)malloc(strlen(part) + 17);
1090 if (!aaa) return -1;
1092 sprintf(aaa, "OPNA %ld|%s", msgnum, part);
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 CtdlIPCImageDownload(const char *filename, void **buf, char *cret)
1120 if (!cret) return -1;
1121 if (!buf) return -1;
1122 if (*buf) return -1;
1123 if (!filename) return -1;
1124 if (download_in_progress) return -1;
1126 aaa = (char *)malloc(strlen(filename) + 6);
1127 if (!aaa) return -1;
1129 sprintf(aaa, "OIMG %s", filename);
1130 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1132 /* FIXME: Possible race condition */
1133 if (ret / 100 == 2) {
1134 download_in_progress = 1;
1135 bytes = extract_long(cret, 0);
1136 last_mod = extract_int(cret, 1);
1137 extract(mimetype, cret, 2);
1138 ret = CtdlIPCReadDownload(buf, bytes, cret);
1139 ret = CtdlIPCEndDownload(cret);
1141 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1142 filename, mimetype);
1149 int CtdlIPCFileUpload(const char *filename, const char *comment, void *buf,
1150 size_t bytes, char *cret)
1155 if (!cret) return -1;
1156 if (!filename) return -1;
1157 if (!comment) return -1;
1158 if (upload_in_progress) return -1;
1160 aaa = (char *)malloc(strlen(filename) + strlen(comment) + 7);
1161 if (!aaa) return -1;
1163 sprintf(aaa, "UOPN %s|%s", filename, comment);
1164 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1166 /* FIXME: Possible race condition */
1168 upload_in_progress = 1;
1169 ret = CtdlIPCWriteUpload(buf, bytes, cret);
1170 ret = CtdlIPCEndUpload(cret);
1176 int CtdlIPCImageUpload(int for_real, const char *filename, size_t bytes,
1182 if (!cret) return -1;
1183 if (!filename) return -1;
1184 if (upload_in_progress) return -1;
1186 aaa = (char *)malloc(strlen(filename) + 17);
1187 if (!aaa) return -1;
1189 sprintf(aaa, "UIMG %d|%s", for_real, filename);
1190 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1192 /* FIXME: Possible race condition */
1194 upload_in_progress = 1;
1200 int CtdlIPCQueryUsername(const char *username, char *cret)
1205 if (!cret) return -2;
1206 if (!username) return -2;
1208 aaa = (char *)malloc(strlen(username) + 6);
1209 if (!aaa) return -1;
1211 sprintf(aaa, "QUSR %s", username);
1212 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1219 int CtdlIPCFloorListing(char **listing, char *cret)
1223 if (!cret) return -2;
1224 if (!listing) return -2;
1225 if (*listing) return -2;
1227 return CtdlIPCGenericCommand("LFLR", NULL, 0, listing, &bytes, cret);
1232 int CtdlIPCCreateFloor(int for_real, const char *name, char *cret)
1237 if (!cret) return -2;
1238 if (!name) return -2;
1240 aaa = (char *)malloc(strlen(name) + 17);
1241 if (!aaa) return -1;
1243 sprintf(aaa, "CFLR %s|%d", name, for_real);
1244 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1251 int CtdlIPCDeleteFloor(int for_real, int floornum, char *cret)
1255 if (!cret) return -1;
1256 if (floornum < 0) return -1;
1258 sprintf(aaa, "KFLR %d|%d", floornum, for_real);
1259 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1264 int CtdlIPCEditFloor(int floornum, const char *floorname, char *cret)
1269 if (!cret) return -2;
1270 if (!floorname) return -2;
1271 if (floornum < 0) return -2;
1273 aaa = (char *)malloc(strlen(floorname) + 17);
1274 if (!aaa) return -1;
1276 sprintf(aaa, "EFLR %d|%s", floornum, floorname);
1277 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1284 int CtdlIPCIdentifySoftware(int developerid, int clientid, int revision,
1285 const char *software_name, const char *hostname, char *cret)
1290 if (developerid < 0) return -2;
1291 if (clientid < 0) return -2;
1292 if (revision < 0) return -2;
1293 if (!software_name) return -2;
1294 if (!hostname) return -2;
1296 aaa = (char *)malloc(strlen(software_name) + strlen(hostname) + 29);
1297 if (!aaa) return -1;
1299 sprintf(aaa, "IDEN %d|%d|%d|%s|%s", developerid, clientid,
1300 revision, software_name, hostname);
1301 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1308 int CtdlIPCSendInstantMessage(const char *username, const char *text,
1314 if (!cret) return -2;
1315 if (!username) return -2;
1317 aaa = (char *)malloc(strlen(username) + 8);
1318 if (!aaa) return -1;
1321 sprintf(aaa, "SEXP %s|-", username);
1322 ret = CtdlIPCGenericCommand(aaa, text, strlen(text),
1325 sprintf(aaa, "SEXP %s||", username);
1326 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1334 int CtdlIPCGetInstantMessage(char **listing, char *cret)
1338 if (!cret) return -2;
1339 if (!listing) return -2;
1340 if (*listing) return -2;
1342 return CtdlIPCGenericCommand("GEXP", NULL, 0, listing, &bytes, cret);
1347 /* mode is 0 = enable, 1 = disable, 2 = status */
1348 int CtdlIPCEnableInstantMessageReceipt(int mode, char *cret)
1352 if (!cret) return -2;
1354 sprintf(aaa, "DEXP %d", mode);
1355 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1360 int CtdlIPCSetBio(char *bio, char *cret)
1362 if (!cret) return -2;
1363 if (!bio) return -2;
1365 return CtdlIPCGenericCommand("EBIO", bio, strlen(bio),
1371 int CtdlIPCGetBio(const char *username, char **listing, char *cret)
1377 if (!cret) return -2;
1378 if (!username) return -2;
1379 if (!listing) return -2;
1380 if (*listing) return -2;
1382 aaa = (char *)malloc(strlen(username) + 6);
1383 if (!aaa) return -1;
1385 sprintf(aaa, "RBIO %s", username);
1386 ret = CtdlIPCGenericCommand(aaa, NULL, 0, listing, &bytes, cret);
1393 int CtdlIPCListUsersWithBios(char **listing, char *cret)
1397 if (!cret) return -2;
1398 if (!listing) return -2;
1399 if (*listing) return -2;
1401 return CtdlIPCGenericCommand("LBIO", NULL, 0, listing, &bytes, cret);
1406 int CtdlIPCStealthMode(int mode, char *cret)
1410 if (!cret) return -1;
1412 sprintf(aaa, "STEL %d", mode ? 1 : 0);
1413 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1418 int CtdlIPCTerminateSession(int sid, char *cret)
1422 if (!cret) return -1;
1424 sprintf(aaa, "TERM %d", sid);
1425 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1430 int CtdlIPCTerminateServerNow(char *cret)
1432 if (!cret) return -1;
1434 return CtdlIPCGenericCommand("DOWN", NULL, 0, NULL, NULL, cret);
1439 int CtdlIPCTerminateServerScheduled(int mode, char *cret)
1443 if (!cret) return -1;
1445 sprintf(aaa, "SCDN %d", mode ? 1 : 0);
1446 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1451 int CtdlIPCEnterSystemMessage(const char *filename, const char *text,
1457 if (!cret) return -2;
1458 if (!text) return -2;
1459 if (!filename) return -2;
1461 aaa = (char *)malloc(strlen(filename) + 6);
1462 if (!aaa) return -1;
1464 sprintf(aaa, "EMSG %s", filename);
1465 ret = CtdlIPCGenericCommand(aaa, text, strlen(text), NULL, NULL, cret);
1472 int CtdlIPCChangeHostname(const char *hostname, char *cret)
1477 if (!cret) return -2;
1478 if (!hostname) return -2;
1480 aaa = (char *)malloc(strlen(hostname) + 6);
1481 if (!aaa) return -1;
1483 sprintf(aaa, "HCHG %s", hostname);
1484 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1491 int CtdlIPCChangeRoomname(const char *roomname, char *cret)
1496 if (!cret) return -2;
1497 if (!roomname) return -2;
1499 aaa = (char *)malloc(strlen(roomname) + 6);
1500 if (!aaa) return -1;
1502 sprintf(aaa, "RCHG %s", roomname);
1503 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1510 int CtdlIPCChangeUsername(const char *username, char *cret)
1515 if (!cret) return -2;
1516 if (!username) return -2;
1518 aaa = (char *)malloc(strlen(username) + 6);
1519 if (!aaa) return -1;
1521 sprintf(aaa, "UCHG %s", username);
1522 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1529 /* This function returns the actual server time reported, or 0 if error */
1530 time_t CtdlIPCServerTime(char *cret)
1532 register time_t tret;
1535 ret = CtdlIPCGenericCommand("TIME", NULL, 0, NULL, NULL, cret);
1536 if (ret / 100 == 2) {
1537 tret = extract_long(cret, 0);
1546 int CtdlIPCAideGetUserParameters(const char *who,
1547 struct usersupp **uret, char *cret)
1552 if (!cret) return -2;
1553 if (!uret) return -2;
1554 if (!*uret) *uret = (struct usersupp *)calloc(1, sizeof(struct usersupp));
1555 if (!*uret) return -1;
1557 aaa = (char *)malloc(strlen(uret[0]->fullname) + 6);
1558 if (!aaa) return -1;
1560 sprintf(aaa, "AGUP %s", who);
1561 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1562 if (ret / 100 == 2) {
1563 extract(uret[0]->fullname, cret, 0);
1564 extract(uret[0]->password, cret, 1);
1565 uret[0]->flags = extract_int(cret, 2);
1566 uret[0]->timescalled = extract_long(cret, 3);
1567 uret[0]->posted = extract_long(cret, 4);
1568 uret[0]->axlevel = extract_int(cret, 5);
1569 uret[0]->usernum = extract_long(cret, 6);
1570 uret[0]->lastcall = extract_long(cret, 7);
1571 uret[0]->USuserpurge = extract_int(cret, 8);
1579 int CtdlIPCAideSetUserParameters(const struct usersupp *uret, char *cret)
1584 if (!cret) return -2;
1585 if (!uret) return -2;
1587 aaa = (char *)malloc(strlen(uret->fullname) + strlen(uret->password) + 84);
1588 if (!aaa) return -1;
1590 sprintf(aaa, "ASUP %s|%s|%d|%ld|%ld|%d|%ld|%ld|%d",
1591 uret->fullname, uret->password, uret->flags,
1592 uret->timescalled, uret->posted, uret->axlevel,
1593 uret->usernum, uret->lastcall, uret->USuserpurge);
1594 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1601 /* which is 0 = room, 1 = floor, 2 = site */
1602 int CtdlIPCGetMessageExpirationPolicy(int which, char *cret)
1604 static char *proto[] = {"room", "floor", "site"};
1607 if (!cret) return -2;
1608 if (which < 0 || which > 2) return -2;
1610 sprintf(aaa, "GPEX %s", proto[which]);
1611 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1616 /* which is 0 = room, 1 = floor, 2 = site */
1617 /* policy is 0 = inherit, 1 = no purge, 2 = by count, 3 = by age (days) */
1618 int CtdlIPCSetMessageExpirationPolicy(int which, int policy, int value,
1623 if (!cret) return -2;
1624 if (which < 0 || which > 2) return -2;
1625 if (policy < 0 || policy > 3) return -2;
1626 if (policy >= 2 && value < 1) return -2;
1628 sprintf(aaa, "SPEX %d|%d|%d", which, policy, value);
1629 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1634 int CtdlGetSystemConfig(char **listing, char *cret)
1638 if (!cret) return -2;
1639 if (!listing) return -2;
1640 if (*listing) return -2;
1642 return CtdlIPCGenericCommand("CONF GET", NULL, 0,
1643 listing, &bytes, cret);
1648 int CtdlSetSystemConfig(const char *listing, char *cret)
1650 if (!cret) return -2;
1651 if (!listing) return -2;
1653 return CtdlIPCGenericCommand("CONF SET", listing, strlen(listing),
1659 int CtdlIPCModerateMessage(long msgnum, int level, char *cret)
1663 if (!cret) return -2;
1664 if (!msgnum) return -2;
1666 sprintf(aaa, "MMOD %ld|%d", msgnum, level);
1667 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1672 int CtdlIPCRequestClientLogout(int session, char *cret)
1676 if (!cret) return -2;
1677 if (session < 0) return -2;
1679 sprintf(aaa, "REQT %d", session);
1680 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1685 int CtdlIPCSetMessageSeen(long msgnum, int seen, char *cret)
1689 if (!cret) return -2;
1690 if (msgnum < 0) return -2;
1692 sprintf(aaa, "SEEN %ld|%d", msgnum, seen ? 1 : 0);
1693 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1698 int CtdlIPCStartEncryption(char *cret)
1700 return CtdlIPCGenericCommand("STLS", NULL, 0, NULL, NULL, cret);
1705 int CtdlIPCDirectoryLookup(const char *address, char *cret)
1709 if (!address) return -2;
1710 if (!cret) return -2;
1712 aaa = (char *)malloc(strlen(address) + 6);
1713 if (!aaa) return -1;
1715 sprintf(aaa, "QDIR %s", address);
1716 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1738 /* ************************************************************************** */
1739 /* Stuff below this line is not for public consumption */
1740 /* ************************************************************************** */
1743 inline void netio_lock(void)
1745 #ifdef THREADED_CLIENT
1746 pthread_mutex_lock(&rwlock);
1751 inline void netio_unlock(void)
1753 #ifdef THREADED_CLIENT
1754 pthread_mutex_unlock(&rwlock);
1759 /* Read a listing from the server up to 000. Append to dest if it exists */
1760 char *CtdlIPCReadListing(char *dest)
1769 length = strlen(ret);
1776 while (serv_gets(aaa), strcmp(aaa, "000")) {
1777 linelength = strlen(aaa);
1778 ret = (char *)realloc(ret, (size_t)(length + linelength + 2));
1780 strcpy(&ret[length], aaa);
1781 length += linelength;
1782 strcpy(&ret[length++], "\n");
1790 /* Send a listing to the server; generate the ending 000. */
1791 int CtdlIPCSendListing(const char *listing)
1795 text = (char *)malloc(strlen(listing) + 6);
1797 strcpy(text, listing);
1798 while (text[strlen(text) - 1] == '\n')
1799 text[strlen(text) - 1] = '\0';
1800 strcat(text, "\n000");
1805 /* Malloc failed but we are committed to send */
1806 /* This may result in extra blanks at the bottom */
1814 /* Partial read of file from server */
1815 size_t CtdlIPCPartialRead(void **buf, size_t offset, size_t bytes, char *cret)
1817 register size_t len = 0;
1820 if (!buf) return -1;
1821 if (!cret) return -1;
1822 if (bytes < 1) return -1;
1823 if (offset < 0) return -1;
1826 sprintf(aaa, "READ %d|%d", offset, bytes);
1830 strcpy(cret, &aaa[4]);
1832 len = extract_long(&aaa[4], 0);
1833 *buf = (void *)realloc(*buf, (size_t)(offset + len));
1835 /* I know what I'm doing */
1836 serv_read((char *)&buf[offset], len);
1838 /* We have to read regardless */
1839 serv_read(aaa, len);
1849 int CtdlIPCEndDownload(char *cret)
1853 if (!cret) return -2;
1854 if (!download_in_progress) return -2;
1856 ret = CtdlIPCGenericCommand("CLOS", NULL, 0, NULL, NULL, cret);
1858 download_in_progress = 0;
1864 int CtdlIPCReadDownload(void **buf, size_t bytes, char *cret)
1866 register size_t len;
1868 if (!cret) return -1;
1869 if (!buf) return -1;
1870 if (*buf) return -1;
1871 if (!download_in_progress) return -1;
1874 while (len < bytes) {
1875 len = CtdlIPCPartialRead(buf, len, 4096, cret);
1886 int CtdlIPCEndUpload(char *cret)
1890 if (!cret) return -1;
1891 if (!upload_in_progress) return -1;
1893 ret = CtdlIPCGenericCommand("UCLS", NULL, 0, NULL, NULL, cret);
1895 upload_in_progress = 0;
1901 int CtdlIPCWriteUpload(void *buf, size_t bytes, char *cret)
1903 register int ret = -1;
1904 register size_t offset;
1907 if (!cret) return -1;
1908 if (!buf) return -1;
1909 if (bytes < 1) return -1;
1912 while (offset < bytes) {
1913 sprintf(aaa, "WRIT %d", bytes - offset);
1916 strcpy(cret, &aaa[4]);
1918 if (aaa[0] == '7') {
1919 register size_t to_write;
1921 to_write = extract_long(&aaa[4], 0);
1922 serv_write(buf + offset, to_write);
1933 * Generic command method. This method should handle any server command
1934 * except for CHAT. It takes the following arguments:
1936 * command Preformatted command to send to server
1937 * to_send A text or binary file to send to server
1938 * (only sent if server requests it)
1939 * bytes_to_send The number of bytes in to_send (required if
1940 * sending binary, optional if sending listing)
1941 * to_receive Pointer to a NULL pointer, if the server
1942 * sends text or binary we will allocate memory
1943 * for the file and stuff it here
1944 * bytes_to_receive If a file is received, we will store its
1946 * proto_response The protocol response. Caller must provide
1947 * this buffer and ensure that it is at least
1948 * 128 bytes in length.
1950 * This function returns a number equal to the protocol response number,
1951 * -1 if an internal error occurred, -2 if caller provided bad values,
1952 * or 0 - the protocol response number if bad values were found during
1953 * the protocol exchange.
1954 * It stores the protocol response string (minus the number) in
1955 * protocol_response as described above. Some commands send additional
1956 * data in this string.
1958 int CtdlIPCGenericCommand(const char *command, const char *to_send,
1959 size_t bytes_to_send, char **to_receive,
1960 size_t *bytes_to_receive, char *proto_response)
1965 if (!command) return -2;
1966 if (!proto_response) return -2;
1969 serv_puts((char *)command);
1971 serv_gets(proto_response);
1972 if (proto_response[3] == '*')
1974 ret = atoi(proto_response);
1975 memmove(proto_response, &proto_response[4],
1976 strlen(proto_response) - 3);
1977 switch (ret / 100) {
1978 default: /* Unknown, punt */
1980 case 3: /* MORE_DATA */
1982 /* Don't need to do anything */
1984 case 1: /* LISTING_FOLLOWS */
1985 if (to_receive && !*to_receive && bytes_to_receive) {
1986 *to_receive = CtdlIPCReadListing(NULL);
1987 } else { /* Drain */
1988 while (serv_gets(buf), strcmp(buf, "000")) ;
1992 case 4: /* SEND_LISTING */
1994 CtdlIPCSendListing(to_send);
1996 /* No listing given, fake it */
2001 case 6: /* BINARY_FOLLOWS */
2002 if (to_receive && !*to_receive && bytes_to_receive) {
2004 extract_long(proto_response, 0);
2005 *to_receive = (char *)malloc(*bytes_to_receive);
2009 serv_read(*to_receive,
2016 drain = extract_long(proto_response, 0);
2017 while (drain > SIZ) {
2018 serv_read(buf, SIZ);
2021 serv_read(buf, drain);
2025 case 7: /* SEND_BINARY */
2026 if (to_send && bytes_to_send) {
2027 serv_write((char *)to_send, bytes_to_send);
2028 } else if (bytes_to_send) {
2029 /* Fake it, send nulls */
2032 fake = bytes_to_send;
2033 memset(buf, '\0', SIZ);
2034 while (fake > SIZ) {
2035 serv_write(buf, SIZ);
2038 serv_write(buf, fake);
2040 } /* else who knows? DANGER WILL ROBINSON */
2042 case 8: /* START_CHAT_MODE */
2043 if (!strncasecmp(command, "CHAT", 4)) {
2044 /* Don't call chatmode with generic! */
2048 /* In this mode we send then receive listing */
2050 CtdlIPCSendListing(to_send);
2052 /* No listing given, fake it */
2056 if (to_receive && !*to_receive
2057 && bytes_to_receive) {
2058 *to_receive = CtdlIPCReadListing(NULL);
2059 } else { /* Drain */
2060 while (serv_gets(buf),
2061 strcmp(buf, "000")) ;
2066 case 9: /* ASYNC_MSG */
2067 /* CtdlIPCDoAsync(ret, proto_response); */
2068 free(CtdlIPCReadListing(NULL)); /* STUB FIXME */