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 * unless there was a problem creating the account.
156 int CtdlIPCCreateUser(const char *username, char *cret)
161 if (!username) return -2;
162 if (!cret) return -2;
164 aaa = (char *)malloc(strlen(username) + 6);
167 sprintf(aaa, "NEWU %s", username);
168 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
175 * Changes the user's password. Returns 200 if changed, errors otherwise.
177 int CtdlIPCChangePassword(const char *passwd, char *cret)
182 if (!passwd) return -2;
183 if (!cret) return -2;
185 aaa = (char *)malloc(strlen(passwd) + 6);
188 sprintf(aaa, "SETP %s", passwd);
189 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
196 /* Caller must free the march list */
197 /* which is 0 = LRMS, 1 = LKRN, 2 = LKRO, 3 = LKRA, 4 = LZRM */
198 /* floor is -1 for all, or floornum */
199 int CtdlIPCKnownRooms(int which, int floor, struct march **listing, char *cret)
202 struct march *march = NULL;
203 static char *proto[] = {"LRMS", "LKRN", "LKRO", "LKRA", "LZRM" };
208 if (!listing) return -2;
209 if (*listing) return -2; /* Free the listing first */
210 if (!cret) return -2;
211 if (which < 0 || which > 4) return -2;
212 if (floor < -1) return -2; /* Can't validate upper bound, sorry */
214 sprintf(aaa, "%s %d", proto[which], floor);
215 ret = CtdlIPCGenericCommand(aaa, NULL, 0, &bbb, &bbbsize, cret);
216 if (ret / 100 == 1) {
219 while (bbb && strlen(bbb)) {
222 extract_token(aaa, bbb, 0, '\n');
224 memmove(bbb, bbb + a + 1, strlen(bbb) - a);
225 mptr = (struct march *) malloc(sizeof (struct march));
228 extract(mptr->march_name, aaa, 0);
229 mptr->march_floor = (char) extract_int(aaa, 2);
230 mptr->march_order = (char) extract_int(aaa, 3);
237 while (mptr2->next != NULL)
250 /* Caller must free the struct usersupp; caller may pass an existing one */
251 int CtdlIPCGetConfig(struct usersupp **uret, char *cret)
255 if (!cret) return -2;
256 if (!uret) return -2;
257 if (!*uret) *uret = (struct usersupp *)calloc(1, sizeof (struct usersupp));
258 if (!*uret) return -1;
260 ret = CtdlIPCGenericCommand("GETU", NULL, 0, NULL, NULL, cret);
261 if (ret / 100 == 2) {
262 uret[0]->USscreenwidth = extract_int(cret, 0);
263 uret[0]->USscreenheight = extract_int(cret, 1);
264 uret[0]->flags = extract_int(cret, 2);
271 int CtdlIPCSetConfig(struct usersupp *uret, char *cret)
275 if (!uret) return -2;
276 if (!cret) return -2;
278 sprintf(aaa, "SETU %d|%d|%d",
279 uret->USscreenwidth, uret->USscreenheight,
281 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
286 int CtdlIPCGotoRoom(const char *room, const char *passwd,
287 struct ctdlipcroom **rret, char *cret)
292 if (!cret) return -2;
293 if (!rret) return -2;
294 if (!*rret) *rret = (struct ctdlipcroom *)calloc(1, sizeof (struct ctdlipcroom));
295 if (!*rret) return -1;
298 aaa = (char *)malloc(strlen(room) + strlen(passwd) + 7);
303 sprintf(aaa, "GOTO %s|%s", room, passwd);
305 aaa = (char *)malloc(strlen(room) + 6);
310 sprintf(aaa, "GOTO %s", room);
312 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
313 if (ret / 100 == 2) {
314 extract(rret[0]->RRname, cret, 0);
315 rret[0]->RRunread = extract_long(cret, 1);
316 rret[0]->RRtotal = extract_long(cret, 2);
317 rret[0]->RRinfoupdated = extract_int(cret, 3);
318 rret[0]->RRflags = extract_int(cret, 4);
319 rret[0]->RRhighest = extract_long(cret, 5);
320 rret[0]->RRlastread = extract_long(cret, 6);
321 rret[0]->RRismailbox = extract_int(cret, 7);
322 rret[0]->RRaide = extract_int(cret, 8);
323 rret[0]->RRnewmail = extract_long(cret, 9);
324 rret[0]->RRfloor = extract_int(cret, 10);
333 /* which is 0 = all, 1 = old, 2 = new, 3 = last, 4 = first, 5 = gt, 6 = lt */
334 /* whicharg is number of messages, applies to last, first, gt, lt */
335 int CtdlIPCGetMessages(int which, int whicharg, const char *template,
336 long **mret, char *cret)
339 register long count = 0;
340 static char *proto[] =
341 { "ALL", "OLD", "NEW", "LAST", "FIRST", "GT", "LT" };
346 if (!cret) return -2;
347 if (!mret) return -2;
348 if (*mret) return -2;
349 if (which < 0 || which > 6) return -2;
352 sprintf(aaa, "MSGS %s||%d", proto[which],
355 sprintf(aaa, "MSGS %s|%d|%d", proto[which], whicharg,
357 if (template) count = strlen(template);
358 ret = CtdlIPCGenericCommand(aaa, template, count, &bbb, &bbbsize, cret);
360 while (strlen(bbb)) {
363 extract_token(aaa, bbb, 0, '\n');
365 memmove(aaa, bbb + a + 1, strlen(bbb) - a - 1);
366 *mret = (long *)realloc(mret, (count + 1) * sizeof (long));
368 *mret[count++] = atol(aaa);
376 int CtdlIPCGetSingleMessage(long msgnum, int headers, int as_mime,
377 struct ctdlipcmessage **mret, char *cret)
384 if (!cret) return -1;
385 if (!mret) return -1;
386 if (!*mret) *mret = (struct ctdlipcmessage *)calloc(1, sizeof (struct ctdlipcmessage));
387 if (!*mret) return -1;
388 if (!msgnum) return -1;
390 sprintf(aaa, "MSG%c %ld|%d", as_mime ? '2' : '0', msgnum, headers);
391 ret = CtdlIPCGenericCommand(aaa, NULL, 0, &bbb, &bbbsize, cret);
392 if (ret / 100 == 1) {
394 while (strlen(bbb) > 4 && bbb[4] == '=') {
395 extract_token(aaa, bbb, 0, '\n');
396 remove_token(bbb, 0, '\n');
398 if (!strncasecmp(aaa, "nhdr=yes", 8))
400 else if (!strncasecmp(aaa, "from=", 5))
401 strcpy(mret[0]->author, &aaa[5]);
402 else if (!strncasecmp(aaa, "type=", 5))
403 mret[0]->type = atoi(&aaa[5]);
404 else if (!strncasecmp(aaa, "msgn=", 5))
405 strcpy(mret[0]->msgid, &aaa[5]);
406 else if (!strncasecmp(aaa, "subj=", 5))
407 strcpy(mret[0]->subject, &aaa[5]);
408 else if (!strncasecmp(aaa, "rfca=", 5))
409 strcpy(mret[0]->email, &aaa[5]);
410 else if (!strncasecmp(aaa, "hnod=", 5))
411 strcpy(mret[0]->hnod, &aaa[5]);
412 else if (!strncasecmp(aaa, "room=", 5))
413 strcpy(mret[0]->room, &aaa[5]);
414 else if (!strncasecmp(aaa, "node=", 5))
415 strcpy(mret[0]->node, &aaa[5]);
416 else if (!strncasecmp(aaa, "rcpt=", 5))
417 strcpy(mret[0]->recipient, &aaa[5]);
418 else if (!strncasecmp(aaa, "time=", 5))
419 mret[0]->time = atol(&aaa[5]);
420 else if (!strncasecmp(aaa, "part=", 5)) {
421 struct parts *ptr, *chain;
423 ptr = (struct parts *)calloc(1, sizeof (struct parts));
425 extract(ptr->name, &aaa[5], 0);
426 extract(ptr->filename, &aaa[5], 1);
427 extract(ptr->number, &aaa[5], 2);
428 extract(ptr->disposition, &aaa[5], 3);
429 extract(ptr->mimetype, &aaa[5], 4);
430 ptr->length = extract_long(&aaa[5], 5);
431 if (!mret[0]->attachments)
432 mret[0]->attachments = ptr;
434 chain = mret[0]->attachments;
442 /* Eliminate "text\n" */
443 remove_token(bbb, 0, '\n');
446 /* Strip trailing whitespace */
447 bbb = (char *)realloc(bbb, strlen(bbb) + 1);
458 int CtdlIPCWhoKnowsRoom(char **listing, char *cret)
463 if (!cret) return -2;
464 if (!listing) return -2;
465 if (*listing) return -2;
467 ret = CtdlIPCGenericCommand("WHOK", NULL, 0, listing, &bytes, cret);
473 int CtdlIPCServerInfo(struct CtdlServInfo *ServInfo, char *cret)
477 char *listing = NULL;
480 if (!cret) return -2;
481 if (!ServInfo) return -2;
483 ret = CtdlIPCGenericCommand("INFO", NULL, 0, &listing, &bytes, cret);
484 if (ret / 100 == 1) {
487 while (*listing && strlen(listing)) {
488 extract_token(buf, listing, 0, '\n');
489 remove_token(listing, 0, '\n');
491 case 0: ServInfo->serv_pid = atoi(buf);
493 case 1: strcpy(ServInfo->serv_nodename,buf);
495 case 2: strcpy(ServInfo->serv_humannode,buf);
497 case 3: strcpy(ServInfo->serv_fqdn,buf);
499 case 4: strcpy(ServInfo->serv_software,buf);
501 case 5: ServInfo->serv_rev_level = atoi(buf);
503 case 6: strcpy(ServInfo->serv_bbs_city,buf);
505 case 7: strcpy(ServInfo->serv_sysadm,buf);
507 case 9: strcpy(ServInfo->serv_moreprompt,buf);
509 case 10: ServInfo->serv_ok_floors = atoi(buf);
511 case 11: ServInfo->serv_paging_level = atoi(buf);
513 case 13: ServInfo->serv_supports_qnop = atoi(buf);
524 int CtdlIPCReadDirectory(char **listing, char *cret)
529 if (!cret) return -2;
530 if (!listing) return -2;
531 if (*listing) return -2;
533 ret = CtdlIPCGenericCommand("RDIR", NULL, 0, listing, &bytes, cret);
539 * Set last-read pointer in this room to msgnum, or 0 for HIGHEST.
541 int CtdlIPCSetLastRead(long msgnum, char *cret)
546 if (!cret) return -2;
549 sprintf(aaa, "SLRP %ld", msgnum);
551 sprintf(aaa, "SLRP HIGHEST");
552 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
558 int CtdlIPCInviteUserToRoom(const char *username, char *cret)
563 if (!cret) return -2;
564 if (!username) return -2;
566 aaa = (char *)malloc(strlen(username) + 6);
569 sprintf(aaa, "INVT %s", username);
570 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
577 int CtdlIPCKickoutUserFromRoom(const char *username, char *cret)
582 if (!cret) return -1;
583 if (!username) return -1;
585 aaa = (char *)malloc(strlen(username) + 6);
587 sprintf(aaa, "KICK %s", username);
588 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
595 int CtdlIPCGetRoomAttributes(struct quickroom **qret, char *cret)
599 if (!cret) return -2;
600 if (!qret) return -2;
601 if (!*qret) *qret = (struct quickroom *)calloc(1, sizeof (struct quickroom));
602 if (!*qret) return -1;
604 ret = CtdlIPCGenericCommand("GETR", NULL, 0, NULL, NULL, cret);
605 if (ret / 100 == 2) {
606 extract(qret[0]->QRname, cret, 0);
607 extract(qret[0]->QRpasswd, cret, 1);
608 extract(qret[0]->QRdirname, cret, 2);
609 qret[0]->QRflags = extract_int(cret, 3);
610 qret[0]->QRfloor = extract_int(cret, 4);
611 qret[0]->QRorder = extract_int(cret, 5);
618 /* set forget to kick all users out of room */
619 int CtdlIPCSetRoomAttributes(int forget, struct quickroom *qret, char *cret)
624 if (!cret) return -2;
625 if (!qret) return -2;
627 aaa = (char *)malloc(strlen(qret->QRname) + strlen(qret->QRpasswd) +
628 strlen(qret->QRdirname) + 52);
631 sprintf(aaa, "SETR %s|%s|%s|%d|%d|%d|%d",
632 qret->QRname, qret->QRpasswd, qret->QRdirname,
633 qret->QRflags, forget, qret->QRfloor, qret->QRorder);
634 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
641 int CtdlIPCGetRoomAide(char *cret)
643 if (!cret) return -1;
645 return CtdlIPCGenericCommand("GETA", NULL, 0, NULL, NULL, cret);
650 int CtdlIPCSetRoomAide(const char *username, char *cret)
655 if (!cret) return -2;
656 if (!username) return -2;
658 aaa = (char *)malloc(strlen(username) + 6);
661 sprintf(aaa, "SETA %s", username);
662 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
669 int CtdlIPCPostMessage(int flag, const struct ctdlipcmessage *mr, char *cret)
674 if (!cret) return -2;
677 aaa = (char *)malloc(strlen(mr->recipient) + strlen(mr->author) + 40);
680 sprintf(aaa, "ENT0 %d|%s|%d|%d|%s", flag, mr->recipient, mr->anonymous,
681 mr->type, mr->author);
682 ret = CtdlIPCGenericCommand(aaa, mr->text, strlen(mr->text), NULL,
690 int CtdlIPCRoomInfo(char **iret, char *cret)
694 if (!cret) return -2;
695 if (!iret) return -2;
696 if (*iret) return -2;
698 return CtdlIPCGenericCommand("RINF", NULL, 0, iret, &bytes, cret);
703 int CtdlIPCDeleteMessage(long msgnum, char *cret)
707 if (!cret) return -2;
708 if (!msgnum) return -2;
710 sprintf(aaa, "DELE %ld", msgnum);
711 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
716 int CtdlIPCMoveMessage(int copy, long msgnum, const char *destroom, char *cret)
721 if (!cret) return -2;
722 if (!destroom) return -2;
723 if (!msgnum) return -2;
725 aaa = (char *)malloc(strlen(destroom) + 28);
728 sprintf(aaa, "MOVE %ld|%s|%d", msgnum, destroom, copy);
729 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
736 int CtdlIPCDeleteRoom(int for_real, char *cret)
740 if (!cret) return -2;
742 sprintf(aaa, "KILL %d", for_real);
743 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
748 int CtdlIPCCreateRoom(int for_real, const char *roomname, int type,
749 const char *password, int floor, char *cret)
754 if (!cret) return -2;
755 if (!roomname) return -2;
758 aaa = (char *)malloc(strlen(roomname) + strlen(password) + 40);
760 sprintf(aaa, "CRE8 %d|%s|%d|%s|%d", for_real, roomname, type,
763 aaa = (char *)malloc(strlen(roomname) + 40);
765 sprintf(aaa, "CRE8 %d|%s|%d||%d", for_real, roomname, type,
768 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
775 int CtdlIPCForgetRoom(char *cret)
777 if (!cret) return -2;
779 return CtdlIPCGenericCommand("FORG", NULL, 0, NULL, NULL, cret);
784 int CtdlIPCSystemMessage(const char *message, char **mret, char *cret)
790 if (!cret) return -2;
791 if (!mret) return -2;
792 if (*mret) return -2;
793 if (!message) return -2;
795 aaa = (char *)malloc(strlen(message) + 6);
798 sprintf(aaa, "MESG %s", message);
799 ret = CtdlIPCGenericCommand(aaa, NULL, 0, mret, &bytes, cret);
806 int CtdlIPCNextUnvalidatedUser(char *cret)
808 if (!cret) return -2;
810 return CtdlIPCGenericCommand("GNUR", NULL, 0, NULL, NULL, cret);
815 int CtdlIPCGetUserRegistration(const char *username, char **rret, char *cret)
821 if (!cret) return -2;
822 if (!rret) return -2;
823 if (*rret) return -2;
826 aaa = (char *)malloc(strlen(username) + 6);
828 aaa = (char *)malloc(12);
832 sprintf(aaa, "GREG %s", username);
834 sprintf(aaa, "GREG _SELF_");
835 ret = CtdlIPCGenericCommand(aaa, NULL, 0, rret, &bytes, cret);
842 int CtdlIPCValidateUser(const char *username, int axlevel, char *cret)
847 if (!cret) return -2;
848 if (!username) return -2;
849 if (axlevel < 0 || axlevel > 7) return -2;
851 aaa = (char *)malloc(strlen(username) + 17);
854 sprintf(aaa, "VALI %s|%d", username, axlevel);
855 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
862 int CtdlIPCSetRoomInfo(int for_real, const char *info, char *cret)
866 if (!cret) return -1;
867 if (!info) return -1;
869 sprintf(aaa, "EINF %d", for_real);
870 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
875 int CtdlIPCUserListing(char **listing, char *cret)
879 if (!cret) return -1;
880 if (!listing) return -1;
881 if (*listing) return -1;
883 return CtdlIPCGenericCommand("LIST", NULL, 0, listing, &bytes, cret);
888 int CtdlIPCSetRegistration(const char *info, char *cret)
890 if (!cret) return -1;
891 if (!info) return -1;
893 return CtdlIPCGenericCommand("REGI", info, strlen(info),
899 int CtdlIPCMiscCheck(struct ctdlipcmisc *chek, char *cret)
903 if (!cret) return -1;
904 if (!chek) return -1;
906 ret = CtdlIPCGenericCommand("CHEK", NULL, 0, NULL, NULL, cret);
907 if (ret / 100 == 2) {
908 chek->newmail = extract_long(cret, 0);
909 chek->needregis = extract_int(cret, 1);
910 chek->needvalid = extract_int(cret, 2);
917 int CtdlIPCDeleteFile(const char *filename, char *cret)
922 if (!cret) return -2;
923 if (!filename) return -2;
925 aaa = (char *)malloc(strlen(filename) + 6);
928 sprintf(aaa, "DELF %s", filename);
929 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
936 int CtdlIPCMoveFile(const char *filename, const char *destroom, char *cret)
941 if (!cret) return -2;
942 if (!filename) return -2;
943 if (!destroom) return -2;
945 aaa = (char *)malloc(strlen(filename) + strlen(destroom) + 7);
948 sprintf(aaa, "MOVF %s|%s", filename, destroom);
949 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
956 int CtdlIPCNetSendFile(const char *filename, const char *destnode, char *cret)
961 if (!cret) return -2;
962 if (!filename) return -2;
963 if (!destnode) return -2;
965 aaa = (char *)malloc(strlen(filename) + strlen(destnode) + 7);
968 sprintf(aaa, "NETF %s|%s", filename, destnode);
969 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
976 int CtdlIPCOnlineUsers(char **listing, time_t *stamp, char *cret)
981 if (!cret) return -1;
982 if (!listing) return -1;
983 if (*listing) return -1;
985 *stamp = CtdlIPCServerTime(cret);
988 ret = CtdlIPCGenericCommand("RWHO", NULL, 0, listing, &bytes, cret);
994 int CtdlIPCFileDownload(const char *filename, void **buf, char *cret)
1002 if (!cret) return -2;
1003 if (!filename) return -2;
1004 if (!buf) return -2;
1005 if (*buf) return -2;
1006 if (download_in_progress) return -2;
1008 aaa = (char *)malloc(strlen(filename) + 6);
1009 if (!aaa) return -1;
1011 sprintf(aaa, "OPEN %s", filename);
1012 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1014 /* FIXME: Possible race condition */
1015 if (ret / 100 == 2) {
1016 download_in_progress = 1;
1017 bytes = extract_long(cret, 0);
1018 last_mod = extract_int(cret, 1);
1019 extract(mimetype, cret, 2);
1020 ret = CtdlIPCReadDownload(buf, bytes, cret);
1021 ret = CtdlIPCEndDownload(cret);
1023 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1024 filename, mimetype);
1031 int CtdlIPCAttachmentDownload(long msgnum, const char *part, void **buf,
1041 if (!cret) return -2;
1042 if (!buf) return -2;
1043 if (*buf) return -2;
1044 if (!part) return -2;
1045 if (!msgnum) return -2;
1046 if (download_in_progress) return -2;
1048 aaa = (char *)malloc(strlen(part) + 17);
1049 if (!aaa) return -1;
1051 sprintf(aaa, "OPNA %ld|%s", msgnum, part);
1052 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1054 /* FIXME: Possible race condition */
1055 if (ret / 100 == 2) {
1056 download_in_progress = 1;
1057 bytes = extract_long(cret, 0);
1058 last_mod = extract_int(cret, 1);
1059 extract(mimetype, cret, 2);
1060 ret = CtdlIPCReadDownload(buf, bytes, cret);
1061 ret = CtdlIPCEndDownload(cret);
1063 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1064 filename, mimetype);
1071 int CtdlIPCImageDownload(const char *filename, void **buf, char *cret)
1079 if (!cret) return -1;
1080 if (!buf) return -1;
1081 if (*buf) return -1;
1082 if (!filename) return -1;
1083 if (download_in_progress) return -1;
1085 aaa = (char *)malloc(strlen(filename) + 6);
1086 if (!aaa) return -1;
1088 sprintf(aaa, "OIMG %s", filename);
1089 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1091 /* FIXME: Possible race condition */
1092 if (ret / 100 == 2) {
1093 download_in_progress = 1;
1094 bytes = extract_long(cret, 0);
1095 last_mod = extract_int(cret, 1);
1096 extract(mimetype, cret, 2);
1097 ret = CtdlIPCReadDownload(buf, bytes, cret);
1098 ret = CtdlIPCEndDownload(cret);
1100 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1101 filename, mimetype);
1108 int CtdlIPCFileUpload(const char *filename, const char *comment, void *buf,
1109 size_t bytes, char *cret)
1114 if (!cret) return -1;
1115 if (!filename) return -1;
1116 if (!comment) return -1;
1117 if (upload_in_progress) return -1;
1119 aaa = (char *)malloc(strlen(filename) + strlen(comment) + 7);
1120 if (!aaa) return -1;
1122 sprintf(aaa, "UOPN %s|%s", filename, comment);
1123 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1125 /* FIXME: Possible race condition */
1127 upload_in_progress = 1;
1128 ret = CtdlIPCWriteUpload(buf, bytes, cret);
1129 ret = CtdlIPCEndUpload(cret);
1135 int CtdlIPCImageUpload(int for_real, const char *filename, size_t bytes,
1141 if (!cret) return -1;
1142 if (!filename) return -1;
1143 if (upload_in_progress) return -1;
1145 aaa = (char *)malloc(strlen(filename) + 17);
1146 if (!aaa) return -1;
1148 sprintf(aaa, "UIMG %d|%s", for_real, filename);
1149 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1151 /* FIXME: Possible race condition */
1153 upload_in_progress = 1;
1159 int CtdlIPCQueryUsername(const char *username, char *cret)
1164 if (!cret) return -2;
1165 if (!username) return -2;
1167 aaa = (char *)malloc(strlen(username) + 6);
1168 if (!aaa) return -1;
1170 sprintf(aaa, "QUSR %s", username);
1171 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1178 int CtdlIPCFloorListing(char **listing, char *cret)
1182 if (!cret) return -2;
1183 if (!listing) return -2;
1184 if (*listing) return -2;
1186 return CtdlIPCGenericCommand("LFLR", NULL, 0, listing, &bytes, cret);
1191 int CtdlIPCCreateFloor(int for_real, const char *name, char *cret)
1196 if (!cret) return -2;
1197 if (!name) return -2;
1199 aaa = (char *)malloc(strlen(name) + 17);
1200 if (!aaa) return -1;
1202 sprintf(aaa, "CFLR %s|%d", name, for_real);
1203 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1210 int CtdlIPCDeleteFloor(int for_real, int floornum, char *cret)
1214 if (!cret) return -1;
1215 if (floornum < 0) return -1;
1217 sprintf(aaa, "KFLR %d|%d", floornum, for_real);
1218 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1223 int CtdlIPCEditFloor(int floornum, const char *floorname, char *cret)
1228 if (!cret) return -2;
1229 if (!floorname) return -2;
1230 if (floornum < 0) return -2;
1232 aaa = (char *)malloc(strlen(floorname) + 17);
1233 if (!aaa) return -1;
1235 sprintf(aaa, "EFLR %d|%s", floornum, floorname);
1236 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1243 int CtdlIPCIdentifySoftware(int developerid, int clientid, int revision,
1244 const char *software_name, const char *hostname, char *cret)
1249 if (developerid < 0) return -2;
1250 if (clientid < 0) return -2;
1251 if (revision < 0) return -2;
1252 if (!software_name) return -2;
1253 if (!hostname) return -2;
1255 aaa = (char *)malloc(strlen(software_name) + strlen(hostname) + 29);
1256 if (!aaa) return -1;
1258 sprintf(aaa, "IDEN %d|%d|%d|%s|%s", developerid, clientid,
1259 revision, software_name, hostname);
1260 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1267 int CtdlIPCSendInstantMessage(const char *username, const char *text,
1273 if (!cret) return -2;
1274 if (!username) return -2;
1276 aaa = (char *)malloc(strlen(username) + 8);
1277 if (!aaa) return -1;
1280 sprintf(aaa, "SEXP %s|-", username);
1281 ret = CtdlIPCGenericCommand(aaa, text, strlen(text),
1284 sprintf(aaa, "SEXP %s||", username);
1285 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1293 int CtdlIPCGetInstantMessage(char **listing, char *cret)
1297 if (!cret) return -2;
1298 if (!listing) return -2;
1299 if (*listing) return -2;
1301 return CtdlIPCGenericCommand("GEXP", NULL, 0, listing, &bytes, cret);
1306 /* mode is 0 = enable, 1 = disable, 2 = status */
1307 int CtdlIPCEnableInstantMessageReceipt(int mode, char *cret)
1311 if (!cret) return -2;
1313 sprintf(aaa, "DEXP %d", mode);
1314 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1319 int CtdlIPCSetBio(char *bio, char *cret)
1321 if (!cret) return -2;
1322 if (!bio) return -2;
1324 return CtdlIPCGenericCommand("EBIO", bio, strlen(bio),
1330 int CtdlIPCGetBio(const char *username, char **listing, char *cret)
1336 if (!cret) return -2;
1337 if (!username) return -2;
1338 if (!listing) return -2;
1339 if (*listing) return -2;
1341 aaa = (char *)malloc(strlen(username) + 6);
1342 if (!aaa) return -1;
1344 sprintf(aaa, "RBIO %s", username);
1345 ret = CtdlIPCGenericCommand(aaa, NULL, 0, listing, &bytes, cret);
1352 int CtdlIPCListUsersWithBios(char **listing, char *cret)
1356 if (!cret) return -2;
1357 if (!listing) return -2;
1358 if (*listing) return -2;
1360 return CtdlIPCGenericCommand("LBIO", NULL, 0, listing, &bytes, cret);
1365 int CtdlIPCStealthMode(int mode, char *cret)
1369 if (!cret) return -1;
1371 sprintf(aaa, "STEL %d", mode ? 1 : 0);
1372 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1377 int CtdlIPCTerminateSession(int sid, char *cret)
1381 if (!cret) return -1;
1383 sprintf(aaa, "TERM %d", sid);
1384 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1389 int CtdlIPCTerminateServerNow(char *cret)
1391 if (!cret) return -1;
1393 return CtdlIPCGenericCommand("DOWN", NULL, 0, NULL, NULL, cret);
1398 int CtdlIPCTerminateServerScheduled(int mode, char *cret)
1402 if (!cret) return -1;
1404 sprintf(aaa, "SCDN %d", mode ? 1 : 0);
1405 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1410 int CtdlIPCEnterSystemMessage(const char *filename, const char *text,
1416 if (!cret) return -2;
1417 if (!text) return -2;
1418 if (!filename) return -2;
1420 aaa = (char *)malloc(strlen(filename) + 6);
1421 if (!aaa) return -1;
1423 sprintf(aaa, "EMSG %s", filename);
1424 ret = CtdlIPCGenericCommand(aaa, text, strlen(text), NULL, NULL, cret);
1431 int CtdlIPCChangeHostname(const char *hostname, char *cret)
1436 if (!cret) return -2;
1437 if (!hostname) return -2;
1439 aaa = (char *)malloc(strlen(hostname) + 6);
1440 if (!aaa) return -1;
1442 sprintf(aaa, "HCHG %s", hostname);
1443 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1450 int CtdlIPCChangeRoomname(const char *roomname, char *cret)
1455 if (!cret) return -2;
1456 if (!roomname) return -2;
1458 aaa = (char *)malloc(strlen(roomname) + 6);
1459 if (!aaa) return -1;
1461 sprintf(aaa, "RCHG %s", roomname);
1462 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1469 int CtdlIPCChangeUsername(const char *username, char *cret)
1474 if (!cret) return -2;
1475 if (!username) return -2;
1477 aaa = (char *)malloc(strlen(username) + 6);
1478 if (!aaa) return -1;
1480 sprintf(aaa, "UCHG %s", username);
1481 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1488 /* This function returns the actual server time reported, or 0 if error */
1489 time_t CtdlIPCServerTime(char *cret)
1491 register time_t tret;
1494 ret = CtdlIPCGenericCommand("TIME", NULL, 0, NULL, NULL, cret);
1495 if (ret / 100 == 2) {
1496 tret = extract_long(cret, 0);
1505 int CtdlIPCAideGetUserParameters(struct usersupp **uret, char *cret)
1510 if (!cret) return -2;
1511 if (!uret) return -2;
1512 if (!*uret) return -2;
1514 aaa = (char *)malloc(strlen(uret[0]->fullname) + 6);
1515 if (!aaa) return -1;
1517 sprintf(aaa, "AGUP %s", uret[0]->fullname);
1518 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1519 if (ret / 100 == 2) {
1520 extract(uret[0]->fullname, cret, 0);
1521 extract(uret[0]->password, cret, 1);
1522 uret[0]->flags = extract_int(cret, 2);
1523 uret[0]->timescalled = extract_long(cret, 3);
1524 uret[0]->posted = extract_long(cret, 4);
1525 uret[0]->axlevel = extract_int(cret, 5);
1526 uret[0]->usernum = extract_long(cret, 6);
1527 uret[0]->lastcall = extract_long(cret, 7);
1528 uret[0]->USuserpurge = extract_int(cret, 8);
1536 int CtdlIPCAideSetUserParameters(const struct usersupp *uret, char *cret)
1541 if (!cret) return -2;
1542 if (!uret) return -2;
1544 aaa = (char *)malloc(strlen(uret->fullname) + strlen(uret->password) + 84);
1545 if (!aaa) return -1;
1547 sprintf(aaa, "ASUP %s|%s|%d|%ld|%ld|%d|%ld|%ld|%d",
1548 uret->fullname, uret->password, uret->flags,
1549 uret->timescalled, uret->posted, uret->axlevel,
1550 uret->usernum, uret->lastcall, uret->USuserpurge);
1551 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1558 /* which is 0 = room, 1 = floor, 2 = site */
1559 int CtdlIPCGetMessageExpirationPolicy(int which, char *cret)
1561 static char *proto[] = {"room", "floor", "site"};
1564 if (!cret) return -2;
1565 if (which < 0 || which > 2) return -2;
1567 sprintf(aaa, "GPEX %s", proto[which]);
1568 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1573 /* which is 0 = room, 1 = floor, 2 = site */
1574 /* policy is 0 = inherit, 1 = no purge, 2 = by count, 3 = by age (days) */
1575 int CtdlIPCSetMessageExpirationPolicy(int which, int policy, int value,
1580 if (!cret) return -2;
1581 if (which < 0 || which > 2) return -2;
1582 if (policy < 0 || policy > 3) return -2;
1583 if (policy >= 2 && value < 1) return -2;
1585 sprintf(aaa, "SPEX %d|%d|%d", which, policy, value);
1586 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1591 int CtdlGetSystemConfig(char **listing, char *cret)
1595 if (!cret) return -2;
1596 if (!listing) return -2;
1597 if (*listing) return -2;
1599 return CtdlIPCGenericCommand("CONF GET", NULL, 0,
1600 listing, &bytes, cret);
1605 int CtdlSetSystemConfig(const char *listing, char *cret)
1607 if (!cret) return -2;
1608 if (!listing) return -2;
1610 return CtdlIPCGenericCommand("CONF SET", listing, strlen(listing),
1616 int CtdlIPCModerateMessage(long msgnum, int level, char *cret)
1620 if (!cret) return -2;
1621 if (!msgnum) return -2;
1623 sprintf(aaa, "MMOD %ld|%d", msgnum, level);
1624 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1629 int CtdlIPCRequestClientLogout(int session, char *cret)
1633 if (!cret) return -2;
1634 if (session < 0) return -2;
1636 sprintf(aaa, "REQT %d", session);
1637 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1642 int CtdlIPCSetMessageSeen(long msgnum, int seen, char *cret)
1646 if (!cret) return -2;
1647 if (msgnum < 0) return -2;
1649 sprintf(aaa, "SEEN %ld|%d", msgnum, seen ? 1 : 0);
1650 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1655 int CtdlIPCStartEncryption(char *cret)
1657 return CtdlIPCGenericCommand("STLS", NULL, 0, NULL, NULL, cret);
1679 /* ************************************************************************** */
1680 /* Stuff below this line is not for public consumption */
1681 /* ************************************************************************** */
1684 inline void netio_lock(void)
1686 #ifdef THREADED_CLIENT
1687 pthread_mutex_lock(&rwlock);
1692 inline void netio_unlock(void)
1694 #ifdef THREADED_CLIENT
1695 pthread_mutex_unlock(&rwlock);
1700 /* Read a listing from the server up to 000. Append to dest if it exists */
1701 char *CtdlIPCReadListing(char *dest)
1708 if (ret) length = strlen(ret);
1709 while (serv_gets(aaa), strcmp(aaa, "000")) {
1710 ret = (char *)realloc(ret, length + strlen(aaa) + 2);
1712 strcpy(&ret[length], aaa);
1713 length += strlen(aaa);
1714 strcpy(&ret[length++], "\n");
1721 /* Send a listing to the server; generate the ending 000. */
1722 int CtdlIPCSendListing(const char *listing)
1726 text = (char *)malloc(strlen(listing) + 5);
1728 strcpy(text, listing);
1729 if (text[strlen(text) - 1] == '\n')
1730 text[strlen(text) - 1] = '\0';
1731 strcat(text, "000");
1736 /* Malloc failed but we are committed to send */
1737 /* This may result in extra blanks at the bottom */
1745 /* Partial read of file from server */
1746 size_t CtdlIPCPartialRead(void **buf, size_t offset, size_t bytes, char *cret)
1748 register size_t len = 0;
1751 if (!buf) return -1;
1752 if (!cret) return -1;
1753 if (bytes < 1) return -1;
1754 if (offset < 0) return -1;
1757 sprintf(aaa, "READ %d|%d", offset, bytes);
1761 strcpy(cret, &aaa[4]);
1763 len = extract_long(&aaa[4], 0);
1764 *buf = (void *)realloc(*buf, offset + len);
1766 /* I know what I'm doing */
1767 serv_read((char *)&buf[offset], len);
1769 /* We have to read regardless */
1770 serv_read(aaa, len);
1780 int CtdlIPCEndDownload(char *cret)
1784 if (!cret) return -2;
1785 if (!download_in_progress) return -2;
1787 ret = CtdlIPCGenericCommand("CLOS", NULL, 0, NULL, NULL, cret);
1789 download_in_progress = 0;
1795 int CtdlIPCReadDownload(void **buf, size_t bytes, char *cret)
1797 register size_t len;
1799 if (!cret) return -1;
1800 if (!buf) return -1;
1801 if (*buf) return -1;
1802 if (!download_in_progress) return -1;
1805 while (len < bytes) {
1806 len = CtdlIPCPartialRead(buf, len, 4096, cret);
1817 int CtdlIPCEndUpload(char *cret)
1821 if (!cret) return -1;
1822 if (!upload_in_progress) return -1;
1824 ret = CtdlIPCGenericCommand("UCLS", NULL, 0, NULL, NULL, cret);
1826 upload_in_progress = 0;
1832 int CtdlIPCWriteUpload(void *buf, size_t bytes, char *cret)
1834 register int ret = -1;
1835 register size_t offset;
1838 if (!cret) return -1;
1839 if (!buf) return -1;
1840 if (bytes < 1) return -1;
1843 while (offset < bytes) {
1844 sprintf(aaa, "WRIT %d", bytes - offset);
1847 strcpy(cret, &aaa[4]);
1849 if (aaa[0] == '7') {
1850 register size_t to_write;
1852 to_write = extract_long(&aaa[4], 0);
1853 serv_write(buf + offset, to_write);
1864 * Generic command method. This method should handle any server command
1865 * except for CHAT. It takes the following arguments:
1867 * command Preformatted command to send to server
1868 * to_send A text or binary file to send to server
1869 * (only sent if server requests it)
1870 * bytes_to_send The number of bytes in to_send (required if
1871 * sending binary, optional if sending listing)
1872 * to_receive Pointer to a NULL pointer, if the server
1873 * sends text or binary we will allocate memory
1874 * for the file and stuff it here
1875 * bytes_to_receive If a file is received, we will store its
1877 * proto_response The protocol response. Caller must provide
1878 * this buffer and ensure that it is at least
1879 * 128 bytes in length.
1881 * This function returns a number equal to the protocol response number,
1882 * -1 if an internal error occurred, -2 if caller provided bad values,
1883 * or 0 - the protocol response number if bad values were found during
1884 * the protocol exchange.
1885 * It stores the protocol response string (minus the number) in
1886 * protocol_response as described above. Some commands send additional
1887 * data in this string.
1889 int CtdlIPCGenericCommand(const char *command, const char *to_send,
1890 size_t bytes_to_send, char **to_receive,
1891 size_t *bytes_to_receive, char *proto_response)
1896 if (!command) return -2;
1897 if (!proto_response) return -2;
1900 serv_puts((char *)command);
1902 serv_gets(proto_response);
1903 if (proto_response[3] == '*')
1905 ret = atoi(proto_response);
1906 memmove(proto_response, &proto_response[4],
1907 strlen(proto_response) - 3);
1908 switch (ret / 100) {
1909 default: /* Unknown, punt */
1911 case 3: /* MORE_DATA */
1913 /* Don't need to do anything */
1915 case 1: /* LISTING_FOLLOWS */
1916 if (to_receive && !*to_receive && bytes_to_receive) {
1917 *to_receive = CtdlIPCReadListing(NULL);
1918 } else { /* Drain */
1919 while (serv_gets(buf), strcmp(buf, "000")) ;
1923 case 4: /* SEND_LISTING */
1925 CtdlIPCSendListing(to_send);
1927 /* No listing given, fake it */
1932 case 6: /* BINARY_FOLLOWS */
1933 if (to_receive && !*to_receive && bytes_to_receive) {
1935 extract_long(proto_response, 0);
1936 *to_receive = (char *)malloc(*bytes_to_receive);
1940 serv_read(*to_receive,
1947 drain = extract_long(proto_response, 0);
1948 while (drain > SIZ) {
1949 serv_read(buf, SIZ);
1952 serv_read(buf, drain);
1956 case 7: /* SEND_BINARY */
1957 if (to_send && bytes_to_send) {
1958 serv_write((char *)to_send, bytes_to_send);
1959 } else if (bytes_to_send) {
1960 /* Fake it, send nulls */
1963 fake = bytes_to_send;
1964 memset(buf, '\0', SIZ);
1965 while (fake > SIZ) {
1966 serv_write(buf, SIZ);
1969 serv_write(buf, fake);
1971 } /* else who knows? DANGER WILL ROBINSON */
1973 case 8: /* START_CHAT_MODE */
1974 if (!strncasecmp(command, "CHAT", 4)) {
1975 /* Don't call chatmode with generic! */
1979 /* In this mode we send then receive listing */
1981 CtdlIPCSendListing(to_send);
1983 /* No listing given, fake it */
1987 if (to_receive && !*to_receive
1988 && bytes_to_receive) {
1989 *to_receive = CtdlIPCReadListing(NULL);
1990 } else { /* Drain */
1991 while (serv_gets(buf),
1992 strcmp(buf, "000")) ;
1997 case 9: /* ASYNC_MSG */
1998 /* CtdlIPCDoAsync(ret, proto_response); */
1999 free(CtdlIPCReadListing(NULL)); /* STUB FIXME */