15 #include <sys/types.h>
20 #ifdef THREADED_CLIENT
24 #include "citadel_ipc.h"
25 #include "citadel_decls.h"
26 #include "client_crypto.h"
29 #ifdef THREADED_CLIENT
30 pthread_mutex_t rwlock;
32 char express_msgs = 0;
34 static volatile int download_in_progress = 0; /* download file open */
35 static volatile int upload_in_progress = 0; /* upload file open */
36 /* static volatile int serv_sock; */ /* Socket on which we talk to server */
40 * Does nothing. The server should always return 200.
42 int CtdlIPCNoop(CtdlIPC *ipc)
46 return CtdlIPCGenericCommand(ipc, "NOOP", NULL, 0, NULL, NULL, aaa);
51 * Does nothing interesting. The server should always return 200
52 * along with your string.
54 int CtdlIPCEcho(CtdlIPC *ipc, const char *arg, char *cret)
62 aaa = (char *)malloc((size_t)(strlen(arg) + 6));
65 sprintf(aaa, "ECHO %s", arg);
66 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
73 * Asks the server to close the connecction.
74 * Should always return 200.
76 int CtdlIPCQuit(CtdlIPC *ipc)
82 CtdlIPC_putline(ipc, "QUIT");
83 CtdlIPC_getline(ipc, aaa);
91 * Asks the server to logout. Should always return 200, even if no user
92 * was logged in. The user will not be logged in after this!
94 int CtdlIPCLogout(CtdlIPC *ipc)
100 CtdlIPC_putline(ipc, "LOUT");
101 CtdlIPC_getline(ipc, aaa);
109 * First stage of authentication - pass the username. Returns 300 if the
110 * username is able to log in, with the username correctly spelled in cret.
111 * Returns various 500 error codes if the user doesn't exist, etc.
113 int CtdlIPCTryLogin(CtdlIPC *ipc, const char *username, char *cret)
118 if (!username) return -2;
119 if (!cret) return -2;
121 aaa = (char *)malloc((size_t)(strlen(username) + 6));
124 sprintf(aaa, "USER %s", username);
125 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
132 * Second stage of authentication - provide password. The server returns
133 * 200 and several arguments in cret relating to the user's account.
135 int CtdlIPCTryPassword(CtdlIPC *ipc, const char *passwd, char *cret)
140 if (!passwd) return -2;
141 if (!cret) return -2;
143 aaa = (char *)malloc((size_t)(strlen(passwd) + 6));
146 sprintf(aaa, "PASS %s", passwd);
147 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
154 * Create a new user. This returns 200 plus the same arguments as TryPassword
155 * if selfservice is nonzero, unless there was a problem creating the account.
156 * If selfservice is zero, creates a new user but does not log out the existing
157 * user - intended for use by system administrators to create accounts on
158 * behalf of other users.
160 int CtdlIPCCreateUser(CtdlIPC *ipc, const char *username, int selfservice, char *cret)
165 if (!username) return -2;
166 if (!cret) return -2;
168 aaa = (char *)malloc((size_t)(strlen(username) + 6));
171 sprintf(aaa, "%s %s", selfservice ? "NEWU" : "CREU", username);
172 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
179 * Changes the user's password. Returns 200 if changed, errors otherwise.
181 int CtdlIPCChangePassword(CtdlIPC *ipc, const char *passwd, char *cret)
186 if (!passwd) return -2;
187 if (!cret) return -2;
189 aaa = (char *)malloc((size_t)(strlen(passwd) + 6));
192 sprintf(aaa, "SETP %s", passwd);
193 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
200 /* Caller must free the march list */
201 /* which is 0 = LRMS, 1 = LKRN, 2 = LKRO, 3 = LKRA, 4 = LZRM */
202 /* floor is -1 for all, or floornum */
203 int CtdlIPCKnownRooms(CtdlIPC *ipc, int which, int floor, struct march **listing, char *cret)
206 struct march *march = NULL;
207 static char *proto[] = {"LRMS", "LKRN", "LKRO", "LKRA", "LZRM" };
212 if (!listing) return -2;
213 if (*listing) return -2; /* Free the listing first */
214 if (!cret) return -2;
215 if (which < 0 || which > 4) return -2;
216 if (floor < -1) return -2; /* Can't validate upper bound, sorry */
218 sprintf(aaa, "%s %d", proto[which], floor);
219 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, &bbb, &bbbsize, cret);
220 if (ret / 100 == 1) {
223 while (bbb && strlen(bbb)) {
226 extract_token(aaa, bbb, 0, '\n');
228 memmove(bbb, bbb + a + 1, strlen(bbb) - a);
229 mptr = (struct march *) malloc(sizeof (struct march));
232 extract(mptr->march_name, aaa, 0);
233 mptr->march_floor = (char) extract_int(aaa, 2);
234 mptr->march_order = (char) extract_int(aaa, 3);
241 while (mptr2->next != NULL)
254 /* Caller must free the struct usersupp; caller may pass an existing one */
255 int CtdlIPCGetConfig(CtdlIPC *ipc, struct usersupp **uret, char *cret)
259 if (!cret) return -2;
260 if (!uret) return -2;
261 if (!*uret) *uret = (struct usersupp *)calloc(1, sizeof (struct usersupp));
262 if (!*uret) return -1;
264 ret = CtdlIPCGenericCommand(ipc, "GETU", NULL, 0, NULL, NULL, cret);
265 if (ret / 100 == 2) {
266 uret[0]->USscreenwidth = extract_int(cret, 0);
267 uret[0]->USscreenheight = extract_int(cret, 1);
268 uret[0]->flags = extract_int(cret, 2);
275 int CtdlIPCSetConfig(CtdlIPC *ipc, struct usersupp *uret, char *cret)
279 if (!uret) return -2;
280 if (!cret) return -2;
282 sprintf(aaa, "SETU %d|%d|%d",
283 uret->USscreenwidth, uret->USscreenheight,
285 return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
290 int CtdlIPCGotoRoom(CtdlIPC *ipc, const char *room, const char *passwd,
291 struct ctdlipcroom **rret, char *cret)
296 if (!cret) return -2;
297 if (!rret) return -2;
298 if (!*rret) *rret = (struct ctdlipcroom *)calloc(1, sizeof (struct ctdlipcroom));
299 if (!*rret) return -1;
302 aaa = (char *)malloc(strlen(room) + strlen(passwd) + 7);
307 sprintf(aaa, "GOTO %s|%s", room, passwd);
309 aaa = (char *)malloc(strlen(room) + 6);
314 sprintf(aaa, "GOTO %s", room);
316 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
317 if (ret / 100 == 2) {
318 extract(rret[0]->RRname, cret, 0);
319 rret[0]->RRunread = extract_long(cret, 1);
320 rret[0]->RRtotal = extract_long(cret, 2);
321 rret[0]->RRinfoupdated = extract_int(cret, 3);
322 rret[0]->RRflags = extract_int(cret, 4);
323 rret[0]->RRhighest = extract_long(cret, 5);
324 rret[0]->RRlastread = extract_long(cret, 6);
325 rret[0]->RRismailbox = extract_int(cret, 7);
326 rret[0]->RRaide = extract_int(cret, 8);
327 rret[0]->RRnewmail = extract_long(cret, 9);
328 rret[0]->RRfloor = extract_int(cret, 10);
337 /* which is 0 = all, 1 = old, 2 = new, 3 = last, 4 = first, 5 = gt, 6 = lt */
338 /* whicharg is number of messages, applies to last, first, gt, lt */
339 int CtdlIPCGetMessages(CtdlIPC *ipc, int which, int whicharg, const char *template,
340 long **mret, char *cret)
343 register long count = 0;
344 static char *proto[] =
345 { "ALL", "OLD", "NEW", "LAST", "FIRST", "GT", "LT" };
350 if (!cret) return -2;
351 if (!mret) return -2;
352 if (*mret) return -2;
353 if (which < 0 || which > 6) return -2;
356 sprintf(aaa, "MSGS %s||%d", proto[which],
359 sprintf(aaa, "MSGS %s|%d|%d", proto[which], whicharg,
361 if (template) count = strlen(template);
362 ret = CtdlIPCGenericCommand(ipc, aaa, template, count, &bbb, &bbbsize, cret);
364 while (strlen(bbb)) {
367 extract_token(aaa, bbb, 0, '\n');
369 memmove(aaa, bbb + a + 1, strlen(bbb) - a - 1);
370 *mret = (long *)realloc(mret,
371 (size_t)((count + 1) * sizeof (long)));
373 *mret[count++] = atol(aaa);
381 int CtdlIPCGetSingleMessage(CtdlIPC *ipc, long msgnum, int headers, int as_mime,
382 struct ctdlipcmessage **mret, char *cret)
388 int multipart_hunting = 0;
389 char multipart_prefix[SIZ];
391 if (!cret) return -1;
392 if (!mret) return -1;
393 if (!*mret) *mret = (struct ctdlipcmessage *)calloc(1, sizeof (struct ctdlipcmessage));
394 if (!*mret) return -1;
395 if (!msgnum) return -1;
397 strcpy(mret[0]->content_type, "");
398 sprintf(aaa, "MSG%d %ld|%d", as_mime, msgnum, headers);
399 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, &bbb, &bbbsize, cret);
400 if (ret / 100 == 1) {
402 strcpy(mret[0]->mime_chosen, "1"); /* Default chosen-part is "1" */
403 while (strlen(bbb) > 4 && bbb[4] == '=') {
404 extract_token(aaa, bbb, 0, '\n');
405 remove_token(bbb, 0, '\n');
407 if (!strncasecmp(aaa, "nhdr=yes", 8))
409 else if (!strncasecmp(aaa, "from=", 5))
410 strcpy(mret[0]->author, &aaa[5]);
411 else if (!strncasecmp(aaa, "type=", 5))
412 mret[0]->type = atoi(&aaa[5]);
413 else if (!strncasecmp(aaa, "msgn=", 5))
414 strcpy(mret[0]->msgid, &aaa[5]);
415 else if (!strncasecmp(aaa, "subj=", 5))
416 strcpy(mret[0]->subject, &aaa[5]);
417 else if (!strncasecmp(aaa, "rfca=", 5))
418 strcpy(mret[0]->email, &aaa[5]);
419 else if (!strncasecmp(aaa, "hnod=", 5))
420 strcpy(mret[0]->hnod, &aaa[5]);
421 else if (!strncasecmp(aaa, "room=", 5))
422 strcpy(mret[0]->room, &aaa[5]);
423 else if (!strncasecmp(aaa, "node=", 5))
424 strcpy(mret[0]->node, &aaa[5]);
425 else if (!strncasecmp(aaa, "rcpt=", 5))
426 strcpy(mret[0]->recipient, &aaa[5]);
427 else if (!strncasecmp(aaa, "time=", 5))
428 mret[0]->time = atol(&aaa[5]);
430 /* Multipart/alternative prefix & suffix strings help
431 * us to determine which part we want to download.
433 else if (!strncasecmp(aaa, "pref=", 5)) {
434 extract(multipart_prefix, &aaa[5], 1);
435 if (!strcasecmp(multipart_prefix,
436 "multipart/alternative")) {
440 else if (!strncasecmp(aaa, "suff=", 5)) {
441 extract(multipart_prefix, &aaa[5], 1);
442 if (!strcasecmp(multipart_prefix,
443 "multipart/alternative")) {
448 else if (!strncasecmp(aaa, "part=", 5)) {
449 struct parts *ptr, *chain;
451 ptr = (struct parts *)calloc(1, sizeof (struct parts));
454 /* Fill the buffers for the caller */
455 extract(ptr->name, &aaa[5], 0);
456 extract(ptr->filename, &aaa[5], 1);
457 extract(ptr->number, &aaa[5], 2);
458 extract(ptr->disposition, &aaa[5], 3);
459 extract(ptr->mimetype, &aaa[5], 4);
460 ptr->length = extract_long(&aaa[5], 5);
461 if (!mret[0]->attachments)
462 mret[0]->attachments = ptr;
464 chain = mret[0]->attachments;
470 /* Now handle multipart/alternative */
471 if (multipart_hunting > 0) {
472 if ( (!strcasecmp(ptr->mimetype,
474 || (!strcasecmp(ptr->mimetype,
476 strcpy(mret[0]->mime_chosen,
484 /* Eliminate "text\n" */
485 remove_token(bbb, 0, '\n');
487 /* If doing a MIME thing, pull out the extra headers */
490 if (!strncasecmp(bbb, "Content-type: ", 14)) {
491 extract_token(mret[0]->content_type, bbb, 0, '\n');
492 strcpy(mret[0]->content_type,
493 &mret[0]->content_type[14]);
494 striplt(mret[0]->content_type);
496 remove_token(bbb, 0, '\n');
497 } while ((bbb[0] != 0) && (bbb[0] != '\n'));
503 /* Strip trailing whitespace */
504 bbb = (char *)realloc(bbb, (size_t)(strlen(bbb) + 1));
506 bbb = (char *)realloc(bbb, 1);
516 int CtdlIPCWhoKnowsRoom(CtdlIPC *ipc, char **listing, char *cret)
521 if (!cret) return -2;
522 if (!listing) return -2;
523 if (*listing) return -2;
525 ret = CtdlIPCGenericCommand(ipc, "WHOK", NULL, 0, listing, &bytes, cret);
531 int CtdlIPCServerInfo(CtdlIPC *ipc, struct CtdlServInfo *ServInfo, char *cret)
535 char *listing = NULL;
538 if (!cret) return -2;
539 if (!ServInfo) return -2;
541 ret = CtdlIPCGenericCommand(ipc, "INFO", NULL, 0, &listing, &bytes, cret);
542 if (ret / 100 == 1) {
545 while (*listing && strlen(listing)) {
546 extract_token(buf, listing, 0, '\n');
547 remove_token(listing, 0, '\n');
549 case 0: ServInfo->serv_pid = atoi(buf);
551 case 1: strcpy(ServInfo->serv_nodename,buf);
553 case 2: strcpy(ServInfo->serv_humannode,buf);
555 case 3: strcpy(ServInfo->serv_fqdn,buf);
557 case 4: strcpy(ServInfo->serv_software,buf);
559 case 5: ServInfo->serv_rev_level = atoi(buf);
561 case 6: strcpy(ServInfo->serv_bbs_city,buf);
563 case 7: strcpy(ServInfo->serv_sysadm,buf);
565 case 9: strcpy(ServInfo->serv_moreprompt,buf);
567 case 10: ServInfo->serv_ok_floors = atoi(buf);
569 case 11: ServInfo->serv_paging_level = atoi(buf);
571 case 13: ServInfo->serv_supports_qnop = atoi(buf);
582 int CtdlIPCReadDirectory(CtdlIPC *ipc, char **listing, char *cret)
587 if (!cret) return -2;
588 if (!listing) return -2;
589 if (*listing) return -2;
591 ret = CtdlIPCGenericCommand(ipc, "RDIR", NULL, 0, listing, &bytes, cret);
597 * Set last-read pointer in this room to msgnum, or 0 for HIGHEST.
599 int CtdlIPCSetLastRead(CtdlIPC *ipc, long msgnum, char *cret)
604 if (!cret) return -2;
607 sprintf(aaa, "SLRP %ld", msgnum);
609 sprintf(aaa, "SLRP HIGHEST");
610 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
616 int CtdlIPCInviteUserToRoom(CtdlIPC *ipc, const char *username, char *cret)
621 if (!cret) return -2;
622 if (!username) return -2;
624 aaa = (char *)malloc(strlen(username) + 6);
627 sprintf(aaa, "INVT %s", username);
628 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
635 int CtdlIPCKickoutUserFromRoom(CtdlIPC *ipc, const char *username, char *cret)
640 if (!cret) return -1;
641 if (!username) return -1;
643 aaa = (char *)malloc(strlen(username) + 6);
645 sprintf(aaa, "KICK %s", username);
646 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
653 int CtdlIPCGetRoomAttributes(CtdlIPC *ipc, struct quickroom **qret, char *cret)
657 if (!cret) return -2;
658 if (!qret) return -2;
659 if (!*qret) *qret = (struct quickroom *)calloc(1, sizeof (struct quickroom));
660 if (!*qret) return -1;
662 ret = CtdlIPCGenericCommand(ipc, "GETR", NULL, 0, NULL, NULL, cret);
663 if (ret / 100 == 2) {
664 extract(qret[0]->QRname, cret, 0);
665 extract(qret[0]->QRpasswd, cret, 1);
666 extract(qret[0]->QRdirname, cret, 2);
667 qret[0]->QRflags = extract_int(cret, 3);
668 qret[0]->QRfloor = extract_int(cret, 4);
669 qret[0]->QRorder = extract_int(cret, 5);
676 /* set forget to kick all users out of room */
677 int CtdlIPCSetRoomAttributes(CtdlIPC *ipc, int forget, struct quickroom *qret, char *cret)
682 if (!cret) return -2;
683 if (!qret) return -2;
685 aaa = (char *)malloc(strlen(qret->QRname) + strlen(qret->QRpasswd) +
686 strlen(qret->QRdirname) + 52);
689 sprintf(aaa, "SETR %s|%s|%s|%d|%d|%d|%d",
690 qret->QRname, qret->QRpasswd, qret->QRdirname,
691 qret->QRflags, forget, qret->QRfloor, qret->QRorder);
692 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
699 int CtdlIPCGetRoomAide(CtdlIPC *ipc, char *cret)
701 if (!cret) return -1;
703 return CtdlIPCGenericCommand(ipc, "GETA", NULL, 0, NULL, NULL, cret);
708 int CtdlIPCSetRoomAide(CtdlIPC *ipc, const char *username, char *cret)
713 if (!cret) return -2;
714 if (!username) return -2;
716 aaa = (char *)malloc(strlen(username) + 6);
719 sprintf(aaa, "SETA %s", username);
720 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
727 int CtdlIPCPostMessage(CtdlIPC *ipc, int flag, const struct ctdlipcmessage *mr, char *cret)
732 if (!cret) return -2;
735 aaa = (char *)malloc(strlen(mr->recipient) + strlen(mr->author) + 40);
738 sprintf(aaa, "ENT0 %d|%s|%d|%d|%s", flag, mr->recipient, mr->anonymous,
739 mr->type, mr->author);
740 ret = CtdlIPCGenericCommand(ipc, aaa, mr->text, strlen(mr->text), NULL,
748 int CtdlIPCRoomInfo(CtdlIPC *ipc, char **iret, char *cret)
752 if (!cret) return -2;
753 if (!iret) return -2;
754 if (*iret) return -2;
756 return CtdlIPCGenericCommand(ipc, "RINF", NULL, 0, iret, &bytes, cret);
761 int CtdlIPCDeleteMessage(CtdlIPC *ipc, long msgnum, char *cret)
765 if (!cret) return -2;
766 if (!msgnum) return -2;
768 sprintf(aaa, "DELE %ld", msgnum);
769 return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
774 int CtdlIPCMoveMessage(CtdlIPC *ipc, int copy, long msgnum, const char *destroom, char *cret)
779 if (!cret) return -2;
780 if (!destroom) return -2;
781 if (!msgnum) return -2;
783 aaa = (char *)malloc(strlen(destroom) + 28);
786 sprintf(aaa, "MOVE %ld|%s|%d", msgnum, destroom, copy);
787 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
794 int CtdlIPCDeleteRoom(CtdlIPC *ipc, int for_real, char *cret)
798 if (!cret) return -2;
800 sprintf(aaa, "KILL %d", for_real);
801 return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
806 int CtdlIPCCreateRoom(CtdlIPC *ipc, int for_real, const char *roomname, int type,
807 const char *password, int floor, char *cret)
812 if (!cret) return -2;
813 if (!roomname) return -2;
816 aaa = (char *)malloc(strlen(roomname) + strlen(password) + 40);
818 sprintf(aaa, "CRE8 %d|%s|%d|%s|%d", for_real, roomname, type,
821 aaa = (char *)malloc(strlen(roomname) + 40);
823 sprintf(aaa, "CRE8 %d|%s|%d||%d", for_real, roomname, type,
826 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
833 int CtdlIPCForgetRoom(CtdlIPC *ipc, char *cret)
835 if (!cret) return -2;
837 return CtdlIPCGenericCommand(ipc, "FORG", NULL, 0, NULL, NULL, cret);
842 int CtdlIPCSystemMessage(CtdlIPC *ipc, const char *message, char **mret, char *cret)
848 if (!cret) return -2;
849 if (!mret) return -2;
850 if (*mret) return -2;
851 if (!message) return -2;
853 aaa = (char *)malloc(strlen(message) + 6);
856 sprintf(aaa, "MESG %s", message);
857 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, mret, &bytes, cret);
864 int CtdlIPCNextUnvalidatedUser(CtdlIPC *ipc, char *cret)
866 if (!cret) return -2;
868 return CtdlIPCGenericCommand(ipc, "GNUR", NULL, 0, NULL, NULL, cret);
873 int CtdlIPCGetUserRegistration(CtdlIPC *ipc, const char *username, char **rret, char *cret)
879 if (!cret) return -2;
880 if (!rret) return -2;
881 if (*rret) return -2;
884 aaa = (char *)malloc(strlen(username) + 6);
886 aaa = (char *)malloc(12);
890 sprintf(aaa, "GREG %s", username);
892 sprintf(aaa, "GREG _SELF_");
893 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, rret, &bytes, cret);
900 int CtdlIPCValidateUser(CtdlIPC *ipc, const char *username, int axlevel, char *cret)
905 if (!cret) return -2;
906 if (!username) return -2;
907 if (axlevel < 0 || axlevel > 7) return -2;
909 aaa = (char *)malloc(strlen(username) + 17);
912 sprintf(aaa, "VALI %s|%d", username, axlevel);
913 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
920 int CtdlIPCSetRoomInfo(CtdlIPC *ipc, int for_real, const char *info, char *cret)
924 if (!cret) return -1;
925 if (!info) return -1;
927 sprintf(aaa, "EINF %d", for_real);
928 return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
933 int CtdlIPCUserListing(CtdlIPC *ipc, char **listing, char *cret)
937 if (!cret) return -1;
938 if (!listing) return -1;
939 if (*listing) return -1;
941 return CtdlIPCGenericCommand(ipc, "LIST", NULL, 0, listing, &bytes, cret);
946 int CtdlIPCSetRegistration(CtdlIPC *ipc, const char *info, char *cret)
948 if (!cret) return -1;
949 if (!info) return -1;
951 return CtdlIPCGenericCommand(ipc, "REGI", info, strlen(info),
957 int CtdlIPCMiscCheck(CtdlIPC *ipc, struct ctdlipcmisc *chek, char *cret)
961 if (!cret) return -1;
962 if (!chek) return -1;
964 ret = CtdlIPCGenericCommand(ipc, "CHEK", NULL, 0, NULL, NULL, cret);
965 if (ret / 100 == 2) {
966 chek->newmail = extract_long(cret, 0);
967 chek->needregis = extract_int(cret, 1);
968 chek->needvalid = extract_int(cret, 2);
975 int CtdlIPCDeleteFile(CtdlIPC *ipc, const char *filename, char *cret)
980 if (!cret) return -2;
981 if (!filename) return -2;
983 aaa = (char *)malloc(strlen(filename) + 6);
986 sprintf(aaa, "DELF %s", filename);
987 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
994 int CtdlIPCMoveFile(CtdlIPC *ipc, const char *filename, const char *destroom, char *cret)
999 if (!cret) return -2;
1000 if (!filename) return -2;
1001 if (!destroom) return -2;
1003 aaa = (char *)malloc(strlen(filename) + strlen(destroom) + 7);
1004 if (!aaa) return -1;
1006 sprintf(aaa, "MOVF %s|%s", filename, destroom);
1007 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1014 int CtdlIPCNetSendFile(CtdlIPC *ipc, const char *filename, const char *destnode, char *cret)
1019 if (!cret) return -2;
1020 if (!filename) return -2;
1021 if (!destnode) return -2;
1023 aaa = (char *)malloc(strlen(filename) + strlen(destnode) + 7);
1024 if (!aaa) return -1;
1026 sprintf(aaa, "NETF %s|%s", filename, destnode);
1027 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1034 int CtdlIPCOnlineUsers(CtdlIPC *ipc, char **listing, time_t *stamp, char *cret)
1039 if (!cret) return -1;
1040 if (!listing) return -1;
1041 if (*listing) return -1;
1043 *stamp = CtdlIPCServerTime(ipc, cret);
1045 *stamp = time(NULL);
1046 ret = CtdlIPCGenericCommand(ipc, "RWHO", NULL, 0, listing, &bytes, cret);
1052 int CtdlIPCFileDownload(CtdlIPC *ipc, const char *filename, void **buf, char *cret)
1060 if (!cret) return -2;
1061 if (!filename) return -2;
1062 if (!buf) return -2;
1063 if (*buf) return -2;
1064 if (download_in_progress) return -2;
1066 aaa = (char *)malloc(strlen(filename) + 6);
1067 if (!aaa) return -1;
1069 sprintf(aaa, "OPEN %s", filename);
1070 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1072 /* FIXME: Possible race condition */
1073 if (ret / 100 == 2) {
1074 download_in_progress = 1;
1075 bytes = extract_long(cret, 0);
1076 last_mod = extract_int(cret, 1);
1077 extract(mimetype, cret, 2);
1078 ret = CtdlIPCReadDownload(ipc, buf, bytes, cret);
1079 ret = CtdlIPCEndDownload(ipc, cret);
1081 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1082 filename, mimetype);
1089 int CtdlIPCAttachmentDownload(CtdlIPC *ipc, long msgnum, const char *part, void **buf,
1099 if (!cret) return -2;
1100 if (!buf) return -2;
1101 if (*buf) return -2;
1102 if (!part) return -2;
1103 if (!msgnum) return -2;
1104 if (download_in_progress) return -2;
1106 aaa = (char *)malloc(strlen(part) + 17);
1107 if (!aaa) return -1;
1109 sprintf(aaa, "OPNA %ld|%s", msgnum, part);
1110 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1112 /* FIXME: Possible race condition */
1113 if (ret / 100 == 2) {
1114 download_in_progress = 1;
1115 bytes = extract_long(cret, 0);
1116 last_mod = extract_int(cret, 1);
1117 extract(mimetype, cret, 2);
1118 ret = CtdlIPCReadDownload(ipc, buf, bytes, cret);
1119 ret = CtdlIPCEndDownload(ipc, cret);
1121 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1122 filename, mimetype);
1129 int CtdlIPCImageDownload(CtdlIPC *ipc, const char *filename, void **buf, char *cret)
1137 if (!cret) return -1;
1138 if (!buf) return -1;
1139 if (*buf) return -1;
1140 if (!filename) return -1;
1141 if (download_in_progress) return -1;
1143 aaa = (char *)malloc(strlen(filename) + 6);
1144 if (!aaa) return -1;
1146 sprintf(aaa, "OIMG %s", filename);
1147 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1149 /* FIXME: Possible race condition */
1150 if (ret / 100 == 2) {
1151 download_in_progress = 1;
1152 bytes = extract_long(cret, 0);
1153 last_mod = extract_int(cret, 1);
1154 extract(mimetype, cret, 2);
1155 ret = CtdlIPCReadDownload(ipc, buf, bytes, cret);
1156 ret = CtdlIPCEndDownload(ipc, cret);
1158 sprintf(cret, "%d|%ld|%s|%s", bytes, last_mod,
1159 filename, mimetype);
1166 int CtdlIPCFileUpload(CtdlIPC *ipc, const char *filename, const char *comment, void *buf,
1167 size_t bytes, char *cret)
1172 if (!cret) return -1;
1173 if (!filename) return -1;
1174 if (!comment) return -1;
1175 if (upload_in_progress) return -1;
1177 aaa = (char *)malloc(strlen(filename) + strlen(comment) + 7);
1178 if (!aaa) return -1;
1180 sprintf(aaa, "UOPN %s|%s", filename, comment);
1181 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1183 /* FIXME: Possible race condition */
1185 upload_in_progress = 1;
1186 ret = CtdlIPCWriteUpload(ipc, buf, bytes, cret);
1187 ret = CtdlIPCEndUpload(ipc, cret);
1193 int CtdlIPCImageUpload(CtdlIPC *ipc, int for_real, const char *filename, size_t bytes,
1199 if (!cret) return -1;
1200 if (!filename) return -1;
1201 if (upload_in_progress) return -1;
1203 aaa = (char *)malloc(strlen(filename) + 17);
1204 if (!aaa) return -1;
1206 sprintf(aaa, "UIMG %d|%s", for_real, filename);
1207 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1209 /* FIXME: Possible race condition */
1211 upload_in_progress = 1;
1217 int CtdlIPCQueryUsername(CtdlIPC *ipc, const char *username, char *cret)
1222 if (!cret) return -2;
1223 if (!username) return -2;
1225 aaa = (char *)malloc(strlen(username) + 6);
1226 if (!aaa) return -1;
1228 sprintf(aaa, "QUSR %s", username);
1229 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1236 int CtdlIPCFloorListing(CtdlIPC *ipc, char **listing, char *cret)
1240 if (!cret) return -2;
1241 if (!listing) return -2;
1242 if (*listing) return -2;
1244 return CtdlIPCGenericCommand(ipc, "LFLR", NULL, 0, listing, &bytes, cret);
1249 int CtdlIPCCreateFloor(CtdlIPC *ipc, int for_real, const char *name, char *cret)
1254 if (!cret) return -2;
1255 if (!name) return -2;
1257 aaa = (char *)malloc(strlen(name) + 17);
1258 if (!aaa) return -1;
1260 sprintf(aaa, "CFLR %s|%d", name, for_real);
1261 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1268 int CtdlIPCDeleteFloor(CtdlIPC *ipc, int for_real, int floornum, char *cret)
1272 if (!cret) return -1;
1273 if (floornum < 0) return -1;
1275 sprintf(aaa, "KFLR %d|%d", floornum, for_real);
1276 return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1281 int CtdlIPCEditFloor(CtdlIPC *ipc, int floornum, const char *floorname, char *cret)
1286 if (!cret) return -2;
1287 if (!floorname) return -2;
1288 if (floornum < 0) return -2;
1290 aaa = (char *)malloc(strlen(floorname) + 17);
1291 if (!aaa) return -1;
1293 sprintf(aaa, "EFLR %d|%s", floornum, floorname);
1294 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1301 int CtdlIPCIdentifySoftware(CtdlIPC *ipc, int developerid, int clientid, int revision,
1302 const char *software_name, const char *hostname, char *cret)
1307 if (developerid < 0) return -2;
1308 if (clientid < 0) return -2;
1309 if (revision < 0) return -2;
1310 if (!software_name) return -2;
1311 if (!hostname) return -2;
1313 aaa = (char *)malloc(strlen(software_name) + strlen(hostname) + 29);
1314 if (!aaa) return -1;
1316 sprintf(aaa, "IDEN %d|%d|%d|%s|%s", developerid, clientid,
1317 revision, software_name, hostname);
1318 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1325 int CtdlIPCSendInstantMessage(CtdlIPC *ipc, const char *username, const char *text,
1331 if (!cret) return -2;
1332 if (!username) return -2;
1334 aaa = (char *)malloc(strlen(username) + 8);
1335 if (!aaa) return -1;
1338 sprintf(aaa, "SEXP %s|-", username);
1339 ret = CtdlIPCGenericCommand(ipc, aaa, text, strlen(text),
1342 sprintf(aaa, "SEXP %s||", username);
1343 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1351 int CtdlIPCGetInstantMessage(CtdlIPC *ipc, char **listing, char *cret)
1355 if (!cret) return -2;
1356 if (!listing) return -2;
1357 if (*listing) return -2;
1359 return CtdlIPCGenericCommand(ipc, "GEXP", NULL, 0, listing, &bytes, cret);
1364 /* mode is 0 = enable, 1 = disable, 2 = status */
1365 int CtdlIPCEnableInstantMessageReceipt(CtdlIPC *ipc, int mode, char *cret)
1369 if (!cret) return -2;
1371 sprintf(aaa, "DEXP %d", mode);
1372 return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1377 int CtdlIPCSetBio(CtdlIPC *ipc, char *bio, char *cret)
1379 if (!cret) return -2;
1380 if (!bio) return -2;
1382 return CtdlIPCGenericCommand(ipc, "EBIO", bio, strlen(bio),
1388 int CtdlIPCGetBio(CtdlIPC *ipc, const char *username, char **listing, char *cret)
1394 if (!cret) return -2;
1395 if (!username) return -2;
1396 if (!listing) return -2;
1397 if (*listing) return -2;
1399 aaa = (char *)malloc(strlen(username) + 6);
1400 if (!aaa) return -1;
1402 sprintf(aaa, "RBIO %s", username);
1403 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, listing, &bytes, cret);
1410 int CtdlIPCListUsersWithBios(CtdlIPC *ipc, char **listing, char *cret)
1414 if (!cret) return -2;
1415 if (!listing) return -2;
1416 if (*listing) return -2;
1418 return CtdlIPCGenericCommand(ipc, "LBIO", NULL, 0, listing, &bytes, cret);
1423 int CtdlIPCStealthMode(CtdlIPC *ipc, int mode, char *cret)
1427 if (!cret) return -1;
1429 sprintf(aaa, "STEL %d", mode ? 1 : 0);
1430 return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1435 int CtdlIPCTerminateSession(CtdlIPC *ipc, int sid, char *cret)
1439 if (!cret) return -1;
1441 sprintf(aaa, "TERM %d", sid);
1442 return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1447 int CtdlIPCTerminateServerNow(CtdlIPC *ipc, char *cret)
1449 if (!cret) return -1;
1451 return CtdlIPCGenericCommand(ipc, "DOWN", NULL, 0, NULL, NULL, cret);
1456 int CtdlIPCTerminateServerScheduled(CtdlIPC *ipc, int mode, char *cret)
1460 if (!cret) return -1;
1462 sprintf(aaa, "SCDN %d", mode ? 1 : 0);
1463 return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1468 int CtdlIPCEnterSystemMessage(CtdlIPC *ipc, const char *filename, const char *text,
1474 if (!cret) return -2;
1475 if (!text) return -2;
1476 if (!filename) return -2;
1478 aaa = (char *)malloc(strlen(filename) + 6);
1479 if (!aaa) return -1;
1481 sprintf(aaa, "EMSG %s", filename);
1482 ret = CtdlIPCGenericCommand(ipc, aaa, text, strlen(text), NULL, NULL, cret);
1489 int CtdlIPCChangeHostname(CtdlIPC *ipc, const char *hostname, char *cret)
1494 if (!cret) return -2;
1495 if (!hostname) return -2;
1497 aaa = (char *)malloc(strlen(hostname) + 6);
1498 if (!aaa) return -1;
1500 sprintf(aaa, "HCHG %s", hostname);
1501 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1508 int CtdlIPCChangeRoomname(CtdlIPC *ipc, const char *roomname, char *cret)
1513 if (!cret) return -2;
1514 if (!roomname) return -2;
1516 aaa = (char *)malloc(strlen(roomname) + 6);
1517 if (!aaa) return -1;
1519 sprintf(aaa, "RCHG %s", roomname);
1520 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1527 int CtdlIPCChangeUsername(CtdlIPC *ipc, const char *username, char *cret)
1532 if (!cret) return -2;
1533 if (!username) return -2;
1535 aaa = (char *)malloc(strlen(username) + 6);
1536 if (!aaa) return -1;
1538 sprintf(aaa, "UCHG %s", username);
1539 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1546 /* This function returns the actual server time reported, or 0 if error */
1547 time_t CtdlIPCServerTime(CtdlIPC *ipc, char *cret)
1549 register time_t tret;
1552 ret = CtdlIPCGenericCommand(ipc, "TIME", NULL, 0, NULL, NULL, cret);
1553 if (ret / 100 == 2) {
1554 tret = extract_long(cret, 0);
1563 int CtdlIPCAideGetUserParameters(CtdlIPC *ipc, const char *who,
1564 struct usersupp **uret, char *cret)
1569 if (!cret) return -2;
1570 if (!uret) return -2;
1571 if (!*uret) *uret = (struct usersupp *)calloc(1, sizeof(struct usersupp));
1572 if (!*uret) return -1;
1574 sprintf(aaa, "AGUP %s", who);
1575 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1577 if (ret / 100 == 2) {
1578 extract(uret[0]->fullname, cret, 0);
1579 extract(uret[0]->password, cret, 1);
1580 uret[0]->flags = extract_int(cret, 2);
1581 uret[0]->timescalled = extract_long(cret, 3);
1582 uret[0]->posted = extract_long(cret, 4);
1583 uret[0]->axlevel = extract_int(cret, 5);
1584 uret[0]->usernum = extract_long(cret, 6);
1585 uret[0]->lastcall = extract_long(cret, 7);
1586 uret[0]->USuserpurge = extract_int(cret, 8);
1593 int CtdlIPCAideSetUserParameters(CtdlIPC *ipc, const struct usersupp *uret, char *cret)
1598 if (!cret) return -2;
1599 if (!uret) return -2;
1601 aaa = (char *)malloc(strlen(uret->fullname) + strlen(uret->password) + 84);
1602 if (!aaa) return -1;
1604 sprintf(aaa, "ASUP %s|%s|%d|%ld|%ld|%d|%ld|%ld|%d",
1605 uret->fullname, uret->password, uret->flags,
1606 uret->timescalled, uret->posted, uret->axlevel,
1607 uret->usernum, uret->lastcall, uret->USuserpurge);
1608 ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1615 /* which is 0 = room, 1 = floor, 2 = site */
1616 int CtdlIPCGetMessageExpirationPolicy(CtdlIPC *ipc, int which, char *cret)
1618 static char *proto[] = {"room", "floor", "site"};
1621 if (!cret) return -2;
1622 if (which < 0 || which > 2) return -2;
1624 sprintf(aaa, "GPEX %s", proto[which]);
1625 return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1630 /* which is 0 = room, 1 = floor, 2 = site */
1631 /* policy is 0 = inherit, 1 = no purge, 2 = by count, 3 = by age (days) */
1632 int CtdlIPCSetMessageExpirationPolicy(CtdlIPC *ipc, int which, int policy, int value,
1637 if (!cret) return -2;
1638 if (which < 0 || which > 2) return -2;
1639 if (policy < 0 || policy > 3) return -2;
1640 if (policy >= 2 && value < 1) return -2;
1642 sprintf(aaa, "SPEX %d|%d|%d", which, policy, value);
1643 return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1648 int CtdlGetSystemConfig(CtdlIPC *ipc, char **listing, char *cret)
1652 if (!cret) return -2;
1653 if (!listing) return -2;
1654 if (*listing) return -2;
1656 return CtdlIPCGenericCommand(ipc, "CONF GET", NULL, 0,
1657 listing, &bytes, cret);
1662 int CtdlSetSystemConfig(CtdlIPC *ipc, const char *listing, char *cret)
1664 if (!cret) return -2;
1665 if (!listing) return -2;
1667 return CtdlIPCGenericCommand(ipc, "CONF SET", listing, strlen(listing),
1673 int CtdlGetSystemConfigByType(CtdlIPC *ipc, const char *mimetype,
1674 char **listing, char *cret)
1679 if (!cret) return -2;
1680 if (!mimetype) return -2;
1681 if (!listing) return -2;
1682 if (*listing) return -2;
1684 aaa = malloc(strlen(mimetype) + 13);
1685 if (!aaa) return -1;
1686 sprintf(aaa, "CONF GETSYS|%s", mimetype);
1687 return CtdlIPCGenericCommand(ipc, aaa, NULL, 0,
1688 listing, &bytes, cret);
1693 int CtdlSetSystemConfigByType(CtdlIPC *ipc, const char *mimetype,
1694 const char *listing, char *cret)
1698 if (!cret) return -2;
1699 if (!mimetype) return -2;
1700 if (!listing) return -2;
1702 aaa = malloc(strlen(mimetype) + 13);
1703 if (!aaa) return -1;
1704 sprintf(aaa, "CONF PUTSYS|%s", mimetype);
1705 return CtdlIPCGenericCommand(ipc, aaa, listing, strlen(listing),
1710 int CtdlIPCModerateMessage(CtdlIPC *ipc, long msgnum, int level, char *cret)
1714 if (!cret) return -2;
1715 if (!msgnum) return -2;
1717 sprintf(aaa, "MMOD %ld|%d", msgnum, level);
1718 return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1723 int CtdlIPCRequestClientLogout(CtdlIPC *ipc, int session, char *cret)
1727 if (!cret) return -2;
1728 if (session < 0) return -2;
1730 sprintf(aaa, "REQT %d", session);
1731 return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1736 int CtdlIPCSetMessageSeen(CtdlIPC *ipc, long msgnum, int seen, char *cret)
1740 if (!cret) return -2;
1741 if (msgnum < 0) return -2;
1743 sprintf(aaa, "SEEN %ld|%d", msgnum, seen ? 1 : 0);
1744 return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1749 int CtdlIPCStartEncryption(CtdlIPC *ipc, char *cret)
1751 return CtdlIPCGenericCommand(ipc, "STLS", NULL, 0, NULL, NULL, cret);
1756 int CtdlIPCDirectoryLookup(CtdlIPC *ipc, const char *address, char *cret)
1760 if (!address) return -2;
1761 if (!cret) return -2;
1763 aaa = (char *)malloc(strlen(address) + 6);
1764 if (!aaa) return -1;
1766 sprintf(aaa, "QDIR %s", address);
1767 return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1772 int CtdlIPCInternalProgram(CtdlIPC *ipc, int secret, char *cret)
1776 if (!cret) return -2;
1777 sprintf(aaa, "IPGM %d", secret);
1778 return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
1799 /* ************************************************************************** */
1800 /* Stuff below this line is not for public consumption */
1801 /* ************************************************************************** */
1804 inline void CtdlIPC_lock(CtdlIPC *ipc)
1806 #ifdef THREADED_CLIENT
1807 pthread_mutex_lock(&(ipc->mutex));
1812 inline void CtdlIPC_unlock(CtdlIPC *ipc)
1814 #ifdef THREADED_CLIENT
1815 pthread_mutex_unlock(&(ipc->mutex));
1820 /* Read a listing from the server up to 000. Append to dest if it exists */
1821 char *CtdlIPCReadListing(CtdlIPC *ipc, char *dest)
1830 length = strlen(ret);
1837 while (CtdlIPC_getline(ipc, aaa), strcmp(aaa, "000")) {
1838 linelength = strlen(aaa);
1839 ret = (char *)realloc(ret, (size_t)(length + linelength + 2));
1841 strcpy(&ret[length], aaa);
1842 length += linelength;
1843 strcpy(&ret[length++], "\n");
1851 /* Send a listing to the server; generate the ending 000. */
1852 int CtdlIPCSendListing(CtdlIPC *ipc, const char *listing)
1856 text = (char *)malloc(strlen(listing) + 6);
1858 strcpy(text, listing);
1859 while (text[strlen(text) - 1] == '\n')
1860 text[strlen(text) - 1] = '\0';
1861 strcat(text, "\n000");
1862 CtdlIPC_putline(ipc, text);
1866 /* Malloc failed but we are committed to send */
1867 /* This may result in extra blanks at the bottom */
1868 CtdlIPC_putline(ipc, text);
1869 CtdlIPC_putline(ipc, "000");
1875 /* Partial read of file from server */
1876 size_t CtdlIPCPartialRead(CtdlIPC *ipc, void **buf, size_t offset, size_t bytes, char *cret)
1878 register size_t len = 0;
1881 if (!buf) return -1;
1882 if (!cret) return -1;
1883 if (bytes < 1) return -1;
1884 if (offset < 0) return -1;
1887 sprintf(aaa, "READ %d|%d", offset, bytes);
1888 CtdlIPC_putline(ipc, aaa);
1889 CtdlIPC_getline(ipc, aaa);
1891 strcpy(cret, &aaa[4]);
1893 len = extract_long(&aaa[4], 0);
1894 *buf = (void *)realloc(*buf, (size_t)(offset + len));
1896 /* I know what I'm doing */
1897 serv_read(ipc, (char *)&buf[offset], len);
1899 /* We have to read regardless */
1900 serv_read(ipc, aaa, len);
1904 CtdlIPC_unlock(ipc);
1910 int CtdlIPCEndDownload(CtdlIPC *ipc, char *cret)
1914 if (!cret) return -2;
1915 if (!download_in_progress) return -2;
1917 ret = CtdlIPCGenericCommand(ipc, "CLOS", NULL, 0, NULL, NULL, cret);
1919 download_in_progress = 0;
1925 int CtdlIPCSpecifyPreferredFormats(CtdlIPC *ipc, char *cret, char *formats) {
1929 snprintf(cmd, sizeof cmd, "MSGP %s", formats);
1930 ret = CtdlIPCGenericCommand(ipc, cmd, NULL, 0, NULL, NULL, cret);
1937 int CtdlIPCReadDownload(CtdlIPC *ipc, void **buf, size_t bytes, char *cret)
1939 register size_t len;
1941 if (!cret) return -1;
1942 if (!buf) return -1;
1943 if (*buf) return -1;
1944 if (!download_in_progress) return -1;
1947 while (len < bytes) {
1948 len = CtdlIPCPartialRead(ipc, buf, len, 4096, cret);
1959 int CtdlIPCEndUpload(CtdlIPC *ipc, char *cret)
1963 if (!cret) return -1;
1964 if (!upload_in_progress) return -1;
1966 ret = CtdlIPCGenericCommand(ipc, "UCLS", NULL, 0, NULL, NULL, cret);
1968 upload_in_progress = 0;
1974 int CtdlIPCWriteUpload(CtdlIPC *ipc, void *buf, size_t bytes, char *cret)
1976 register int ret = -1;
1977 register size_t offset;
1980 if (!cret) return -1;
1981 if (!buf) return -1;
1982 if (bytes < 1) return -1;
1985 while (offset < bytes) {
1986 sprintf(aaa, "WRIT %d", bytes - offset);
1987 CtdlIPC_putline(ipc, aaa);
1988 CtdlIPC_getline(ipc, aaa);
1989 strcpy(cret, &aaa[4]);
1991 if (aaa[0] == '7') {
1992 register size_t to_write;
1994 to_write = extract_long(&aaa[4], 0);
1995 serv_write(ipc, buf + offset, to_write);
2006 * Generic command method. This method should handle any server command
2007 * except for CHAT. It takes the following arguments:
2009 * ipc The server to speak with
2010 * command Preformatted command to send to server
2011 * to_send A text or binary file to send to server
2012 * (only sent if server requests it)
2013 * bytes_to_send The number of bytes in to_send (required if
2014 * sending binary, optional if sending listing)
2015 * to_receive Pointer to a NULL pointer, if the server
2016 * sends text or binary we will allocate memory
2017 * for the file and stuff it here
2018 * bytes_to_receive If a file is received, we will store its
2020 * proto_response The protocol response. Caller must provide
2021 * this buffer and ensure that it is at least
2022 * 128 bytes in length.
2024 * This function returns a number equal to the protocol response number,
2025 * -1 if an internal error occurred, -2 if caller provided bad values,
2026 * or 0 - the protocol response number if bad values were found during
2027 * the protocol exchange.
2028 * It stores the protocol response string (minus the number) in
2029 * protocol_response as described above. Some commands send additional
2030 * data in this string.
2032 int CtdlIPCGenericCommand(CtdlIPC *ipc,
2033 const char *command, const char *to_send,
2034 size_t bytes_to_send, char **to_receive,
2035 size_t *bytes_to_receive, char *proto_response)
2041 if (!command) return -2;
2042 if (!proto_response) return -2;
2044 if (ipc->ssl) watch_ssl = 1;
2047 CtdlIPC_putline(ipc, command);
2049 CtdlIPC_getline(ipc, proto_response);
2050 if (proto_response[3] == '*')
2052 ret = atoi(proto_response);
2053 strcpy(proto_response, &proto_response[4]);
2054 switch (ret / 100) {
2055 default: /* Unknown, punt */
2057 case 3: /* MORE_DATA */
2059 /* Don't need to do anything */
2061 case 1: /* LISTING_FOLLOWS */
2062 if (to_receive && !*to_receive && bytes_to_receive) {
2063 *to_receive = CtdlIPCReadListing(ipc, NULL);
2064 } else { /* Drain */
2065 while (CtdlIPC_getline(ipc, buf), strcmp(buf, "000")) ;
2069 case 4: /* SEND_LISTING */
2071 CtdlIPCSendListing(ipc, to_send);
2073 /* No listing given, fake it */
2074 CtdlIPC_putline(ipc, "000");
2078 case 6: /* BINARY_FOLLOWS */
2079 if (to_receive && !*to_receive && bytes_to_receive) {
2081 extract_long(proto_response, 0);
2082 *to_receive = (char *)
2083 malloc((size_t)*bytes_to_receive);
2087 serv_read(ipc, *to_receive,
2094 drain = extract_long(proto_response, 0);
2095 while (drain > SIZ) {
2096 serv_read(ipc, buf, SIZ);
2099 serv_read(ipc, buf, drain);
2103 case 7: /* SEND_BINARY */
2104 if (to_send && bytes_to_send) {
2105 serv_write(ipc, to_send, bytes_to_send);
2106 } else if (bytes_to_send) {
2107 /* Fake it, send nulls */
2110 fake = bytes_to_send;
2111 memset(buf, '\0', SIZ);
2112 while (fake > SIZ) {
2113 serv_write(ipc, buf, SIZ);
2116 serv_write(ipc, buf, fake);
2118 } /* else who knows? DANGER WILL ROBINSON */
2120 case 8: /* START_CHAT_MODE */
2121 if (!strncasecmp(command, "CHAT", 4)) {
2122 /* Don't call chatmode with generic! */
2123 CtdlIPC_putline(ipc, "/quit");
2126 /* In this mode we send then receive listing */
2128 CtdlIPCSendListing(ipc, to_send);
2130 /* No listing given, fake it */
2131 CtdlIPC_putline(ipc, "000");
2134 if (to_receive && !*to_receive
2135 && bytes_to_receive) {
2136 *to_receive = CtdlIPCReadListing(ipc, NULL);
2137 } else { /* Drain */
2138 while (CtdlIPC_getline(ipc, buf),
2139 strcmp(buf, "000")) ;
2144 case 9: /* ASYNC_MSG */
2145 /* CtdlIPCDoAsync(ret, proto_response); */
2146 free(CtdlIPCReadListing(ipc, NULL)); /* STUB FIXME */
2152 CtdlIPC_unlock(ipc);