AmendHub

Download:

jcs

/

subtext

/

amendments

/

71

mail: Add missing read field, implement message listing and reading


jcs made amendment 71 over 2 years ago
--- mail.c Sat Jan 29 18:36:52 2022 +++ mail.c Thu Feb 17 12:16:02 2022 @@ -34,6 +34,8 @@ struct bile_object_field mail_object_fields[] = { member_size(struct private_message, id), -1 }, { offsetof(struct private_message, time), member_size(struct private_message, time), -1 }, + { offsetof(struct private_message, read), + member_size(struct private_message, read), -1 }, { offsetof(struct private_message, sender_user_id), member_size(struct private_message, sender_user_id), -1 }, { offsetof(struct private_message, subject_size), @@ -51,12 +53,19 @@ struct bile_object_field mail_object_fields[] = { short mail_save(struct session *s, struct private_message *msg); size_t mail_find_for_user_id(unsigned long user_id, unsigned long **mail_ids); +void mail_help(struct session *s); +short mail_read(struct session *s, unsigned long idx); +void mail_list(struct session *s, bool sent, unsigned long **mail_ids, + size_t *nmsgs); void mail_menu(struct session *s) { + char arg[32]; + size_t count, nmsgs, id; bool done = false; - unsigned char c; + char *field; + unsigned long *mail_ids = NULL; if (!s->user) { session_output_string(s, "Mail is not available to guests.\r\n" @@ -65,53 +74,61 @@ mail_menu(struct session *s) return; } - session_output_template(s, "{{B}}Private Mail Menu{{/}}\r\n" - "{{B}}---------{{/}}\r\n"); - -mail_menu: - session_output_template(s, "({{B}}L{{/}})ist mail messages\r\n" - "({{B}}C{{/}})ompose new message\r\n" - "({{B}}Q{{/}})uit to main menu\r\n"); + session_output_template(s, "{{B}}Private Mail{{/}} " + "('{{B}}?{{/}}' for help)\r\n" + "{{B}}--------------------{{/}}\r\n"); session_flush(s); + mail_list(s, false, &mail_ids, &nmsgs); + while (!done) { session_output_template(s, "{{B}}Mail>{{/}} "); session_flush(s); -get_another_char: - c = session_input_char(s); - if (s->ending) + field = session_field_input(s, 30, 30, NULL, 0); + if (field == NULL) return; - if (c == '\r' || c == 0) - goto get_another_char; - - session_printf(s, "%c\r\n", c); + session_output(s, "\r\n", 2); session_flush(s); - switch (c) { - case 'c': - case 'C': - case 's': - case 'S': + if (sscanf(field, "c %s%n", &arg, &count) == 1 && count > 1) + mail_compose(s, arg, NULL, NULL); + else if (sscanf(field, "%ld%n", &id, &count) == 1 && count > 1) { + if (id < 1 || id > nmsgs) { + session_output_string(s, "Invalid message id\r\n"); + session_flush(s); + continue; + } + mail_read(s, mail_ids[id - 1]); + } else if (strcmp(field, "c") == 0) mail_compose(s, NULL, NULL, NULL); - break; - case 'l': - case 'L': - mail_list(s, false); - break; - case 'Q': - case 'q': - case 'X': - case 'x': + else if (strcmp(field, "l") == 0) + mail_list(s, false, &mail_ids, &nmsgs); + else if (strcmp(field, "q") == 0) done = true; - break; - case '?': - goto mail_menu; + else if (strcmp(field, "?") == 0) + mail_help(s); + else if (field[0] != '\0') { + session_output_template(s, + "Invalid option ({{B}}?{{/}} for help)\r\n"); + session_flush(s); } + + free(field); } } void +mail_help(struct session *s) +{ + session_output_template(s, + "({{B}}L{{/}})ist and read mail messages\r\n" + "({{B}}C{{/}})ompose new message\r\n" + "({{B}}Q{{/}})uit to main menu\r\n"); + session_flush(s); +} + +void mail_compose(struct session *s, char *initial_to, char *initial_subject, char *initial_body) { @@ -264,38 +281,44 @@ mail_compose_done: } void -mail_list(struct session *s, bool sent) +mail_list(struct session *s, bool sent, unsigned long **mail_ids, + size_t *nmsgs) { - unsigned long *mail_ids = NULL; - size_t nmsgs, n, size; + char time[24]; + size_t n, size; struct private_message msg; struct user *user; - char *data; + char *data, *input; + short id; - nmsgs = mail_find_for_user_id(s->user->id, &mail_ids); - if (nmsgs == 0) { + *nmsgs = mail_find_for_user_id(s->user->id, mail_ids); + if (*nmsgs == 0) { session_output_string(s, "No messages.\r\n"); session_flush(s); - if (mail_ids) - free(mail_ids); + if (*mail_ids) + free(*mail_ids); return; } - for (n = 0; n < nmsgs; n++) { - size = bile_read_alloc(db->bile, DB_MESSAGE_RTYPE, mail_ids[n], + for (n = 0; n < *nmsgs; n++) { + size = bile_read_alloc(db->bile, DB_MESSAGE_RTYPE, (*mail_ids)[n], &data); bile_unmarshall_object(db->bile, mail_object_fields, nitems(mail_object_fields), data, size, &msg); user = user_find(msg.sender_user_id); - session_printf(s, "%s%c [% 3ld] %s % 16s %s%s\r\n", - msg.read ? ansi(s, ANSI_BOLD, ANSI_END) : "", - msg.read ? 'N' : ' ', + strftime(time, sizeof(time), "%Y-%m-%d %H:%M", + localtime(&msg.time)); + + session_printf(s, "%s%c [%- 3ld] %s %- 10s %- 40s%s\r\n", + msg.read ? "" : ansi(s, ANSI_BOLD, ANSI_END), + msg.read ? ' ' : 'N', n + 1, - "(time)", + time, user ? user->username : "(unknown)", msg.subject, - msg.read ? ansi(s, ANSI_RESET, ANSI_END) : ""); + msg.read ? "" : ansi(s, ANSI_RESET, ANSI_END)); + session_flush(s); if (msg.subject) free(msg.subject); @@ -303,8 +326,47 @@ mail_list(struct session *s, bool sent) free(msg.body); free(data); } +} + +short +mail_read(struct session *s, unsigned long id) +{ + char time[32]; + size_t size; + struct private_message msg; + struct user *sender, *recipient; + char *data; - free(mail_ids); + size = bile_read_alloc(db->bile, DB_MESSAGE_RTYPE, id, &data); + bile_unmarshall_object(db->bile, mail_object_fields, + nitems(mail_object_fields), data, size, &msg); + sender = user_find(msg.sender_user_id); + recipient = user_find(msg.recipient_user_id); + + strftime(time, sizeof(time), "%Y-%m-%d %H:%M:%S", + localtime(&msg.time)); + + session_printf(s, "{{B}}From:{{/}} %s\r\n", + sender ? sender->username : "(unknown)"); + session_printf(s, "{{B}}To:{{/}} %s\r\n", + recipient ? recipient->username : "(unknown)"); + session_printf(s, "{{B}}Date:{{/}} %s\r\n", time); + session_printf(s, "{{B}}Subject:{{/}} %s\r\n", msg.subject); + session_flush(s); + session_output_string(s, "\r\n"); + session_output(s, msg.body, msg.body_size); + session_output_string(s, "\r\n"); + + if (!msg.read) { + msg.read = Time; + mail_save(s, &msg); + } + + if (msg.subject) + free(msg.subject); + if (msg.body) + free(msg.body); + free(data); } short @@ -333,9 +395,10 @@ mail_find_for_user_id(unsigned long user_id, unsigned unsigned long msg_user_id; struct user_map *muser; struct bile_object *o; - size_t nmsg, msgs_for_user, mail_ids_size; + size_t nmsg, msgs_for_user, mail_ids_size, id; + short i, j; - mail_ids_size = 256; + mail_ids_size = sizeof(unsigned long) * 16; *mail_ids = xmalloc(mail_ids_size); msgs_for_user = 0; @@ -345,12 +408,24 @@ mail_find_for_user_id(unsigned long user_id, unsigned sizeof(msg_user_id)); if (msg_user_id == user_id) { EXPAND_TO_FIT(*mail_ids, mail_ids_size, - msgs_for_user * sizeof(long), sizeof(long), 256); + msgs_for_user * sizeof(long), sizeof(long), + sizeof(unsigned long) * 16); (*mail_ids)[msgs_for_user++] = o->id; } free(o); nmsg++; } + /* sort by message id for consistent ordering */ + for (i = 0; i < msgs_for_user; i++) { + for (j = 0; j < msgs_for_user - i - 1; j++) { + if ((*mail_ids)[j] > (*mail_ids)[j + 1]) { + id = (*mail_ids)[j]; + (*mail_ids)[j] = (*mail_ids)[j + 1]; + (*mail_ids)[j + 1] = id; + } + } + } + return msgs_for_user; } --- mail.h Sat Jan 29 17:29:30 2022 +++ mail.h Sat Jan 29 23:36:48 2022 @@ -39,6 +39,5 @@ extern struct bile_object_field mail_object_fields[]; void mail_menu(struct session *s); void mail_compose(struct session *s, char *to, char *subject, char *body); -void mail_list(struct session *s, bool sent); #endif