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)
386 int multipart_hunting = 0;
387 char multipart_prefix[SIZ];
389 if (!cret) return -1;
390 if (!mret) return -1;
391 if (!*mret) *mret = (struct ctdlipcmessage *)calloc(1, sizeof (struct ctdlipcmessage));
392 if (!*mret) return -1;
393 if (!msgnum) return -1;
395 sprintf(aaa, "MSG%c %ld|%d", as_mime ? '2' : '0', msgnum, headers);
396 ret = CtdlIPCGenericCommand(aaa, NULL, 0, &bbb, &bbbsize, cret);
397 if (ret / 100 == 1) {
399 strcpy(mret[0]->mime_chosen, "1"); /* Default chosen-part is "1" */
400 while (strlen(bbb) > 4 && bbb[4] == '=') {
401 extract_token(aaa, bbb, 0, '\n');
402 remove_token(bbb, 0, '\n');
404 if (!strncasecmp(aaa, "nhdr=yes", 8))
406 else if (!strncasecmp(aaa, "from=", 5))
407 strcpy(mret[0]->author, &aaa[5]);
408 else if (!strncasecmp(aaa, "type=", 5))
409 mret[0]->type = atoi(&aaa[5]);
410 else if (!strncasecmp(aaa, "msgn=", 5))
411 strcpy(mret[0]->msgid, &aaa[5]);
412 else if (!strncasecmp(aaa, "subj=", 5))
413 strcpy(mret[0]->subject, &aaa[5]);
414 else if (!strncasecmp(aaa, "rfca=", 5))
415 strcpy(mret[0]->email, &aaa[5]);
416 else if (!strncasecmp(aaa, "hnod=", 5))
417 strcpy(mret[0]->hnod, &aaa[5]);
418 else if (!strncasecmp(aaa, "room=", 5))
419 strcpy(mret[0]->room, &aaa[5]);
420 else if (!strncasecmp(aaa, "node=", 5))
421 strcpy(mret[0]->node, &aaa[5]);
422 else if (!strncasecmp(aaa, "rcpt=", 5))
423 strcpy(mret[0]->recipient, &aaa[5]);
424 else if (!strncasecmp(aaa, "time=", 5))
425 mret[0]->time = atol(&aaa[5]);
427 /* Multipart/alternative prefix & suffix strings help
428 * us to determine which part we want to download.
430 else if (!strncasecmp(aaa, "pref=", 5)) {
431 extract(multipart_prefix, &aaa[5], 1);
432 if (!strcasecmp(multipart_prefix,
433 "multipart/alternative")) {
437 else if (!strncasecmp(aaa, "suff=", 5)) {
438 extract(multipart_prefix, &aaa[5], 1);
439 if (!strcasecmp(multipart_prefix,
440 "multipart/alternative")) {
445 else if (!strncasecmp(aaa, "part=", 5)) {
446 struct parts *ptr, *chain;
448 ptr = (struct parts *)calloc(1, sizeof (struct parts));
451 /* Fill the buffers for the caller */
452 extract(ptr->name, &aaa[5], 0);
453 extract(ptr->filename, &aaa[5], 1);
454 extract(ptr->number, &aaa[5], 2);
455 extract(ptr->disposition, &aaa[5], 3);
456 extract(ptr->mimetype, &aaa[5], 4);
457 ptr->length = extract_long(&aaa[5], 5);
458 if (!mret[0]->attachments)
459 mret[0]->attachments = ptr;
461 chain = mret[0]->attachments;
467 /* Now handle multipart/alternative */
468 if (multipart_hunting > 0) {
469 if ( (!strcasecmp(ptr->mimetype,
471 || (!strcasecmp(ptr->mimetype,
473 strcpy(mret[0]->mime_chosen,
481 /* Eliminate "text\n" */
482 remove_token(bbb, 0, '\n');
485 /* Strip trailing whitespace */
486 bbb = (char *)realloc(bbb, strlen(bbb) + 1);
488 bbb = (char *)realloc(bbb, 1);
498 int CtdlIPCWhoKnowsRoom(char **listing, char *cret)
503 if (!cret) return -2;
504 if (!listing) return -2;
505 if (*listing) return -2;
507 ret = CtdlIPCGenericCommand("WHOK", NULL, 0, listing, &bytes, cret);
513 int CtdlIPCServerInfo(struct CtdlServInfo *ServInfo, char *cret)
517 char *listing = NULL;
520 if (!cret) return -2;
521 if (!ServInfo) return -2;
523 ret = CtdlIPCGenericCommand("INFO", NULL, 0, &listing, &bytes, cret);
524 if (ret / 100 == 1) {
527 while (*listing && strlen(listing)) {
528 extract_token(buf, listing, 0, '\n');
529 remove_token(listing, 0, '\n');
531 case 0: ServInfo->serv_pid = atoi(buf);
533 case 1: strcpy(ServInfo->serv_nodename,buf);
535 case 2: strcpy(ServInfo->serv_humannode,buf);
537 case 3: strcpy(ServInfo->serv_fqdn,buf);
539 case 4: strcpy(ServInfo->serv_software,buf);
541 case 5: ServInfo->serv_rev_level = atoi(buf);
543 case 6: strcpy(ServInfo->serv_bbs_city,buf);
545 case 7: strcpy(ServInfo->serv_sysadm,buf);
547 case 9: strcpy(ServInfo->serv_moreprompt,buf);
549 case 10: ServInfo->serv_ok_floors = atoi(buf);
551 case 11: ServInfo->serv_paging_level = atoi(buf);
553 case 13: ServInfo->serv_supports_qnop = atoi(buf);
564 int CtdlIPCReadDirectory(char **listing, char *cret)
569 if (!cret) return -2;
570 if (!listing) return -2;
571 if (*listing) return -2;
573 ret = CtdlIPCGenericCommand("RDIR", NULL, 0, listing, &bytes, cret);
579 * Set last-read pointer in this room to msgnum, or 0 for HIGHEST.
581 int CtdlIPCSetLastRead(long msgnum, char *cret)
586 if (!cret) return -2;
589 sprintf(aaa, "SLRP %ld", msgnum);
591 sprintf(aaa, "SLRP HIGHEST");
592 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
598 int CtdlIPCInviteUserToRoom(const char *username, char *cret)
603 if (!cret) return -2;
604 if (!username) return -2;
606 aaa = (char *)malloc(strlen(username) + 6);
609 sprintf(aaa, "INVT %s", username);
610 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
617 int CtdlIPCKickoutUserFromRoom(const char *username, char *cret)
622 if (!cret) return -1;
623 if (!username) return -1;
625 aaa = (char *)malloc(strlen(username) + 6);
627 sprintf(aaa, "KICK %s", username);
628 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
635 int CtdlIPCGetRoomAttributes(struct quickroom **qret, char *cret)
639 if (!cret) return -2;
640 if (!qret) return -2;
641 if (!*qret) *qret = (struct quickroom *)calloc(1, sizeof (struct quickroom));
642 if (!*qret) return -1;
644 ret = CtdlIPCGenericCommand("GETR", NULL, 0, NULL, NULL, cret);
645 if (ret / 100 == 2) {
646 extract(qret[0]->QRname, cret, 0);
647 extract(qret[0]->QRpasswd, cret, 1);
648 extract(qret[0]->QRdirname, cret, 2);
649 qret[0]->QRflags = extract_int(cret, 3);
650 qret[0]->QRfloor = extract_int(cret, 4);
651 qret[0]->QRorder = extract_int(cret, 5);
658 /* set forget to kick all users out of room */
659 int CtdlIPCSetRoomAttributes(int forget, struct quickroom *qret, char *cret)
664 if (!cret) return -2;
665 if (!qret) return -2;
667 aaa = (char *)malloc(strlen(qret->QRname) + strlen(qret->QRpasswd) +
668 strlen(qret->QRdirname) + 52);
671 sprintf(aaa, "SETR %s|%s|%s|%d|%d|%d|%d",
672 qret->QRname, qret->QRpasswd, qret->QRdirname,
673 qret->QRflags, forget, qret->QRfloor, qret->QRorder);
674 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
681 int CtdlIPCGetRoomAide(char *cret)
683 if (!cret) return -1;
685 return CtdlIPCGenericCommand("GETA", NULL, 0, NULL, NULL, cret);
690 int CtdlIPCSetRoomAide(const char *username, char *cret)
695 if (!cret) return -2;
696 if (!username) return -2;
698 aaa = (char *)malloc(strlen(username) + 6);
701 sprintf(aaa, "SETA %s", username);
702 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
709 int CtdlIPCPostMessage(int flag, const struct ctdlipcmessage *mr, char *cret)
714 if (!cret) return -2;
717 aaa = (char *)malloc(strlen(mr->recipient) + strlen(mr->author) + 40);
720 sprintf(aaa, "ENT0 %d|%s|%d|%d|%s", flag, mr->recipient, mr->anonymous,
721 mr->type, mr->author);
722 ret = CtdlIPCGenericCommand(aaa, mr->text, strlen(mr->text), NULL,
730 int CtdlIPCRoomInfo(char **iret, char *cret)
734 if (!cret) return -2;
735 if (!iret) return -2;
736 if (*iret) return -2;
738 return CtdlIPCGenericCommand("RINF", NULL, 0, iret, &bytes, cret);
743 int CtdlIPCDeleteMessage(long msgnum, char *cret)
747 if (!cret) return -2;
748 if (!msgnum) return -2;
750 sprintf(aaa, "DELE %ld", msgnum);
751 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
756 int CtdlIPCMoveMessage(int copy, long msgnum, const char *destroom, char *cret)
761 if (!cret) return -2;
762 if (!destroom) return -2;
763 if (!msgnum) return -2;
765 aaa = (char *)malloc(strlen(destroom) + 28);
768 sprintf(aaa, "MOVE %ld|%s|%d", msgnum, destroom, copy);
769 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
776 int CtdlIPCDeleteRoom(int for_real, char *cret)
780 if (!cret) return -2;
782 sprintf(aaa, "KILL %d", for_real);
783 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
788 int CtdlIPCCreateRoom(int for_real, const char *roomname, int type,
789 const char *password, int floor, char *cret)
794 if (!cret) return -2;
795 if (!roomname) return -2;
798 aaa = (char *)malloc(strlen(roomname) + strlen(password) + 40);
800 sprintf(aaa, "CRE8 %d|%s|%d|%s|%d", for_real, roomname, type,
803 aaa = (char *)malloc(strlen(roomname) + 40);
805 sprintf(aaa, "CRE8 %d|%s|%d||%d", for_real, roomname, type,
808 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
815 int CtdlIPCForgetRoom(char *cret)
817 if (!cret) return -2;
819 return CtdlIPCGenericCommand("FORG", NULL, 0, NULL, NULL, cret);
824 int CtdlIPCSystemMessage(const char *message, char **mret, char *cret)
830 if (!cret) return -2;
831 if (!mret) return -2;
832 if (*mret) return -2;
833 if (!message) return -2;
835 aaa = (char *)malloc(strlen(message) + 6);
838 sprintf(aaa, "MESG %s", message);
839 ret = CtdlIPCGenericCommand(aaa, NULL, 0, mret, &bytes, cret);
846 int CtdlIPCNextUnvalidatedUser(char *cret)
848 if (!cret) return -2;
850 return CtdlIPCGenericCommand("GNUR", NULL, 0, NULL, NULL, cret);
855 int CtdlIPCGetUserRegistration(const char *username, char **rret, char *cret)
861 if (!cret) return -2;
862 if (!rret) return -2;
863 if (*rret) return -2;
866 aaa = (char *)malloc(strlen(username) + 6);
868 aaa = (char *)malloc(12);
872 sprintf(aaa, "GREG %s", username);
874 sprintf(aaa, "GREG _SELF_");
875 ret = CtdlIPCGenericCommand(aaa, NULL, 0, rret, &bytes, cret);
882 int CtdlIPCValidateUser(const char *username, int axlevel, char *cret)
887 if (!cret) return -2;
888 if (!username) return -2;
889 if (axlevel < 0 || axlevel > 7) return -2;
891 aaa = (char *)malloc(strlen(username) + 17);
894 sprintf(aaa, "VALI %s|%d", username, axlevel);
895 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
902 int CtdlIPCSetRoomInfo(int for_real, const char *info, char *cret)
906 if (!cret) return -1;
907 if (!info) return -1;
909 sprintf(aaa, "EINF %d", for_real);
910 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
915 int CtdlIPCUserListing(char **listing, char *cret)
919 if (!cret) return -1;
920 if (!listing) return -1;
921 if (*listing) return -1;
923 return CtdlIPCGenericCommand("LIST", NULL, 0, listing, &bytes, cret);
928 int CtdlIPCSetRegistration(const char *info, char *cret)
930 if (!cret) return -1;
931 if (!info) return -1;
933 return CtdlIPCGenericCommand("REGI", info, strlen(info),
939 int CtdlIPCMiscCheck(struct ctdlipcmisc *chek, char *cret)
943 if (!cret) return -1;
944 if (!chek) return -1;
946 ret = CtdlIPCGenericCommand("CHEK", NULL, 0, NULL, NULL, cret);
947 if (ret / 100 == 2) {
948 chek->newmail = extract_long(cret, 0);
949 chek->needregis = extract_int(cret, 1);
950 chek->needvalid = extract_int(cret, 2);
957 int CtdlIPCDeleteFile(const char *filename, char *cret)
962 if (!cret) return -2;
963 if (!filename) return -2;
965 aaa = (char *)malloc(strlen(filename) + 6);
968 sprintf(aaa, "DELF %s", filename);
969 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
976 int CtdlIPCMoveFile(const char *filename, const char *destroom, char *cret)
981 if (!cret) return -2;
982 if (!filename) return -2;
983 if (!destroom) return -2;
985 aaa = (char *)malloc(strlen(filename) + strlen(destroom) + 7);
988 sprintf(aaa, "MOVF %s|%s", filename, destroom);
989 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
996 int CtdlIPCNetSendFile(const char *filename, const char *destnode, char *cret)
1001 if (!cret) return -2;
1002 if (!filename) return -2;
1003 if (!destnode) return -2;
1005 aaa = (char *)malloc(strlen(filename) + strlen(destnode) + 7);
1006 if (!aaa) return -1;
1008 sprintf(aaa, "NETF %s|%s", filename, destnode);
1009 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1016 int CtdlIPCOnlineUsers(char **listing, time_t *stamp, char *cret)
1021 if (!cret) return -1;
1022 if (!listing) return -1;
1023 if (*listing) return -1;
1025 *stamp = CtdlIPCServerTime(cret);
1027 *stamp = time(NULL);
1028 ret = CtdlIPCGenericCommand("RWHO", NULL, 0, listing, &bytes, cret);
1034 int CtdlIPCFileDownload(const char *filename, void **buf, char *cret)
1042 if (!cret) return -2;
1043 if (!filename) return -2;
1044 if (!buf) return -2;
1045 if (*buf) return -2;
1046 if (download_in_progress) return -2;
1048 aaa = (char *)malloc(strlen(filename) + 6);
1049 if (!aaa) return -1;
1051 sprintf(aaa, "OPEN %s", filename);
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 CtdlIPCAttachmentDownload(long msgnum, const char *part, void **buf,
1081 if (!cret) return -2;
1082 if (!buf) return -2;
1083 if (*buf) return -2;
1084 if (!part) return -2;
1085 if (!msgnum) return -2;
1086 if (download_in_progress) return -2;
1088 aaa = (char *)malloc(strlen(part) + 17);
1089 if (!aaa) return -1;
1091 sprintf(aaa, "OPNA %ld|%s", msgnum, part);
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 CtdlIPCImageDownload(const char *filename, void **buf, char *cret)
1119 if (!cret) return -1;
1120 if (!buf) return -1;
1121 if (*buf) return -1;
1122 if (!filename) return -1;
1123 if (download_in_progress) return -1;
1125 aaa = (char *)malloc(strlen(filename) + 6);
1126 if (!aaa) return -1;
1128 sprintf(aaa, "OIMG %s", filename);
1129 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1131 /* FIXME: Possible race condition */
1132 if (ret / 100 == 2) {
1133 download_in_progress = 1;
1134 bytes = extract_long(cret, 0);
1135 last_mod = extract_int(cret, 1);
1136 extract(mimetype, cret, 2);
1137 ret = CtdlIPCReadDownload(buf, bytes, cret);
1138 ret = CtdlIPCEndDownload(cret);
1140 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1141 filename, mimetype);
1148 int CtdlIPCFileUpload(const char *filename, const char *comment, void *buf,
1149 size_t bytes, char *cret)
1154 if (!cret) return -1;
1155 if (!filename) return -1;
1156 if (!comment) return -1;
1157 if (upload_in_progress) return -1;
1159 aaa = (char *)malloc(strlen(filename) + strlen(comment) + 7);
1160 if (!aaa) return -1;
1162 sprintf(aaa, "UOPN %s|%s", filename, comment);
1163 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1165 /* FIXME: Possible race condition */
1167 upload_in_progress = 1;
1168 ret = CtdlIPCWriteUpload(buf, bytes, cret);
1169 ret = CtdlIPCEndUpload(cret);
1175 int CtdlIPCImageUpload(int for_real, const char *filename, size_t bytes,
1181 if (!cret) return -1;
1182 if (!filename) return -1;
1183 if (upload_in_progress) return -1;
1185 aaa = (char *)malloc(strlen(filename) + 17);
1186 if (!aaa) return -1;
1188 sprintf(aaa, "UIMG %d|%s", for_real, filename);
1189 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1191 /* FIXME: Possible race condition */
1193 upload_in_progress = 1;
1199 int CtdlIPCQueryUsername(const char *username, char *cret)
1204 if (!cret) return -2;
1205 if (!username) return -2;
1207 aaa = (char *)malloc(strlen(username) + 6);
1208 if (!aaa) return -1;
1210 sprintf(aaa, "QUSR %s", username);
1211 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1218 int CtdlIPCFloorListing(char **listing, char *cret)
1222 if (!cret) return -2;
1223 if (!listing) return -2;
1224 if (*listing) return -2;
1226 return CtdlIPCGenericCommand("LFLR", NULL, 0, listing, &bytes, cret);
1231 int CtdlIPCCreateFloor(int for_real, const char *name, char *cret)
1236 if (!cret) return -2;
1237 if (!name) return -2;
1239 aaa = (char *)malloc(strlen(name) + 17);
1240 if (!aaa) return -1;
1242 sprintf(aaa, "CFLR %s|%d", name, for_real);
1243 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1250 int CtdlIPCDeleteFloor(int for_real, int floornum, char *cret)
1254 if (!cret) return -1;
1255 if (floornum < 0) return -1;
1257 sprintf(aaa, "KFLR %d|%d", floornum, for_real);
1258 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1263 int CtdlIPCEditFloor(int floornum, const char *floorname, char *cret)
1268 if (!cret) return -2;
1269 if (!floorname) return -2;
1270 if (floornum < 0) return -2;
1272 aaa = (char *)malloc(strlen(floorname) + 17);
1273 if (!aaa) return -1;
1275 sprintf(aaa, "EFLR %d|%s", floornum, floorname);
1276 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1283 int CtdlIPCIdentifySoftware(int developerid, int clientid, int revision,
1284 const char *software_name, const char *hostname, char *cret)
1289 if (developerid < 0) return -2;
1290 if (clientid < 0) return -2;
1291 if (revision < 0) return -2;
1292 if (!software_name) return -2;
1293 if (!hostname) return -2;
1295 aaa = (char *)malloc(strlen(software_name) + strlen(hostname) + 29);
1296 if (!aaa) return -1;
1298 sprintf(aaa, "IDEN %d|%d|%d|%s|%s", developerid, clientid,
1299 revision, software_name, hostname);
1300 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1307 int CtdlIPCSendInstantMessage(const char *username, const char *text,
1313 if (!cret) return -2;
1314 if (!username) return -2;
1316 aaa = (char *)malloc(strlen(username) + 8);
1317 if (!aaa) return -1;
1320 sprintf(aaa, "SEXP %s|-", username);
1321 ret = CtdlIPCGenericCommand(aaa, text, strlen(text),
1324 sprintf(aaa, "SEXP %s||", username);
1325 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1333 int CtdlIPCGetInstantMessage(char **listing, char *cret)
1337 if (!cret) return -2;
1338 if (!listing) return -2;
1339 if (*listing) return -2;
1341 return CtdlIPCGenericCommand("GEXP", NULL, 0, listing, &bytes, cret);
1346 /* mode is 0 = enable, 1 = disable, 2 = status */
1347 int CtdlIPCEnableInstantMessageReceipt(int mode, char *cret)
1351 if (!cret) return -2;
1353 sprintf(aaa, "DEXP %d", mode);
1354 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1359 int CtdlIPCSetBio(char *bio, char *cret)
1361 if (!cret) return -2;
1362 if (!bio) return -2;
1364 return CtdlIPCGenericCommand("EBIO", bio, strlen(bio),
1370 int CtdlIPCGetBio(const char *username, char **listing, char *cret)
1376 if (!cret) return -2;
1377 if (!username) return -2;
1378 if (!listing) return -2;
1379 if (*listing) return -2;
1381 aaa = (char *)malloc(strlen(username) + 6);
1382 if (!aaa) return -1;
1384 sprintf(aaa, "RBIO %s", username);
1385 ret = CtdlIPCGenericCommand(aaa, NULL, 0, listing, &bytes, cret);
1392 int CtdlIPCListUsersWithBios(char **listing, char *cret)
1396 if (!cret) return -2;
1397 if (!listing) return -2;
1398 if (*listing) return -2;
1400 return CtdlIPCGenericCommand("LBIO", NULL, 0, listing, &bytes, cret);
1405 int CtdlIPCStealthMode(int mode, char *cret)
1409 if (!cret) return -1;
1411 sprintf(aaa, "STEL %d", mode ? 1 : 0);
1412 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1417 int CtdlIPCTerminateSession(int sid, char *cret)
1421 if (!cret) return -1;
1423 sprintf(aaa, "TERM %d", sid);
1424 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1429 int CtdlIPCTerminateServerNow(char *cret)
1431 if (!cret) return -1;
1433 return CtdlIPCGenericCommand("DOWN", NULL, 0, NULL, NULL, cret);
1438 int CtdlIPCTerminateServerScheduled(int mode, char *cret)
1442 if (!cret) return -1;
1444 sprintf(aaa, "SCDN %d", mode ? 1 : 0);
1445 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1450 int CtdlIPCEnterSystemMessage(const char *filename, const char *text,
1456 if (!cret) return -2;
1457 if (!text) return -2;
1458 if (!filename) return -2;
1460 aaa = (char *)malloc(strlen(filename) + 6);
1461 if (!aaa) return -1;
1463 sprintf(aaa, "EMSG %s", filename);
1464 ret = CtdlIPCGenericCommand(aaa, text, strlen(text), NULL, NULL, cret);
1471 int CtdlIPCChangeHostname(const char *hostname, char *cret)
1476 if (!cret) return -2;
1477 if (!hostname) return -2;
1479 aaa = (char *)malloc(strlen(hostname) + 6);
1480 if (!aaa) return -1;
1482 sprintf(aaa, "HCHG %s", hostname);
1483 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1490 int CtdlIPCChangeRoomname(const char *roomname, char *cret)
1495 if (!cret) return -2;
1496 if (!roomname) return -2;
1498 aaa = (char *)malloc(strlen(roomname) + 6);
1499 if (!aaa) return -1;
1501 sprintf(aaa, "RCHG %s", roomname);
1502 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1509 int CtdlIPCChangeUsername(const char *username, char *cret)
1514 if (!cret) return -2;
1515 if (!username) return -2;
1517 aaa = (char *)malloc(strlen(username) + 6);
1518 if (!aaa) return -1;
1520 sprintf(aaa, "UCHG %s", username);
1521 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1528 /* This function returns the actual server time reported, or 0 if error */
1529 time_t CtdlIPCServerTime(char *cret)
1531 register time_t tret;
1534 ret = CtdlIPCGenericCommand("TIME", NULL, 0, NULL, NULL, cret);
1535 if (ret / 100 == 2) {
1536 tret = extract_long(cret, 0);
1545 int CtdlIPCAideGetUserParameters(const char *who,
1546 struct usersupp **uret, char *cret)
1551 if (!cret) return -2;
1552 if (!uret) return -2;
1553 if (!*uret) *uret = (struct usersupp *)calloc(1, sizeof(struct usersupp));
1554 if (!*uret) return -1;
1556 aaa = (char *)malloc(strlen(uret[0]->fullname) + 6);
1557 if (!aaa) return -1;
1559 sprintf(aaa, "AGUP %s", who);
1560 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1561 if (ret / 100 == 2) {
1562 extract(uret[0]->fullname, cret, 0);
1563 extract(uret[0]->password, cret, 1);
1564 uret[0]->flags = extract_int(cret, 2);
1565 uret[0]->timescalled = extract_long(cret, 3);
1566 uret[0]->posted = extract_long(cret, 4);
1567 uret[0]->axlevel = extract_int(cret, 5);
1568 uret[0]->usernum = extract_long(cret, 6);
1569 uret[0]->lastcall = extract_long(cret, 7);
1570 uret[0]->USuserpurge = extract_int(cret, 8);
1578 int CtdlIPCAideSetUserParameters(const struct usersupp *uret, char *cret)
1583 if (!cret) return -2;
1584 if (!uret) return -2;
1586 aaa = (char *)malloc(strlen(uret->fullname) + strlen(uret->password) + 84);
1587 if (!aaa) return -1;
1589 sprintf(aaa, "ASUP %s|%s|%d|%ld|%ld|%d|%ld|%ld|%d",
1590 uret->fullname, uret->password, uret->flags,
1591 uret->timescalled, uret->posted, uret->axlevel,
1592 uret->usernum, uret->lastcall, uret->USuserpurge);
1593 ret = CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1600 /* which is 0 = room, 1 = floor, 2 = site */
1601 int CtdlIPCGetMessageExpirationPolicy(int which, char *cret)
1603 static char *proto[] = {"room", "floor", "site"};
1606 if (!cret) return -2;
1607 if (which < 0 || which > 2) return -2;
1609 sprintf(aaa, "GPEX %s", proto[which]);
1610 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1615 /* which is 0 = room, 1 = floor, 2 = site */
1616 /* policy is 0 = inherit, 1 = no purge, 2 = by count, 3 = by age (days) */
1617 int CtdlIPCSetMessageExpirationPolicy(int which, int policy, int value,
1622 if (!cret) return -2;
1623 if (which < 0 || which > 2) return -2;
1624 if (policy < 0 || policy > 3) return -2;
1625 if (policy >= 2 && value < 1) return -2;
1627 sprintf(aaa, "SPEX %d|%d|%d", which, policy, value);
1628 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1633 int CtdlGetSystemConfig(char **listing, char *cret)
1637 if (!cret) return -2;
1638 if (!listing) return -2;
1639 if (*listing) return -2;
1641 return CtdlIPCGenericCommand("CONF GET", NULL, 0,
1642 listing, &bytes, cret);
1647 int CtdlSetSystemConfig(const char *listing, char *cret)
1649 if (!cret) return -2;
1650 if (!listing) return -2;
1652 return CtdlIPCGenericCommand("CONF SET", listing, strlen(listing),
1658 int CtdlIPCModerateMessage(long msgnum, int level, char *cret)
1662 if (!cret) return -2;
1663 if (!msgnum) return -2;
1665 sprintf(aaa, "MMOD %ld|%d", msgnum, level);
1666 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1671 int CtdlIPCRequestClientLogout(int session, char *cret)
1675 if (!cret) return -2;
1676 if (session < 0) return -2;
1678 sprintf(aaa, "REQT %d", session);
1679 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1684 int CtdlIPCSetMessageSeen(long msgnum, int seen, char *cret)
1688 if (!cret) return -2;
1689 if (msgnum < 0) return -2;
1691 sprintf(aaa, "SEEN %ld|%d", msgnum, seen ? 1 : 0);
1692 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1697 int CtdlIPCStartEncryption(char *cret)
1699 return CtdlIPCGenericCommand("STLS", NULL, 0, NULL, NULL, cret);
1704 int CtdlIPCDirectoryLookup(const char *address, char *cret)
1708 if (!address) return -2;
1709 if (!cret) return -2;
1711 aaa = (char *)malloc(strlen(address) + 6);
1712 if (!aaa) return -1;
1714 sprintf(aaa, "QDIR %s", address);
1715 return CtdlIPCGenericCommand(aaa, NULL, 0, NULL, NULL, cret);
1737 /* ************************************************************************** */
1738 /* Stuff below this line is not for public consumption */
1739 /* ************************************************************************** */
1742 inline void netio_lock(void)
1744 #ifdef THREADED_CLIENT
1745 pthread_mutex_lock(&rwlock);
1750 inline void netio_unlock(void)
1752 #ifdef THREADED_CLIENT
1753 pthread_mutex_unlock(&rwlock);
1758 /* Read a listing from the server up to 000. Append to dest if it exists */
1759 char *CtdlIPCReadListing(char *dest)
1766 if (ret) length = strlen(ret);
1767 while (serv_gets(aaa), strcmp(aaa, "000")) {
1768 ret = (char *)realloc(ret, length + strlen(aaa) + 2);
1770 strcpy(&ret[length], aaa);
1771 length += strlen(aaa);
1772 strcpy(&ret[length++], "\n");
1779 /* Send a listing to the server; generate the ending 000. */
1780 int CtdlIPCSendListing(const char *listing)
1784 text = (char *)malloc(strlen(listing) + 6);
1786 strcpy(text, listing);
1787 while (text[strlen(text) - 1] == '\n')
1788 text[strlen(text) - 1] = '\0';
1789 strcat(text, "\n000");
1794 /* Malloc failed but we are committed to send */
1795 /* This may result in extra blanks at the bottom */
1803 /* Partial read of file from server */
1804 size_t CtdlIPCPartialRead(void **buf, size_t offset, size_t bytes, char *cret)
1806 register size_t len = 0;
1809 if (!buf) return -1;
1810 if (!cret) return -1;
1811 if (bytes < 1) return -1;
1812 if (offset < 0) return -1;
1815 sprintf(aaa, "READ %d|%d", offset, bytes);
1819 strcpy(cret, &aaa[4]);
1821 len = extract_long(&aaa[4], 0);
1822 *buf = (void *)realloc(*buf, offset + len);
1824 /* I know what I'm doing */
1825 serv_read((char *)&buf[offset], len);
1827 /* We have to read regardless */
1828 serv_read(aaa, len);
1838 int CtdlIPCEndDownload(char *cret)
1842 if (!cret) return -2;
1843 if (!download_in_progress) return -2;
1845 ret = CtdlIPCGenericCommand("CLOS", NULL, 0, NULL, NULL, cret);
1847 download_in_progress = 0;
1853 int CtdlIPCReadDownload(void **buf, size_t bytes, char *cret)
1855 register size_t len;
1857 if (!cret) return -1;
1858 if (!buf) return -1;
1859 if (*buf) return -1;
1860 if (!download_in_progress) return -1;
1863 while (len < bytes) {
1864 len = CtdlIPCPartialRead(buf, len, 4096, cret);
1875 int CtdlIPCEndUpload(char *cret)
1879 if (!cret) return -1;
1880 if (!upload_in_progress) return -1;
1882 ret = CtdlIPCGenericCommand("UCLS", NULL, 0, NULL, NULL, cret);
1884 upload_in_progress = 0;
1890 int CtdlIPCWriteUpload(void *buf, size_t bytes, char *cret)
1892 register int ret = -1;
1893 register size_t offset;
1896 if (!cret) return -1;
1897 if (!buf) return -1;
1898 if (bytes < 1) return -1;
1901 while (offset < bytes) {
1902 sprintf(aaa, "WRIT %d", bytes - offset);
1905 strcpy(cret, &aaa[4]);
1907 if (aaa[0] == '7') {
1908 register size_t to_write;
1910 to_write = extract_long(&aaa[4], 0);
1911 serv_write(buf + offset, to_write);
1922 * Generic command method. This method should handle any server command
1923 * except for CHAT. It takes the following arguments:
1925 * command Preformatted command to send to server
1926 * to_send A text or binary file to send to server
1927 * (only sent if server requests it)
1928 * bytes_to_send The number of bytes in to_send (required if
1929 * sending binary, optional if sending listing)
1930 * to_receive Pointer to a NULL pointer, if the server
1931 * sends text or binary we will allocate memory
1932 * for the file and stuff it here
1933 * bytes_to_receive If a file is received, we will store its
1935 * proto_response The protocol response. Caller must provide
1936 * this buffer and ensure that it is at least
1937 * 128 bytes in length.
1939 * This function returns a number equal to the protocol response number,
1940 * -1 if an internal error occurred, -2 if caller provided bad values,
1941 * or 0 - the protocol response number if bad values were found during
1942 * the protocol exchange.
1943 * It stores the protocol response string (minus the number) in
1944 * protocol_response as described above. Some commands send additional
1945 * data in this string.
1947 int CtdlIPCGenericCommand(const char *command, const char *to_send,
1948 size_t bytes_to_send, char **to_receive,
1949 size_t *bytes_to_receive, char *proto_response)
1954 if (!command) return -2;
1955 if (!proto_response) return -2;
1958 serv_puts((char *)command);
1960 serv_gets(proto_response);
1961 if (proto_response[3] == '*')
1963 ret = atoi(proto_response);
1964 memmove(proto_response, &proto_response[4],
1965 strlen(proto_response) - 3);
1966 switch (ret / 100) {
1967 default: /* Unknown, punt */
1969 case 3: /* MORE_DATA */
1971 /* Don't need to do anything */
1973 case 1: /* LISTING_FOLLOWS */
1974 if (to_receive && !*to_receive && bytes_to_receive) {
1975 *to_receive = CtdlIPCReadListing(NULL);
1976 } else { /* Drain */
1977 while (serv_gets(buf), strcmp(buf, "000")) ;
1981 case 4: /* SEND_LISTING */
1983 CtdlIPCSendListing(to_send);
1985 /* No listing given, fake it */
1990 case 6: /* BINARY_FOLLOWS */
1991 if (to_receive && !*to_receive && bytes_to_receive) {
1993 extract_long(proto_response, 0);
1994 *to_receive = (char *)malloc(*bytes_to_receive);
1998 serv_read(*to_receive,
2005 drain = extract_long(proto_response, 0);
2006 while (drain > SIZ) {
2007 serv_read(buf, SIZ);
2010 serv_read(buf, drain);
2014 case 7: /* SEND_BINARY */
2015 if (to_send && bytes_to_send) {
2016 serv_write((char *)to_send, bytes_to_send);
2017 } else if (bytes_to_send) {
2018 /* Fake it, send nulls */
2021 fake = bytes_to_send;
2022 memset(buf, '\0', SIZ);
2023 while (fake > SIZ) {
2024 serv_write(buf, SIZ);
2027 serv_write(buf, fake);
2029 } /* else who knows? DANGER WILL ROBINSON */
2031 case 8: /* START_CHAT_MODE */
2032 if (!strncasecmp(command, "CHAT", 4)) {
2033 /* Don't call chatmode with generic! */
2037 /* In this mode we send then receive listing */
2039 CtdlIPCSendListing(to_send);
2041 /* No listing given, fake it */
2045 if (to_receive && !*to_receive
2046 && bytes_to_receive) {
2047 *to_receive = CtdlIPCReadListing(NULL);
2048 } else { /* Drain */
2049 while (serv_gets(buf),
2050 strcmp(buf, "000")) ;
2055 case 9: /* ASYNC_MSG */
2056 /* CtdlIPCDoAsync(ret, proto_response); */
2057 free(CtdlIPCReadListing(NULL)); /* STUB FIXME */