X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmessages.c;h=442089552e2e1f32bbbd90f1a4dd76c9498d6a71;hb=44bdabdda4dc6e9823e0464c37157c960abac9f7;hp=b6341e50efcfc1706bdc7711e09049afec7e542a;hpb=fcb314d106308a2ce6ebb85e13381a168aeacef0;p=citadel.git diff --git a/citadel/messages.c b/citadel/messages.c index b6341e50e..442089552 100644 --- a/citadel/messages.c +++ b/citadel/messages.c @@ -1,7 +1,7 @@ /* * $Id$ * - * Citadel/UX message support routines + * Citadel message support routines * see copyright.txt for copyright information */ @@ -30,6 +30,10 @@ # endif #endif +#ifdef HAVE_PTHREAD_H +#include +#endif + #include #include "citadel.h" #include "citadel_ipc.h" @@ -55,11 +59,11 @@ struct cittext { char text[MAXWORDBUF]; }; -void sttybbs(int cmd); +void stty_ctdl(int cmd); int haschar(const char *st, int ch); void getline(char *string, int lim); int file_checksum(char *filename); -void progress(unsigned long curr, unsigned long cmax); +void progress(CtdlIPC* ipc, unsigned long curr, unsigned long cmax); unsigned long *msg_arr = NULL; int msg_arr_size = 0; @@ -68,7 +72,6 @@ char rc_alt_semantics; extern char room_name[]; extern unsigned room_flags; extern long highest_msg_read; -extern struct CtdlServInfo serv_info; extern char temp[]; extern char temp2[]; extern int screenwidth; @@ -81,13 +84,19 @@ extern char fullname[]; extern char axlevel; extern unsigned userflags; extern char sigcaught; -extern char editor_path[]; extern char printcmd[]; extern int rc_allow_attachments; extern int rc_display_message_numbers; extern int rc_force_mail_prompts; extern int editor_pid; extern CtdlIPC *ipc_for_signal_handlers; /* KLUDGE cover your eyes */ +int num_urls = 0; +char urls[MAXURLS][SIZ]; +char imagecmd[SIZ]; +int has_images = 0; /* Current msg has images */ +struct parts *last_message_parts = NULL; /* Parts from last msg */ + + void ka_sigcatch(int signum) { @@ -347,7 +356,26 @@ void citedit(CtdlIPC *ipc, FILE * fp) } } -/* Read a message from the server + +/* + * Free the struct parts + */ +void free_parts(struct parts *p) +{ + struct parts *a_part = p; + + while (a_part) { + struct parts *q; + + q = a_part; + a_part = a_part->next; + free(q); + } +} + + +/* + * Read a message from the server */ int read_message(CtdlIPC *ipc, long num, /* message number */ @@ -362,9 +390,18 @@ int read_message(CtdlIPC *ipc, struct ctdlipcmessage *message = NULL; int r; /* IPC response code */ char *converted_text = NULL; + char *lineptr; + char *nextline; + char *searchptr; + int i; + char ch; + int linelen; + int final_line_is_blank = 0; + + has_images = 0; sigcaught = 0; - sttybbs(1); + stty_ctdl(1); strcpy(reply_to, NO_REPLY_TO); strcpy(reply_subject, ""); @@ -377,7 +414,7 @@ int read_message(CtdlIPC *ipc, ++lines_printed; lines_printed = checkpagin(lines_printed, pagin, screenheight); - sttybbs(0); + stty_ctdl(0); return (0); } @@ -424,7 +461,7 @@ int read_message(CtdlIPC *ipc, } } pprintf("\n"); - sttybbs(0); + stty_ctdl(0); return (0); } @@ -471,8 +508,8 @@ int read_message(CtdlIPC *ipc, } if (strlen(message->node)) { if ((room_flags & QR_NETWORK) - || ((strcasecmp(message->node, serv_info.serv_nodename) - && (strcasecmp(message->node, serv_info.serv_fqdn))))) { + || ((strcasecmp(message->node, ipc->ServInfo.nodename) + && (strcasecmp(message->node, ipc->ServInfo.fqdn))))) { if (strlen(message->email) == 0) { if (dest) { fprintf(dest, "@%s ", message->node); @@ -485,7 +522,7 @@ int read_message(CtdlIPC *ipc, } } } - if (strcasecmp(message->hnod, serv_info.serv_humannode) + if (strcasecmp(message->hnod, ipc->ServInfo.humannode) && (strlen(message->hnod)) && (!strlen(message->email))) { if (dest) { fprintf(dest, "(%s) ", message->hnod); @@ -574,7 +611,7 @@ int read_message(CtdlIPC *ipc, * of the client screen. */ if (!strcasecmp(message->content_type, "text/html")) { - converted_text = html_to_ascii(message->text, screenwidth, 0); + converted_text = html_to_ascii(message->text, 0, screenwidth, 0); if (converted_text != NULL) { free(message->text); message->text = converted_text; @@ -587,6 +624,26 @@ int read_message(CtdlIPC *ipc, format_type = 1; } + /* Extract URL's */ + num_urls = 0; /* Start with a clean slate */ + searchptr = message->text; + while ( (searchptr != NULL) && (num_urls < MAXURLS) ) { + searchptr = strstr(searchptr, "http://"); + if (searchptr != NULL) { + safestrncpy(urls[num_urls], searchptr, sizeof(urls[num_urls])); + for (i = 0; i < strlen(urls[num_urls]); i++) { + ch = urls[num_urls][i]; + if (ch == '>' || ch == '\"' || ch == ')' || + ch == ' ' || ch == '\n') { + urls[num_urls][i] = 0; + break; + } + } + num_urls++; + ++searchptr; + } + } + /* * Here we go */ @@ -594,37 +651,49 @@ int read_message(CtdlIPC *ipc, fr = fmout(screenwidth, NULL, message->text, dest, ((pagin == 1) ? 1 : 0), screenheight, (-1), 1); } else { - /* FIXME: renderer for text/plain */ - char *msgtext; - char *lineptr; + /* renderer for text/plain */ - msgtext = message->text; + lineptr = message->text; - while (lineptr = strtok(msgtext, "\n"), lineptr != NULL) { - msgtext = NULL; + do { + nextline = strchr(lineptr, '\n'); + if (nextline != NULL) { + *nextline = 0; + ++nextline; + if (*nextline == 0) nextline = NULL; + } if (sigcaught == 0) { + linelen = strlen(lineptr); + if (lineptr[linelen-1] == '\r') { + lineptr[--linelen] = 0; + } if (dest) { fprintf(dest, "%s\n", lineptr); } else { scr_printf("%s\n", lineptr); lines_printed = lines_printed + 1 + - (strlen(lineptr) / screenwidth); + (linelen / screenwidth); lines_printed = checkpagin(lines_printed, pagin, screenheight); } } - } + if (lineptr[0] == 0) final_line_is_blank = 1; + else final_line_is_blank = 0; + lineptr = nextline; + } while (nextline); fr = sigcaught; } - if (dest) { - fprintf(dest, "\n"); - } else { - scr_printf("\n"); - /* scr_flush(); */ - ++lines_printed; - lines_printed = checkpagin(lines_printed, pagin, screenheight); + if (!final_line_is_blank) { + if (dest) { + fprintf(dest, "\n"); + } + else { + scr_printf("\n"); + ++lines_printed; + lines_printed = checkpagin(lines_printed, pagin, screenheight); + } } /* Enumerate any attachments */ @@ -635,26 +704,31 @@ int read_message(CtdlIPC *ipc, if ( (!strcasecmp(ptr->disposition, "attachment")) || (!strcasecmp(ptr->disposition, "inline"))) { color(DIM_WHITE); - scr_printf("Part "); + pprintf("Part "); color(BRIGHT_MAGENTA); - scr_printf("%s", ptr->number); + pprintf("%s", ptr->number); color(DIM_WHITE); - scr_printf(": "); + pprintf(": "); color(BRIGHT_CYAN); - scr_printf("%s", ptr->filename); + pprintf("%s", ptr->filename); color(DIM_WHITE); - scr_printf(" (%s, %ld bytes)\n", ptr->mimetype, ptr->length); + pprintf(" (%s, %ld bytes)\n", ptr->mimetype, ptr->length); + if (!strncmp(ptr->mimetype, "image/", 6)) + has_images++; } } } + /* Save the attachments info for later */ + last_message_parts = message->attachments; + /* Now we're done */ free(message->text); free(message); if (pagin == 1 && !dest) color(DIM_WHITE); - sttybbs(0); + stty_ctdl(0); return (fr); } @@ -723,7 +797,7 @@ void replace_string(char *filename, long int startpos) int client_make_message(CtdlIPC *ipc, char *filename, /* temporary file name */ char *recipient, /* NULL if it's not mail */ - int anon_type, /* see MES_ types in header file */ + int is_anonymous, int format_type, int mode, char *subject) /* buffer to store subject line */ @@ -733,14 +807,21 @@ int client_make_message(CtdlIPC *ipc, long beg; char datestr[SIZ]; char header[SIZ]; + char *editor_path = NULL; int cksum = 0; - if (mode == 2) - if (strlen(editor_path) == 0) { - err_printf - ("*** No editor available, using built-in editor\n"); + if (mode >= 2) + { + if((mode-2) < MAX_EDITORS && strlen(editor_paths[mode-2]) > 0) { + editor_path = editor_paths[mode-2]; + } else if (strlen(editor_paths[0]) > 0) { + editor_path = editor_paths[0]; + } else { + err_printf("*** No editor available, " + "using built-in editor\n"); mode = 0; } + } fmt_date(datestr, sizeof datestr, time(NULL), 0); header[0] = 0; @@ -750,7 +831,10 @@ int client_make_message(CtdlIPC *ipc, } else { snprintf(header, sizeof header, - " %s from %s", datestr, fullname); + " %s from %s", + datestr, + (is_anonymous ? "[anonymous]" : fullname) + ); if (strlen(recipient) > 0) { size_t tmp = strlen(header); snprintf(&header[tmp], sizeof header - tmp, @@ -771,7 +855,8 @@ int client_make_message(CtdlIPC *ipc, if (mode == 0) { fp = fopen(filename, "r"); if (fp != NULL) { - fmout(screenwidth, fp, NULL, NULL, 0, screenheight, 0, 0); + fmout(screenwidth, fp, NULL, NULL, 0, + screenheight, 0, 0); beg = ftell(fp); fclose(fp); } else { @@ -825,11 +910,12 @@ ME1: switch (mode) { break; case 2: + default: /* allow 2+ modes */ e_ex_code = 1; /* start with a failed exit code */ + screen_reset(); + stty_ctdl(SB_RESTORE); editor_pid = fork(); cksum = file_checksum(filename); - screen_reset(); - sttybbs(SB_RESTORE); if (editor_pid == 0) { char tmp[SIZ]; @@ -845,18 +931,19 @@ ME1: switch (mode) { b = ka_wait(&e_ex_code); } while ((b != editor_pid) && (b >= 0)); editor_pid = (-1); - sttybbs(0); + stty_ctdl(0); screen_set(); break; } -MECR: if (mode == 2) { +MECR: if (mode >= 2) { if (file_checksum(filename) == cksum) { err_printf("*** Aborted message.\n"); e_ex_code = 1; } - if (e_ex_code == 0) + if (e_ex_code == 0) { goto MEFIN; + } goto MEABT2; } @@ -865,16 +952,14 @@ MECR: if (mode == 2) { "add sbject|" "eplace string|old message"); - if (b == 'a') - goto MEABT; - if (b == 'c') - goto ME1; - if (b == 's') - goto MEFIN; + if (b == 'a') goto MEABT; + if (b == 'c') goto ME1; + if (b == 's') goto MEFIN; if (b == 'p') { scr_printf(" %s from %s", datestr, fullname); - if (strlen(recipient) > 0) + if (strlen(recipient) > 0) { scr_printf(" to %s", recipient); + } scr_printf("\n"); if (subject != NULL) if (strlen(subject) > 0) { scr_printf("Subject: %s\n", subject); @@ -913,6 +998,8 @@ MEABT2: unlink(filename); return (2); } + +#if 0 /* * Transmit message text to the server. * @@ -968,6 +1055,8 @@ void transmit_message(CtdlIPC *ipc, FILE *fp) scr_printf(" \r"); scr_flush(); } +#endif + /* * Make sure there's room in msg_arr[] for at least one more. @@ -981,6 +1070,29 @@ void check_msg_arr_size(void) { } +/* + * break_big_lines() - break up lines that are >1024 characters + * otherwise the server will truncate + */ +void break_big_lines(char *msg) { + char *ptr; + char *break_here; + + if (msg == NULL) { + return; + } + + ptr = msg; + while (strlen(ptr) > 1000) { + break_here = strchr(&ptr[900], ' '); + if ((break_here == NULL) || (break_here > &ptr[999])) { + break_here = &ptr[999]; + } + *break_here = '\n'; + ptr = break_here++; + } +} + /* * entmsg() - edit and create a message @@ -988,16 +1100,18 @@ void check_msg_arr_size(void) { */ int entmsg(CtdlIPC *ipc, int is_reply, /* nonzero if this was a eply command */ - int c) /* */ + int c) /* mode */ { - char buf[300]; - char cmd[SIZ]; + char buf[SIZ]; int a, b; int need_recp = 0; int mode; long highmsg = 0L; FILE *fp; char subject[SIZ]; + struct ctdlipcmessage message; + unsigned long *msgarr = NULL; + int r; /* IPC response code */ if (c > 0) mode = 1; @@ -1010,12 +1124,16 @@ int entmsg(CtdlIPC *ipc, * First, check to see if we have permission to enter a message in * this room. The server will return an error code if we can't. */ - snprintf(cmd, sizeof cmd, "ENT0 0||0|%d", mode); - CtdlIPC_putline(ipc, cmd); - CtdlIPC_getline(ipc, cmd); - - if ((strncmp(cmd, "570", 3)) && (strncmp(cmd, "200", 3))) { - scr_printf("%s\n", &cmd[4]); + strcpy(message.recipient, ""); + strcpy(message.author, ""); + strcpy(message.subject, ""); + message.text = message.author; /* point to "", changes later */ + message.anonymous = 0; + message.type = mode; + r = CtdlIPCPostMessage(ipc, 0, &message, buf); + + if (r / 100 != 2 && r / 10 != 57) { + scr_printf("%s\n", buf); return (1); } @@ -1023,8 +1141,9 @@ int entmsg(CtdlIPC *ipc, * in this room, but a recipient needs to be specified. */ need_recp = 0; - if (!strncmp(cmd, "570", 3)) + if (r / 10 == 57) { need_recp = 1; + } /* If the user is a dumbass, tell them how to type. */ if ((userflags & US_EXPERT) == 0) { @@ -1046,36 +1165,34 @@ int entmsg(CtdlIPC *ipc, } else strcpy(buf, "sysop"); } + strcpy(message.recipient, buf); if (is_reply) { if (strlen(reply_subject) > 0) { if (!strncasecmp(reply_subject, "Re: ", 3)) { - strcpy(subject, reply_subject); + strcpy(message.subject, reply_subject); } else { - snprintf(subject, - sizeof subject, + snprintf(message.subject, + sizeof message.subject, "Re: %s", reply_subject); } } } - b = 0; if (room_flags & QR_ANONOPT) { scr_printf("Anonymous (Y/N)? "); if (yesno() == 1) - b = 1; + message.anonymous = 1; } /* If it's mail, we've got to check the validity of the recipient... */ - if (strlen(buf) > 0) { - snprintf(cmd, sizeof cmd, "ENT0 0|%s|%d|%d|%s", buf, b, mode, subject); - CtdlIPC_putline(ipc, cmd); - CtdlIPC_getline(ipc, cmd); - if (cmd[0] != '2') { - scr_printf("%s\n", &cmd[4]); + if (strlen(message.recipient) > 0) { + r = CtdlIPCPostMessage(ipc, 0, &message, buf); + if (r / 100 != 2) { + scr_printf("%s\n", buf); return (1); } } @@ -1084,72 +1201,72 @@ int entmsg(CtdlIPC *ipc, * tell upon saving whether someone else has posted too. */ num_msgs = 0; - CtdlIPC_putline(ipc, "MSGS LAST|1"); - CtdlIPC_getline(ipc, cmd); - if (cmd[0] != '1') { - scr_printf("%s\n", &cmd[5]); + r = CtdlIPCGetMessages(ipc, LastMessages, 1, NULL, &msgarr, buf); + if (r / 100 != 1) { + scr_printf("%s\n", buf); } else { - while (CtdlIPC_getline(ipc, cmd), strcmp(cmd, "000")) { - check_msg_arr_size(); - msg_arr[num_msgs++] = atol(cmd); - } + for (num_msgs = 0; msgarr[num_msgs]; num_msgs++) + ; } /* Now compose the message... */ - if (client_make_message(ipc, temp, buf, b, 0, c, subject) != 0) { + if (client_make_message(ipc, temp, message.recipient, + message.anonymous, 0, c, message.subject) != 0) { return (2); } /* Reopen the temp file that was created, so we can send it */ fp = fopen(temp, "r"); - /* Yes, unlink it now, so it doesn't stick around if we crash */ - unlink(temp); - - if (fp == NULL) { + if (!fp || !(message.text = load_message_from_file(fp))) { err_printf("*** Internal error while trying to save message!\n" - " %s: %s\n", + "%s: %s\n", temp, strerror(errno)); + unlink(temp); return(errno); } + if (fp) fclose(fp); + + /* Break lines that are >1024 characters, otherwise the server + * will truncate them. + */ + break_big_lines(message.text); + /* Transmit message to the server */ - snprintf(cmd, sizeof cmd, "ENT0 1|%s|%d|%d|%s|", buf, b, mode, subject); - CtdlIPC_putline(ipc, cmd); - CtdlIPC_getline(ipc, cmd); - if (cmd[0] != '4') { - scr_printf("%s\n", &cmd[4]); + r = CtdlIPCPostMessage(ipc, 1, &message, buf); + if (r / 100 != 4) { + scr_printf("%s\n", buf); return (1); } - transmit_message(ipc, fp); - CtdlIPC_putline(ipc, "000"); + /* Yes, unlink it now, so it doesn't stick around if we crash */ + unlink(temp); - fclose(fp); + if (num_msgs >= 1) highmsg = msgarr[num_msgs - 1]; - if (num_msgs >= 1) highmsg = msg_arr[num_msgs - 1]; - num_msgs = 0; - CtdlIPC_putline(ipc, "MSGS NEW"); - CtdlIPC_getline(ipc, cmd); - if (cmd[0] != '1') { - scr_printf("%s\n", &cmd[5]); + if (msgarr) free(msgarr); + msgarr = NULL; + r = CtdlIPCGetMessages(ipc, NewMessages, 0, NULL, &msgarr, buf); + if (r / 100 != 1) { + scr_printf("%s\n", buf); } else { - while (CtdlIPC_getline(ipc, cmd), strcmp(cmd, "000")) { - check_msg_arr_size(); - msg_arr[num_msgs++] = atol(cmd); - } + for (num_msgs = 0; msgarr[num_msgs]; num_msgs++) + ; } /* get new highest message number in room to set lrp for goto... */ - maxmsgnum = msg_arr[num_msgs - 1]; + maxmsgnum = msgarr[num_msgs - 1]; /* now see if anyone else has posted in here */ b = (-1); for (a = 0; a < num_msgs; ++a) { - if (msg_arr[a] > highmsg) { + if (msgarr[a] > highmsg) { ++b; } } + if (msgarr) free(msgarr); + msgarr = NULL; /* In the Mail> room, this algorithm always counts one message * higher than in public rooms, so we decrement it by one. @@ -1238,12 +1355,136 @@ void list_urls(CtdlIPC *ipc) scr_printf("\n"); } + +/* + * Run image viewer in background + */ +int do_image_view(const char *filename) +{ + char cmd[SIZ]; + pid_t childpid; + + snprintf(cmd, sizeof cmd, imagecmd, filename); + childpid = fork(); + if (childpid < 0) { + unlink(filename); + return childpid; + } + + if (childpid == 0) { + int retcode; + pid_t grandchildpid; + + grandchildpid = fork(); + if (grandchildpid < 0) { + return grandchildpid; + } + + if (grandchildpid == 0) { + int nullfd; + int outfd = -1; + int errfd = -1; + + nullfd = open("/dev/null", O_WRONLY); + if (nullfd > -1) { + dup2(1, outfd); + dup2(2, errfd); + dup2(nullfd, 1); + dup2(nullfd, 2); + } + retcode = system(cmd); + if (nullfd > -1) { + dup2(outfd, 1); + dup2(errfd, 2); + close(nullfd); + } + unlink(filename); + exit(retcode); + } + + if (grandchildpid > 0) { + exit(0); + } + } + + if (childpid > 0) { + int retcode; + + waitpid(childpid, &retcode, 0); + return retcode; + } + + return -1; +} + + +/* + * View an image attached to a message + */ +void image_view(CtdlIPC *ipc, unsigned long msg) +{ + struct parts *ptr = last_message_parts; + char part[SIZ]; + int found = 0; + + /* Run through available parts */ + for (ptr = last_message_parts; ptr; ptr = ptr->next) { + if ((!strcasecmp(ptr->disposition, "attachment") + || !strcasecmp(ptr->disposition, "inline")) + && !strncmp(ptr->mimetype, "image/", 6)) { + found++; + if (found == 1) { + strcpy(part, ptr->number); + } + } + } + + while (found > 0) { + if (found > 1) + strprompt("View which part (0 when done)", part, SIZ-1); + found = -found; + for (ptr = last_message_parts; ptr; ptr = ptr->next) { + if ((!strcasecmp(ptr->disposition, "attachment") + || !strcasecmp(ptr->disposition, "inline")) + && !strncmp(ptr->mimetype, "image/", 6) + && !strcasecmp(ptr->number, part)) { + char tmp[PATH_MAX]; + char buf[SIZ]; + void *file = NULL; /* The downloaded file */ + int r; + + /* view image */ + found = -found; + r = CtdlIPCAttachmentDownload(ipc, msg, ptr->number, &file, progress, buf); + if (r / 100 != 2) { + scr_printf("%s\n", buf); + } else { + size_t len; + + len = (size_t)extract_long(buf, 0); + progress(ipc, len, len); + scr_flush(); + CtdlMakeTempFileName(tmp, sizeof tmp); + strcat(tmp, ptr->filename); + save_buffer(file, len, tmp); + free(file); + do_image_view(tmp); + } + break; + } + } + if (found == 1) + break; + } +} + + /* * Read the messages in the current room */ void readmsgs(CtdlIPC *ipc, - int c, /* 0=Read all 1=Read new 2=Read old 3=Read last q */ - int rdir, /* 1=Forward (-1)=Reverse */ + enum MessageList c, /* see listing in citadel_ipc.h */ + enum MessageDirection rdir, /* 1=Forward (-1)=Reverse */ int q /* Number of msgs to read (if c==3) */ ) { int a, b, e, f, g, start; @@ -1267,40 +1508,25 @@ void readmsgs(CtdlIPC *ipc, else b = 0; - strcpy(prtfile, tmpnam(NULL)); + CtdlMakeTempFileName(prtfile, sizeof prtfile); - num_msgs = 0; - strcpy(cmd, "MSGS "); - switch (c) { - case 0: - strcat(cmd, "ALL"); - break; - case 1: - strcat(cmd, "NEW"); - break; - case 2: - strcat(cmd, "OLD"); - break; - case 3: - snprintf(&cmd[5], sizeof cmd - 5, "LAST|%d", q); - break; + if (msg_arr) { + free(msg_arr); + msg_arr = NULL; } - CtdlIPC_putline(ipc, cmd); - CtdlIPC_getline(ipc, cmd); - if (cmd[0] != '1') { - scr_printf("%s\n", &cmd[5]); + r = CtdlIPCGetMessages(ipc, c, q, NULL, &msg_arr, cmd); + if (r / 100 != 1) { + scr_printf("%s\n", cmd); } else { - while (CtdlIPC_getline(ipc, cmd), strcmp(cmd, "000")) { - check_msg_arr_size(); - msg_arr[num_msgs++] = atol(cmd); - } + for (num_msgs = 0; msg_arr[num_msgs]; num_msgs++) + ; } - if (num_msgs == 0) { - if (c == 3) return; + if (num_msgs == 0) { /* TODO look at this later */ + if (c == LastMessages) return; scr_printf("*** There are no "); - if (c == 1) scr_printf("new "); - if (c == 2) scr_printf("old "); + if (c == NewMessages) scr_printf("new "); + if (c == OldMessages) scr_printf("old "); scr_printf("messages in this room.\n"); return; } @@ -1332,6 +1558,10 @@ RAGAIN: pagin = ((arcflag == 0) screenwidth = 80; } + /* clear parts list */ + free_parts(last_message_parts); + last_message_parts = NULL; + /* now read the message... */ e = read_message(ipc, msg_arr[a], pagin, dest); @@ -1357,9 +1587,9 @@ RMSGREAD: scr_flush(); if (f == 0) { freopen(prtfile, "r", stdin); screen_reset(); - sttybbs(SB_RESTORE); + stty_ctdl(SB_RESTORE); ka_system(printcmd); - sttybbs(SB_NO_INTR); + stty_ctdl(SB_NO_INTR); screen_set(); unlink(prtfile); exit(0); @@ -1389,9 +1619,11 @@ RMSGREAD: scr_flush(); color(DIM_WHITE); scr_printf(") "); - keyopt("ack gain uote eply ext top m next "); + keyopt("ack gain uote eply ext top "); if (rc_url_cmd[0] && num_urls) keyopt("RLview "); + if (has_images > 0 && strlen(imagecmd) > 0) + keyopt("mages "); keyopt("help -> "); do { @@ -1420,11 +1652,15 @@ RMSGREAD: scr_flush(); if ((e == 'u') && (strlen(rc_url_cmd) == 0)) e = 0; + if ((e == 'i') + && (!strlen(imagecmd) || !has_images)) + e = 0; } while ((e != 'a') && (e != 'n') && (e != 's') && (e != 'd') && (e != 'm') && (e != 'p') && (e != 'q') && (e != 'b') && (e != 'h') && (e != 'r') && (e != 'f') && (e != '?') - && (e != 'u') && (e != 'c') && (e != 'y')); + && (e != 'u') && (e != 'c') && (e != 'y') + && (e != 'i')); switch (e) { case 's': scr_printf("Stop"); @@ -1468,11 +1704,13 @@ RMSGREAD: scr_flush(); case 'y': scr_printf("mY next"); break; + case 'i': + break; case '?': scr_printf("? "); break; } - if (userflags & US_DISAPPEAR) + if (userflags & US_DISAPPEAR || e == 'i') scr_printf("\r%79s\r", ""); else scr_printf("\n"); @@ -1505,6 +1743,8 @@ RMSGREAD: scr_flush(); (" F (save attachments to a file)\n"); if (strlen(rc_url_cmd) > 0) scr_printf(" U (list URL's for display)\n"); + if (strlen(imagecmd) > 0 && has_images > 0) + scr_printf(" I Image viewer\n"); scr_printf("\n"); goto RMSGREAD; case 'p': @@ -1549,18 +1789,25 @@ RMSGREAD: scr_flush(); ((sizeof filename) - 1)); r = CtdlIPCAttachmentDownload(ipc, msg_arr[a], filename, &attachment, progress, cmd); - extract(filename, cmd, 2); - destination_directory(save_to, filename); - r = CtdlIPCAttachmentDownload(ipc, msg_arr[a], - filename, &attachment, progress, cmd); if (r / 100 != 2) { scr_printf("%s\n", cmd); } else { + extract_token(filename, cmd, 2, '|', sizeof filename); + /* + * Part 1 won't have a filename; use the + * subject of the message instead. IO + */ + if (!strlen(filename)) + strcpy(filename, reply_subject); + destination_directory(save_to, filename); save_buffer(attachment, extract_unsigned_long(cmd, 0), save_to); } - if (attachment) free(attachment); + if (attachment) { + free(attachment); + attachment = NULL; + } goto RMSGREAD; case 'd': scr_printf("*** Delete this message? "); @@ -1578,12 +1825,15 @@ RMSGREAD: scr_flush(); goto RMSGREAD; case 'r': savedpos = num_msgs; - entmsg(ipc, 1, (DEFAULT_ENTRY == 46 ? 2 : 0)); + entmsg(ipc, 1, ((userflags & US_EXTEDIT) ? 2 : 0)); num_msgs = savedpos; goto RMSGREAD; case 'u': list_urls(ipc); goto RMSGREAD; + case 'i': + image_view(ipc, msg_arr[a]); + goto RMSGREAD; case 'y': { /* hack hack hack */ /* find the next message by me, stay here if we find nothing */ @@ -1591,29 +1841,24 @@ RMSGREAD: scr_flush(); int lasta = a; for (finda = a; ((finda < num_msgs) && (finda >= 0)); finda += rdir) { - /* This is repetitively dumb, but that's what computers are for. - We have to load up messages until we find one by us */ - char buf[SIZ]; - int founda = 0; + /* This is repetitively dumb, but that's what computers are for. + We have to load up messages until we find one by us */ + char buf[SIZ]; + int founda = 0; + struct ctdlipcmessage *msg = NULL; - snprintf(buf, sizeof buf, "MSG0 %ld|1", msg_arr[finda]); /* read the header so we can get 'from=' */ - CtdlIPC_putline(ipc, buf); - CtdlIPC_getline(ipc, buf); - while (CtdlIPC_getline(ipc, buf), strcmp(buf, "000")) - { - if ((!strncasecmp(buf, "from=", 5)) && (finda != a)) /* Skip current message. */ - { - if (strcasecmp(buf+5, fullname) == 0) - { - a = lasta; /* meesa current */ - founda = 1; - } - } - } - // we are now in synch with the server - if (founda) - break; /* for */ - lasta = finda; /* keep one behind or we skip on the reentrance to the for */ + /* read the header so we can get 'from=' */ + r = CtdlIPCGetSingleMessage(ipc, msg_arr[finda], 1, 0, &msg, buf); + if (!strncasecmp(msg->author, fullname, sizeof(fullname))) { + a = lasta; /* meesa current */ + founda = 1; + } + + free(msg); + + if (founda) + break; /* for */ + lasta = finda; /* keep one behind or we skip on the reentrance to the for */ } /* for */ } /* case 'y' */ } /* switch */ @@ -1647,6 +1892,8 @@ void edit_system_message(CtdlIPC *ipc, char *which_message) void check_message_base(CtdlIPC *ipc) { char buf[SIZ]; + char *transcript = NULL; + int r; /* IPC response code */ scr_printf ("Please read the documentation before running this command.\n" @@ -1654,14 +1901,56 @@ void check_message_base(CtdlIPC *ipc) if (yesno() == 0) return; - CtdlIPC_putline(ipc, "FSCK"); - CtdlIPC_getline(ipc, buf); - if (buf[0] != '1') { - scr_printf("%s\n", &buf[4]); + r = CtdlIPCMessageBaseCheck(ipc, &transcript, buf); + if (r / 100 != 1) { + scr_printf("%s\n", buf); return; } - while (CtdlIPC_getline(ipc, buf), strcmp(buf, "000")) { - scr_printf("%s\n", buf); + while (transcript && strlen(transcript)) { + lines_printed = 1; + extract_token(buf, transcript, 0, '\n', sizeof buf); + remove_token(transcript, 0, '\n'); + pprintf("%s\n", buf); } + if (transcript) free(transcript); + return; +} + + +/* + * Loads the contents of a file into memory. Caller must free the allocated + * memory. + */ +char *load_message_from_file(FILE *src) +{ + size_t i; + size_t got = 0; + char *dest = NULL; + + fseek(src, 0, SEEK_END); + i = ftell(src); + rewind(src); + + dest = (char *)calloc(1, i + 1); + if (!dest) + return NULL; + + while (got < i) { + size_t g; + + g = fread(dest + got, 1, i - got, src); + got += g; + if (g < i - got) { + /* Interrupted system call, keep going */ + if (errno == EINTR) + continue; + /* At this point we have either EOF or error */ + i = got; + break; + } + dest[i] = 0; + } + + return dest; }