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);
461 int CtdlIPCWhoKnowsRoom(char **listing, char *cret)
466 if (!cret) return -2;
467 if (!listing) return -2;
468 if (*listing) return -2;
470 ret = CtdlIPCGenericCommand("WHOK", NULL, 0, listing, &bytes, cret);
476 int CtdlIPCServerInfo(struct CtdlServInfo *ServInfo, char *cret)
480 char *listing = NULL;
483 if (!cret) return -2;
484 if (!ServInfo) return -2;
486 ret = CtdlIPCGenericCommand("INFO", NULL, 0, &listing, &bytes, cret);
487 if (ret / 100 == 1) {
490 while (*listing && strlen(listing)) {
491 extract_token(buf, listing, 0, '\n');
492 remove_token(listing, 0, '\n');
494 case 0: ServInfo->serv_pid = atoi(buf);
496 case 1: strcpy(ServInfo->serv_nodename,buf);
498 case 2: strcpy(ServInfo->serv_humannode,buf);
500 case 3: strcpy(ServInfo->serv_fqdn,buf);
502 case 4: strcpy(ServInfo->serv_software,buf);
504 case 5: ServInfo->serv_rev_level = atoi(buf);
506 case 6: strcpy(ServInfo->serv_bbs_city,buf);
508 case 7: strcpy(ServInfo->serv_sysadm,buf);
510 case 9: strcpy(ServInfo->serv_moreprompt,buf);
512 case 10: ServInfo->serv_ok_floors = atoi(buf);
514 case 11: ServInfo->serv_paging_level = atoi(buf);
516 case 13: ServInfo->serv_supports_qnop = atoi(buf);
527 int CtdlIPCReadDirectory(char **listing, char *cret)
532 if (!cret) return -2;
533 if (!listing) return -2;
534 if (*listing) return -2;
536 ret = CtdlIPCGenericCommand("RDIR", NULL, 0, listing, &bytes, cret);
542 * Set last-read pointer in this room to msgnum, or 0 for HIGHEST.
544 int CtdlIPCSetLastRead(long msgnum, char *cret)
549 if (!cret) return -2;
552 sprintf(aaa, "SLRP %ld", msgnum);
554 sprintf(aaa, "SLRP HIGHEST");
555 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
561 int CtdlIPCInviteUserToRoom(const char *username, char *cret)
566 if (!cret) return -2;
567 if (!username) return -2;
569 aaa = (char *)malloc(strlen(username) + 6);
572 sprintf(aaa, "INVT %s", username);
573 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
580 int CtdlIPCKickoutUserFromRoom(const char *username, char *cret)
585 if (!cret) return -1;
586 if (!username) return -1;
588 aaa = (char *)malloc(strlen(username) + 6);
590 sprintf(aaa, "KICK %s", username);
591 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
598 int CtdlIPCGetRoomAttributes(struct quickroom **qret, char *cret)
602 if (!cret) return -2;
603 if (!qret) return -2;
604 if (!*qret) *qret = (struct quickroom *)calloc(1, sizeof (struct quickroom));
605 if (!*qret) return -1;
607 ret = CtdlIPCGenericCommand("GETR", NULL, 0, NULL, NULL, cret);
608 if (ret / 100 == 2) {
609 extract(qret[0]->QRname, cret, 0);
610 extract(qret[0]->QRpasswd, cret, 1);
611 extract(qret[0]->QRdirname, cret, 2);
612 qret[0]->QRflags = extract_int(cret, 3);
613 qret[0]->QRfloor = extract_int(cret, 4);
614 qret[0]->QRorder = extract_int(cret, 5);
621 /* set forget to kick all users out of room */
622 int CtdlIPCSetRoomAttributes(int forget, struct quickroom *qret, char *cret)
627 if (!cret) return -2;
628 if (!qret) return -2;
630 aaa = (char *)malloc(strlen(qret->QRname) + strlen(qret->QRpasswd) +
631 strlen(qret->QRdirname) + 52);
634 sprintf(aaa, "SETR %s|%s|%s|%d|%d|%d|%d",
635 qret->QRname, qret->QRpasswd, qret->QRdirname,
636 qret->QRflags, forget, qret->QRfloor, qret->QRorder);
637 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
644 int CtdlIPCGetRoomAide(char *cret)
646 if (!cret) return -1;
648 return CtdlIPCGenericCommand("GETA", NULL, 0, NULL, NULL, cret);
653 int CtdlIPCSetRoomAide(const char *username, char *cret)
658 if (!cret) return -2;
659 if (!username) return -2;
661 aaa = (char *)malloc(strlen(username) + 6);
664 sprintf(aaa, "SETA %s", username);
665 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
672 int CtdlIPCPostMessage(int flag, const struct ctdlipcmessage *mr, char *cret)
677 if (!cret) return -2;
680 aaa = (char *)malloc(strlen(mr->recipient) + strlen(mr->author) + 40);
683 sprintf(aaa, "ENT0 %d|%s|%d|%d|%s", flag, mr->recipient, mr->anonymous,
684 mr->type, mr->author);
685 ret = CtdlIPCGenericCommand(aaa, mr->text, strlen(mr->text), NULL,
693 int CtdlIPCRoomInfo(char **iret, char *cret)
697 if (!cret) return -2;
698 if (!iret) return -2;
699 if (*iret) return -2;
701 return CtdlIPCGenericCommand("RINF", NULL, 0, iret, &bytes, cret);
706 int CtdlIPCDeleteMessage(long msgnum, char *cret)
710 if (!cret) return -2;
711 if (!msgnum) return -2;
713 sprintf(aaa, "DELE %ld", msgnum);
714 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
719 int CtdlIPCMoveMessage(int copy, long msgnum, const char *destroom, char *cret)
724 if (!cret) return -2;
725 if (!destroom) return -2;
726 if (!msgnum) return -2;
728 aaa = (char *)malloc(strlen(destroom) + 28);
731 sprintf(aaa, "MOVE %ld|%s|%d", msgnum, destroom, copy);
732 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
739 int CtdlIPCDeleteRoom(int for_real, char *cret)
743 if (!cret) return -2;
745 sprintf(aaa, "KILL %d", for_real);
746 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
751 int CtdlIPCCreateRoom(int for_real, const char *roomname, int type,
752 const char *password, int floor, char *cret)
757 if (!cret) return -2;
758 if (!roomname) return -2;
761 aaa = (char *)malloc(strlen(roomname) + strlen(password) + 40);
763 sprintf(aaa, "CRE8 %d|%s|%d|%s|%d", for_real, roomname, type,
766 aaa = (char *)malloc(strlen(roomname) + 40);
768 sprintf(aaa, "CRE8 %d|%s|%d||%d", for_real, roomname, type,
771 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
778 int CtdlIPCForgetRoom(char *cret)
780 if (!cret) return -2;
782 return CtdlIPCGenericCommand("FORG", NULL, 0, NULL, NULL, cret);
787 int CtdlIPCSystemMessage(const char *message, char **mret, char *cret)
793 if (!cret) return -2;
794 if (!mret) return -2;
795 if (*mret) return -2;
796 if (!message) return -2;
798 aaa = (char *)malloc(strlen(message) + 6);
801 sprintf(aaa, "MESG %s", message);
802 ret = CtdlIPCGenericCommand(aaa, NULL, 0, mret, &bytes, cret);
809 int CtdlIPCNextUnvalidatedUser(char *cret)
811 if (!cret) return -2;
813 return CtdlIPCGenericCommand("GNUR", NULL, 0, NULL, NULL, cret);
818 int CtdlIPCGetUserRegistration(const char *username, char **rret, char *cret)
824 if (!cret) return -2;
825 if (!rret) return -2;
826 if (*rret) return -2;
829 aaa = (char *)malloc(strlen(username) + 6);
831 aaa = (char *)malloc(12);
835 sprintf(aaa, "GREG %s", username);
837 sprintf(aaa, "GREG _SELF_");
838 ret = CtdlIPCGenericCommand(aaa, NULL, 0, rret, &bytes, cret);
845 int CtdlIPCValidateUser(const char *username, int axlevel, char *cret)
850 if (!cret) return -2;
851 if (!username) return -2;
852 if (axlevel < 0 || axlevel > 7) return -2;
854 aaa = (char *)malloc(strlen(username) + 17);
857 sprintf(aaa, "VALI %s|%d", username, axlevel);
858 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
865 int CtdlIPCSetRoomInfo(int for_real, const char *info, char *cret)
869 if (!cret) return -1;
870 if (!info) return -1;
872 sprintf(aaa, "EINF %d", for_real);
873 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
878 int CtdlIPCUserListing(char **listing, char *cret)
882 if (!cret) return -1;
883 if (!listing) return -1;
884 if (*listing) return -1;
886 return CtdlIPCGenericCommand("LIST", NULL, 0, listing, &bytes, cret);
891 int CtdlIPCSetRegistration(const char *info, char *cret)
893 if (!cret) return -1;
894 if (!info) return -1;
896 return CtdlIPCGenericCommand("REGI", info, strlen(info),
902 int CtdlIPCMiscCheck(struct ctdlipcmisc *chek, char *cret)
906 if (!cret) return -1;
907 if (!chek) return -1;
909 ret = CtdlIPCGenericCommand("CHEK", NULL, 0, NULL, NULL, cret);
910 if (ret / 100 == 2) {
911 chek->newmail = extract_long(cret, 0);
912 chek->needregis = extract_int(cret, 1);
913 chek->needvalid = extract_int(cret, 2);
920 int CtdlIPCDeleteFile(const char *filename, char *cret)
925 if (!cret) return -2;
926 if (!filename) return -2;
928 aaa = (char *)malloc(strlen(filename) + 6);
931 sprintf(aaa, "DELF %s", filename);
932 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
939 int CtdlIPCMoveFile(const char *filename, const char *destroom, char *cret)
944 if (!cret) return -2;
945 if (!filename) return -2;
946 if (!destroom) return -2;
948 aaa = (char *)malloc(strlen(filename) + strlen(destroom) + 7);
951 sprintf(aaa, "MOVF %s|%s", filename, destroom);
952 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
959 int CtdlIPCNetSendFile(const char *filename, const char *destnode, char *cret)
964 if (!cret) return -2;
965 if (!filename) return -2;
966 if (!destnode) return -2;
968 aaa = (char *)malloc(strlen(filename) + strlen(destnode) + 7);
971 sprintf(aaa, "NETF %s|%s", filename, destnode);
972 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
979 int CtdlIPCOnlineUsers(char **listing, time_t *stamp, char *cret)
984 if (!cret) return -1;
985 if (!listing) return -1;
986 if (*listing) return -1;
988 *stamp = CtdlIPCServerTime(cret);
991 ret = CtdlIPCGenericCommand("RWHO", NULL, 0, listing, &bytes, cret);
997 int CtdlIPCFileDownload(const char *filename, void **buf, char *cret)
1005 if (!cret) return -2;
1006 if (!filename) return -2;
1007 if (!buf) return -2;
1008 if (*buf) return -2;
1009 if (download_in_progress) return -2;
1011 aaa = (char *)malloc(strlen(filename) + 6);
1012 if (!aaa) return -1;
1014 sprintf(aaa, "OPEN %s", filename);
1015 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1017 /* FIXME: Possible race condition */
1018 if (ret / 100 == 2) {
1019 download_in_progress = 1;
1020 bytes = extract_long(cret, 0);
1021 last_mod = extract_int(cret, 1);
1022 extract(mimetype, cret, 2);
1023 ret = CtdlIPCReadDownload(buf, bytes, cret);
1024 ret = CtdlIPCEndDownload(cret);
1026 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1027 filename, mimetype);
1034 int CtdlIPCAttachmentDownload(long msgnum, const char *part, void **buf,
1044 if (!cret) return -2;
1045 if (!buf) return -2;
1046 if (*buf) return -2;
1047 if (!part) return -2;
1048 if (!msgnum) return -2;
1049 if (download_in_progress) return -2;
1051 aaa = (char *)malloc(strlen(part) + 17);
1052 if (!aaa) return -1;
1054 sprintf(aaa, "OPNA %ld|%s", msgnum, part);
1055 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1057 /* FIXME: Possible race condition */
1058 if (ret / 100 == 2) {
1059 download_in_progress = 1;
1060 bytes = extract_long(cret, 0);
1061 last_mod = extract_int(cret, 1);
1062 extract(mimetype, cret, 2);
1063 ret = CtdlIPCReadDownload(buf, bytes, cret);
1064 ret = CtdlIPCEndDownload(cret);
1066 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1067 filename, mimetype);
1074 int CtdlIPCImageDownload(const char *filename, void **buf, char *cret)
1082 if (!cret) return -1;
1083 if (!buf) return -1;
1084 if (*buf) return -1;
1085 if (!filename) return -1;
1086 if (download_in_progress) return -1;
1088 aaa = (char *)malloc(strlen(filename) + 6);
1089 if (!aaa) return -1;
1091 sprintf(aaa, "OIMG %s", filename);
1092 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1094 /* FIXME: Possible race condition */
1095 if (ret / 100 == 2) {
1096 download_in_progress = 1;
1097 bytes = extract_long(cret, 0);
1098 last_mod = extract_int(cret, 1);
1099 extract(mimetype, cret, 2);
1100 ret = CtdlIPCReadDownload(buf, bytes, cret);
1101 ret = CtdlIPCEndDownload(cret);
1103 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1104 filename, mimetype);
1111 int CtdlIPCFileUpload(const char *filename, const char *comment, void *buf,
1112 size_t bytes, char *cret)
1117 if (!cret) return -1;
1118 if (!filename) return -1;
1119 if (!comment) return -1;
1120 if (upload_in_progress) return -1;
1122 aaa = (char *)malloc(strlen(filename) + strlen(comment) + 7);
1123 if (!aaa) return -1;
1125 sprintf(aaa, "UOPN %s|%s", filename, comment);
1126 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1128 /* FIXME: Possible race condition */
1130 upload_in_progress = 1;
1131 ret = CtdlIPCWriteUpload(buf, bytes, cret);
1132 ret = CtdlIPCEndUpload(cret);
1138 int CtdlIPCImageUpload(int for_real, const char *filename, size_t bytes,
1144 if (!cret) return -1;
1145 if (!filename) return -1;
1146 if (upload_in_progress) return -1;
1148 aaa = (char *)malloc(strlen(filename) + 17);
1149 if (!aaa) return -1;
1151 sprintf(aaa, "UIMG %d|%s", for_real, filename);
1152 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1154 /* FIXME: Possible race condition */
1156 upload_in_progress = 1;
1162 int CtdlIPCQueryUsername(const char *username, char *cret)
1167 if (!cret) return -2;
1168 if (!username) return -2;
1170 aaa = (char *)malloc(strlen(username) + 6);
1171 if (!aaa) return -1;
1173 sprintf(aaa, "QUSR %s", username);
1174 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1181 int CtdlIPCFloorListing(char **listing, char *cret)
1185 if (!cret) return -2;
1186 if (!listing) return -2;
1187 if (*listing) return -2;
1189 return CtdlIPCGenericCommand("LFLR", NULL, 0, listing, &bytes, cret);
1194 int CtdlIPCCreateFloor(int for_real, const char *name, char *cret)
1199 if (!cret) return -2;
1200 if (!name) return -2;
1202 aaa = (char *)malloc(strlen(name) + 17);
1203 if (!aaa) return -1;
1205 sprintf(aaa, "CFLR %s|%d", name, for_real);
1206 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1213 int CtdlIPCDeleteFloor(int for_real, int floornum, char *cret)
1217 if (!cret) return -1;
1218 if (floornum < 0) return -1;
1220 sprintf(aaa, "KFLR %d|%d", floornum, for_real);
1221 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1226 int CtdlIPCEditFloor(int floornum, const char *floorname, char *cret)
1231 if (!cret) return -2;
1232 if (!floorname) return -2;
1233 if (floornum < 0) return -2;
1235 aaa = (char *)malloc(strlen(floorname) + 17);
1236 if (!aaa) return -1;
1238 sprintf(aaa, "EFLR %d|%s", floornum, floorname);
1239 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1246 int CtdlIPCIdentifySoftware(int developerid, int clientid, int revision,
1247 const char *software_name, const char *hostname, char *cret)
1252 if (developerid < 0) return -2;
1253 if (clientid < 0) return -2;
1254 if (revision < 0) return -2;
1255 if (!software_name) return -2;
1256 if (!hostname) return -2;
1258 aaa = (char *)malloc(strlen(software_name) + strlen(hostname) + 29);
1259 if (!aaa) return -1;
1261 sprintf(aaa, "IDEN %d|%d|%d|%s|%s", developerid, clientid,
1262 revision, software_name, hostname);
1263 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1270 int CtdlIPCSendInstantMessage(const char *username, const char *text,
1276 if (!cret) return -2;
1277 if (!username) return -2;
1279 aaa = (char *)malloc(strlen(username) + 8);
1280 if (!aaa) return -1;
1283 sprintf(aaa, "SEXP %s|-", username);
1284 ret = CtdlIPCGenericCommand(aaa, text, strlen(text),
1287 sprintf(aaa, "SEXP %s||", username);
1288 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1296 int CtdlIPCGetInstantMessage(char **listing, char *cret)
1300 if (!cret) return -2;
1301 if (!listing) return -2;
1302 if (*listing) return -2;
1304 return CtdlIPCGenericCommand("GEXP", NULL, 0, listing, &bytes, cret);
1309 /* mode is 0 = enable, 1 = disable, 2 = status */
1310 int CtdlIPCEnableInstantMessageReceipt(int mode, char *cret)
1314 if (!cret) return -2;
1316 sprintf(aaa, "DEXP %d", mode);
1317 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1322 int CtdlIPCSetBio(char *bio, char *cret)
1324 if (!cret) return -2;
1325 if (!bio) return -2;
1327 return CtdlIPCGenericCommand("EBIO", bio, strlen(bio),
1333 int CtdlIPCGetBio(const char *username, char **listing, char *cret)
1339 if (!cret) return -2;
1340 if (!username) return -2;
1341 if (!listing) return -2;
1342 if (*listing) return -2;
1344 aaa = (char *)malloc(strlen(username) + 6);
1345 if (!aaa) return -1;
1347 sprintf(aaa, "RBIO %s", username);
1348 ret = CtdlIPCGenericCommand(aaa, NULL, 0, listing, &bytes, cret);
1355 int CtdlIPCListUsersWithBios(char **listing, char *cret)
1359 if (!cret) return -2;
1360 if (!listing) return -2;
1361 if (*listing) return -2;
1363 return CtdlIPCGenericCommand("LBIO", NULL, 0, listing, &bytes, cret);
1368 int CtdlIPCStealthMode(int mode, char *cret)
1372 if (!cret) return -1;
1374 sprintf(aaa, "STEL %d", mode ? 1 : 0);
1375 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1380 int CtdlIPCTerminateSession(int sid, char *cret)
1384 if (!cret) return -1;
1386 sprintf(aaa, "TERM %d", sid);
1387 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1392 int CtdlIPCTerminateServerNow(char *cret)
1394 if (!cret) return -1;
1396 return CtdlIPCGenericCommand("DOWN", NULL, 0, NULL, NULL, cret);
1401 int CtdlIPCTerminateServerScheduled(int mode, char *cret)
1405 if (!cret) return -1;
1407 sprintf(aaa, "SCDN %d", mode ? 1 : 0);
1408 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1413 int CtdlIPCEnterSystemMessage(const char *filename, const char *text,
1419 if (!cret) return -2;
1420 if (!text) return -2;
1421 if (!filename) return -2;
1423 aaa = (char *)malloc(strlen(filename) + 6);
1424 if (!aaa) return -1;
1426 sprintf(aaa, "EMSG %s", filename);
1427 ret = CtdlIPCGenericCommand(aaa, text, strlen(text), NULL, NULL, cret);
1434 int CtdlIPCChangeHostname(const char *hostname, char *cret)
1439 if (!cret) return -2;
1440 if (!hostname) return -2;
1442 aaa = (char *)malloc(strlen(hostname) + 6);
1443 if (!aaa) return -1;
1445 sprintf(aaa, "HCHG %s", hostname);
1446 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1453 int CtdlIPCChangeRoomname(const char *roomname, char *cret)
1458 if (!cret) return -2;
1459 if (!roomname) return -2;
1461 aaa = (char *)malloc(strlen(roomname) + 6);
1462 if (!aaa) return -1;
1464 sprintf(aaa, "RCHG %s", roomname);
1465 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1472 int CtdlIPCChangeUsername(const char *username, char *cret)
1477 if (!cret) return -2;
1478 if (!username) return -2;
1480 aaa = (char *)malloc(strlen(username) + 6);
1481 if (!aaa) return -1;
1483 sprintf(aaa, "UCHG %s", username);
1484 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1491 /* This function returns the actual server time reported, or 0 if error */
1492 time_t CtdlIPCServerTime(char *cret)
1494 register time_t tret;
1497 ret = CtdlIPCGenericCommand("TIME", NULL, 0, NULL, NULL, cret);
1498 if (ret / 100 == 2) {
1499 tret = extract_long(cret, 0);
1508 int CtdlIPCAideGetUserParameters(const char *who,
1509 struct usersupp **uret, char *cret)
1514 if (!cret) return -2;
1515 if (!uret) return -2;
1516 if (!*uret) *uret = (struct usersupp *)calloc(1, sizeof(struct usersupp));
1517 if (!*uret) return -1;
1519 aaa = (char *)malloc(strlen(uret[0]->fullname) + 6);
1520 if (!aaa) return -1;
1522 sprintf(aaa, "AGUP %s", who);
1523 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1524 if (ret / 100 == 2) {
1525 extract(uret[0]->fullname, cret, 0);
1526 extract(uret[0]->password, cret, 1);
1527 uret[0]->flags = extract_int(cret, 2);
1528 uret[0]->timescalled = extract_long(cret, 3);
1529 uret[0]->posted = extract_long(cret, 4);
1530 uret[0]->axlevel = extract_int(cret, 5);
1531 uret[0]->usernum = extract_long(cret, 6);
1532 uret[0]->lastcall = extract_long(cret, 7);
1533 uret[0]->USuserpurge = extract_int(cret, 8);
1541 int CtdlIPCAideSetUserParameters(const struct usersupp *uret, char *cret)
1546 if (!cret) return -2;
1547 if (!uret) return -2;
1549 aaa = (char *)malloc(strlen(uret->fullname) + strlen(uret->password) + 84);
1550 if (!aaa) return -1;
1552 sprintf(aaa, "ASUP %s|%s|%d|%ld|%ld|%d|%ld|%ld|%d",
1553 uret->fullname, uret->password, uret->flags,
1554 uret->timescalled, uret->posted, uret->axlevel,
1555 uret->usernum, uret->lastcall, uret->USuserpurge);
1556 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1563 /* which is 0 = room, 1 = floor, 2 = site */
1564 int CtdlIPCGetMessageExpirationPolicy(int which, char *cret)
1566 static char *proto[] = {"room", "floor", "site"};
1569 if (!cret) return -2;
1570 if (which < 0 || which > 2) return -2;
1572 sprintf(aaa, "GPEX %s", proto[which]);
1573 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1578 /* which is 0 = room, 1 = floor, 2 = site */
1579 /* policy is 0 = inherit, 1 = no purge, 2 = by count, 3 = by age (days) */
1580 int CtdlIPCSetMessageExpirationPolicy(int which, int policy, int value,
1585 if (!cret) return -2;
1586 if (which < 0 || which > 2) return -2;
1587 if (policy < 0 || policy > 3) return -2;
1588 if (policy >= 2 && value < 1) return -2;
1590 sprintf(aaa, "SPEX %d|%d|%d", which, policy, value);
1591 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1596 int CtdlGetSystemConfig(char **listing, char *cret)
1600 if (!cret) return -2;
1601 if (!listing) return -2;
1602 if (*listing) return -2;
1604 return CtdlIPCGenericCommand("CONF GET", NULL, 0,
1605 listing, &bytes, cret);
1610 int CtdlSetSystemConfig(const char *listing, char *cret)
1612 if (!cret) return -2;
1613 if (!listing) return -2;
1615 return CtdlIPCGenericCommand("CONF SET", listing, strlen(listing),
1621 int CtdlIPCModerateMessage(long msgnum, int level, char *cret)
1625 if (!cret) return -2;
1626 if (!msgnum) return -2;
1628 sprintf(aaa, "MMOD %ld|%d", msgnum, level);
1629 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1634 int CtdlIPCRequestClientLogout(int session, char *cret)
1638 if (!cret) return -2;
1639 if (session < 0) return -2;
1641 sprintf(aaa, "REQT %d", session);
1642 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1647 int CtdlIPCSetMessageSeen(long msgnum, int seen, char *cret)
1651 if (!cret) return -2;
1652 if (msgnum < 0) return -2;
1654 sprintf(aaa, "SEEN %ld|%d", msgnum, seen ? 1 : 0);
1655 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1660 int CtdlIPCStartEncryption(char *cret)
1662 return CtdlIPCGenericCommand("STLS", NULL, 0, NULL, NULL, cret);
1667 int CtdlIPCDirectoryLookup(const char *address, char *cret)
1671 if (!address) return -2;
1672 if (!cret) return -2;
1674 aaa = (char *)malloc(strlen(address) + 6);
1675 if (!aaa) return -1;
1677 sprintf(aaa, "QDIR %s", address);
1678 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1700 /* ************************************************************************** */
1701 /* Stuff below this line is not for public consumption */
1702 /* ************************************************************************** */
1705 inline void netio_lock(void)
1707 #ifdef THREADED_CLIENT
1708 pthread_mutex_lock(&rwlock);
1713 inline void netio_unlock(void)
1715 #ifdef THREADED_CLIENT
1716 pthread_mutex_unlock(&rwlock);
1721 /* Read a listing from the server up to 000. Append to dest if it exists */
1722 char *CtdlIPCReadListing(char *dest)
1729 if (ret) length = strlen(ret);
1730 while (serv_gets(aaa), strcmp(aaa, "000")) {
1731 ret = (char *)realloc(ret, length + strlen(aaa) + 2);
1733 strcpy(&ret[length], aaa);
1734 length += strlen(aaa);
1735 strcpy(&ret[length++], "\n");
1742 /* Send a listing to the server; generate the ending 000. */
1743 int CtdlIPCSendListing(const char *listing)
1747 text = (char *)malloc(strlen(listing) + 6);
1749 strcpy(text, listing);
1750 while (text[strlen(text) - 1] == '\n')
1751 text[strlen(text) - 1] = '\0';
1752 strcat(text, "\n000");
1757 /* Malloc failed but we are committed to send */
1758 /* This may result in extra blanks at the bottom */
1766 /* Partial read of file from server */
1767 size_t CtdlIPCPartialRead(void **buf, size_t offset, size_t bytes, char *cret)
1769 register size_t len = 0;
1772 if (!buf) return -1;
1773 if (!cret) return -1;
1774 if (bytes < 1) return -1;
1775 if (offset < 0) return -1;
1778 sprintf(aaa, "READ %d|%d", offset, bytes);
1782 strcpy(cret, &aaa[4]);
1784 len = extract_long(&aaa[4], 0);
1785 *buf = (void *)realloc(*buf, offset + len);
1787 /* I know what I'm doing */
1788 serv_read((char *)&buf[offset], len);
1790 /* We have to read regardless */
1791 serv_read(aaa, len);
1801 int CtdlIPCEndDownload(char *cret)
1805 if (!cret) return -2;
1806 if (!download_in_progress) return -2;
1808 ret = CtdlIPCGenericCommand("CLOS", NULL, 0, NULL, NULL, cret);
1810 download_in_progress = 0;
1816 int CtdlIPCReadDownload(void **buf, size_t bytes, char *cret)
1818 register size_t len;
1820 if (!cret) return -1;
1821 if (!buf) return -1;
1822 if (*buf) return -1;
1823 if (!download_in_progress) return -1;
1826 while (len < bytes) {
1827 len = CtdlIPCPartialRead(buf, len, 4096, cret);
1838 int CtdlIPCEndUpload(char *cret)
1842 if (!cret) return -1;
1843 if (!upload_in_progress) return -1;
1845 ret = CtdlIPCGenericCommand("UCLS", NULL, 0, NULL, NULL, cret);
1847 upload_in_progress = 0;
1853 int CtdlIPCWriteUpload(void *buf, size_t bytes, char *cret)
1855 register int ret = -1;
1856 register size_t offset;
1859 if (!cret) return -1;
1860 if (!buf) return -1;
1861 if (bytes < 1) return -1;
1864 while (offset < bytes) {
1865 sprintf(aaa, "WRIT %d", bytes - offset);
1868 strcpy(cret, &aaa[4]);
1870 if (aaa[0] == '7') {
1871 register size_t to_write;
1873 to_write = extract_long(&aaa[4], 0);
1874 serv_write(buf + offset, to_write);
1885 * Generic command method. This method should handle any server command
1886 * except for CHAT. It takes the following arguments:
1888 * command Preformatted command to send to server
1889 * to_send A text or binary file to send to server
1890 * (only sent if server requests it)
1891 * bytes_to_send The number of bytes in to_send (required if
1892 * sending binary, optional if sending listing)
1893 * to_receive Pointer to a NULL pointer, if the server
1894 * sends text or binary we will allocate memory
1895 * for the file and stuff it here
1896 * bytes_to_receive If a file is received, we will store its
1898 * proto_response The protocol response. Caller must provide
1899 * this buffer and ensure that it is at least
1900 * 128 bytes in length.
1902 * This function returns a number equal to the protocol response number,
1903 * -1 if an internal error occurred, -2 if caller provided bad values,
1904 * or 0 - the protocol response number if bad values were found during
1905 * the protocol exchange.
1906 * It stores the protocol response string (minus the number) in
1907 * protocol_response as described above. Some commands send additional
1908 * data in this string.
1910 int CtdlIPCGenericCommand(const char *command, const char *to_send,
1911 size_t bytes_to_send, char **to_receive,
1912 size_t *bytes_to_receive, char *proto_response)
1917 if (!command) return -2;
1918 if (!proto_response) return -2;
1921 serv_puts((char *)command);
1923 serv_gets(proto_response);
1924 if (proto_response[3] == '*')
1926 ret = atoi(proto_response);
1927 memmove(proto_response, &proto_response[4],
1928 strlen(proto_response) - 3);
1929 switch (ret / 100) {
1930 default: /* Unknown, punt */
1932 case 3: /* MORE_DATA */
1934 /* Don't need to do anything */
1936 case 1: /* LISTING_FOLLOWS */
1937 if (to_receive && !*to_receive && bytes_to_receive) {
1938 *to_receive = CtdlIPCReadListing(NULL);
1939 } else { /* Drain */
1940 while (serv_gets(buf), strcmp(buf, "000")) ;
1944 case 4: /* SEND_LISTING */
1946 CtdlIPCSendListing(to_send);
1948 /* No listing given, fake it */
1953 case 6: /* BINARY_FOLLOWS */
1954 if (to_receive && !*to_receive && bytes_to_receive) {
1956 extract_long(proto_response, 0);
1957 *to_receive = (char *)malloc(*bytes_to_receive);
1961 serv_read(*to_receive,
1968 drain = extract_long(proto_response, 0);
1969 while (drain > SIZ) {
1970 serv_read(buf, SIZ);
1973 serv_read(buf, drain);
1977 case 7: /* SEND_BINARY */
1978 if (to_send && bytes_to_send) {
1979 serv_write((char *)to_send, bytes_to_send);
1980 } else if (bytes_to_send) {
1981 /* Fake it, send nulls */
1984 fake = bytes_to_send;
1985 memset(buf, '\0', SIZ);
1986 while (fake > SIZ) {
1987 serv_write(buf, SIZ);
1990 serv_write(buf, fake);
1992 } /* else who knows? DANGER WILL ROBINSON */
1994 case 8: /* START_CHAT_MODE */
1995 if (!strncasecmp(command, "CHAT", 4)) {
1996 /* Don't call chatmode with generic! */
2000 /* In this mode we send then receive listing */
2002 CtdlIPCSendListing(to_send);
2004 /* No listing given, fake it */
2008 if (to_receive && !*to_receive
2009 && bytes_to_receive) {
2010 *to_receive = CtdlIPCReadListing(NULL);
2011 } else { /* Drain */
2012 while (serv_gets(buf),
2013 strcmp(buf, "000")) ;
2018 case 9: /* ASYNC_MSG */
2019 /* CtdlIPCDoAsync(ret, proto_response); */
2020 free(CtdlIPCReadListing(NULL)); /* STUB FIXME */