From 2a5a18bc8ba265b8605cfac40b6b90ddd73d4eac Mon Sep 17 00:00:00 2001 From: Andrew Pamment Date: Tue, 22 Mar 2016 21:46:43 +1000 Subject: [PATCH] Finished the very basics of mail system. --- .gitignore | 1 + ansis/mailmenu.ans | 15 ++ bbs.c | 8 + bbs.h | 3 + bbs.ini | 1 + localmail.ini | 1 + mail_menu.c | 613 +++++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 626 insertions(+), 16 deletions(-) create mode 100644 ansis/mailmenu.ans diff --git a/.gitignore b/.gitignore index 3e334c7..a3d1f24 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.sq3 *.core magicka +msgs/* diff --git a/ansis/mailmenu.ans b/ansis/mailmenu.ans new file mode 100644 index 0000000..e3cbc89 --- /dev/null +++ b/ansis/mailmenu.ans @@ -0,0 +1,15 @@ +[?7h +ÜÜÜÜÜÜÜÜÜÜÜ ÜÜÜÜÜÜ ÜÜ ÜÜ ÜÜÜÜ ÜÜÜÜÜÜÜÜÜÜÜ ÜÜÜÜÜÜÜ ÜÜÜÜÜÜ ÜÜ Ü ÜÜ +²ß°Ü ²ß°Ü ²Û²ß° ²ÛÛÛ²ßÛßßß ²ß°Ü ²ß°Ü ²Û²ßÜÜ ßß ²ß°Ü ²Û²ßÛ Û² +°² ² °² ² ±ß°²ßß߲߱² ±ÛÜß ±ß°² ² °² ² ±ß±²Ü° ²ß°² ² ±ß°²Üß ²  +ßß ß ßß ß °Û ßß ß °Û ßß °ßßßßßß ßß ß ßß ß °Û ßßßßßß ßß ß °Û ßßßßßß + ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + ³ C. Change Message Conference ³ E. Email a User³ + ³ A. Change Message Area³ R. Read your Email³ + ³ L. List Messages³³ + ³ P. Post a Message³³ + ³³³ + ³³ Q. Quit to Main Menu³ + ³³ G. Goodbye (Log Off)³ + ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ + diff --git a/bbs.c b/bbs.c index 90b18f4..556dcda 100644 --- a/bbs.c +++ b/bbs.c @@ -53,6 +53,12 @@ static int mail_area_handler(void* user, const char* section, const char* name, } else { mc->networked = 0; } + } else if (strcasecmp(name, "real names")) { + if (strcasecmp(value, "true") == 0) { + mc->realnames = 1; + } else { + mc->realnames = 0; + } } } else { // check if it's partially filled in @@ -109,6 +115,8 @@ static int handler(void* user, const char* section, const char* name, conf->ansi_path = strdup(value); } else if (strcasecmp(name, "bbs path") == 0) { conf->bbs_path = strdup(value); + } else if (strcasecmp(name, "email path") == 0) { + conf->email_path = strdup(value); } } else if (strcasecmp(section, "mail conferences") == 0) { if (conf->mail_conference_count == 0) { diff --git a/bbs.h b/bbs.h index d174969..0ab87f1 100644 --- a/bbs.h +++ b/bbs.h @@ -18,6 +18,7 @@ struct mail_conference { char *name; char *path; int networked; + int realnames; int sec_level; int mail_area_count; struct mail_area **mail_areas; @@ -29,6 +30,8 @@ struct bbs_config { char *ansi_path; char *bbs_path; + char *email_path; + int nodes; int newuserlvl; int mail_conference_count; diff --git a/bbs.ini b/bbs.ini index 2783b9d..1bbccd0 100644 --- a/bbs.ini +++ b/bbs.ini @@ -7,6 +7,7 @@ New User Level = 10 [paths] ANSI Path = /home/andrew/MagickaBBS/ansis BBS Path = /home/andrew/MagickaBBS +Email Path = /home/andrew/MagickaBBS/msgs/email [mail conferences] Local Mail = localmail.ini diff --git a/localmail.ini b/localmail.ini index 7a8fc62..99f0a28 100644 --- a/localmail.ini +++ b/localmail.ini @@ -1,6 +1,7 @@ [main] Visible Sec Level = 10 Networked = false +Real Names = false [General] Read Sec Level = 10 diff --git a/mail_menu.c b/mail_menu.c index b99dba1..10d889d 100644 --- a/mail_menu.c +++ b/mail_menu.c @@ -28,8 +28,9 @@ s_JamBase *open_jam_base(char *path) { return jb; } -char *editor(int socket, char *quote) { +char *editor(int socket, char *quote, char *from) { int lines = 0; + char buffer[256]; char linebuffer[80]; char prompt[12]; int doquit = 0; @@ -37,7 +38,31 @@ char *editor(int socket, char *quote) { int i; char *msg; int size = 0; + int quotelines = 0; + char **quotecontent; + int lineat=0; + int qfrom,qto; + if (quote != NULL) { + for (i=0;i %s", from[0], linebuffer); + quotelines++; + lineat = 0; + } else { + linebuffer[lineat++] = quote[i]; + linebuffer[lineat] = '\0'; + } + } + } s_putstring(socket, "\r\nMagicka Internal Editor, Type /S to Save, /A to abort and /? for help\r\n"); s_putstring(socket, "-------------------------------------------------------------------------------"); @@ -48,16 +73,23 @@ char *editor(int socket, char *quote) { if (linebuffer[0] == '/') { if (toupper(linebuffer[1]) == 'S') { for (i=0;i 0) { free(content); } + + if (quote != NULL) { + for (i=0;i quotelines) { + qto = quotelines; + } + if (qfrom < 0) { + qfrom = 0; + } + if (qfrom > qto) { + s_putstring(socket, "Quoting Cancelled\r\n"); + } + + for (i=qfrom;i<=qto;i++) { + if (lines == 0) { + content = (char **)malloc(sizeof(char *)); + } else { + content = (char **)realloc(content, sizeof(char *) * (lines + 1)); + } + + content[lines] = strdup(quotecontent[i]); + lines++; + } + + s_putstring(socket, "\r\nMagicka Internal Editor, Type /S to Save, /A to abort and /? for help\r\n"); + s_putstring(socket, "-------------------------------------------------------------------------------\r\n"); + for (i=0;icur_mail_conf]->mail_areas[user->cur_mail_area]->path); if (!jb) { @@ -155,6 +261,101 @@ void read_message(int socket, struct user_record *user, int mailno) { } } + s_putstring(socket, "Press R to reply or any other key to quit...\r\n"); + + c = s_getc(socket); + + if (tolower(c) == 'r') { + if (user->sec_level < conf.mail_conferences[user->cur_mail_conf]->mail_areas[user->cur_mail_area]->write_sec_level) { + s_putstring(socket, "\r\nSorry, you are not allowed to post in this area\r\n"); + } else { + if (subject != NULL) { + sprintf(buffer, "RE: %s", subject); + free(subject); + } + subject = (char *)malloc(strlen(buffer) + 1); + strcpy(subject, buffer); + if (from != NULL) { + strcpy(buffer, from); + free(from); + } + if (conf.mail_conferences[user->cur_mail_conf]->realnames == 0) { + from = (char *)malloc(strlen(user->loginname) + 1); + strcpy(from, user->loginname); + } else { + from = (char *)malloc(strlen(user->firstname) + strlen(user->lastname) + 2); + sprintf(from, "%s %s", user->firstname, user->lastname); + } + if (to != NULL) { + free(to); + } + to = (char *)malloc(strlen(buffer) + 1); + strcpy(to, buffer); + replybody = editor(socket, body, to); + if (replybody != NULL) { + jb = open_jam_base(conf.mail_conferences[user->cur_mail_conf]->mail_areas[user->cur_mail_area]->path); + if (!jb) { + printf("Error opening JAM base.. %s\n", conf.mail_conferences[user->cur_mail_conf]->mail_areas[user->cur_mail_area]->path); + free(replybody); + free(body); + free(subject); + free(to); + free(from); + return; + } + + JAM_ClearMsgHeader( &jmh ); + jmh.DateWritten = time(NULL); + + jsp = JAM_NewSubPacket(); + jsf.LoID = JAMSFLD_SENDERNAME; + jsf.HiID = 0; + jsf.DatLen = strlen(from); + jsf.Buffer = (uchar *)from; + JAM_PutSubfield(jsp, &jsf); + + jsf.LoID = JAMSFLD_RECVRNAME; + jsf.HiID = 0; + jsf.DatLen = strlen(to); + jsf.Buffer = (uchar *)to; + JAM_PutSubfield(jsp, &jsf); + + jsf.LoID = JAMSFLD_SUBJECT; + jsf.HiID = 0; + jsf.DatLen = strlen(subject); + jsf.Buffer = (uchar *)subject; + JAM_PutSubfield(jsp, &jsf); + + + while (1) { + z = JAM_LockMB(jb, 100); + if (z == 0) { + break; + } else if (z == JAM_LOCK_FAILED) { + sleep(1); + } else { + free(replybody); + free(body); + free(subject); + free(to); + free(from); + printf("Failed to lock msg base!\n"); + return; + } + } + if (JAM_AddMessage(jb, &jmh, jsp, (uchar *)replybody, strlen(replybody))) { + printf("Failed to add message\n"); + } + + JAM_UnlockMB(jb); + + JAM_DelSubPacket(jsp); + free(replybody); + JAM_CloseMB(jb); + } + } + } + free(body); if (from != NULL) { @@ -192,9 +393,15 @@ int mail_menu(int socket, struct user_record *user) { char *subject; char *from; char *to; + char *body; + char *replybody; + char *msg; int closed; + ulong jam_crc; + unsigned int lastmsg,currmsg; + int lines; while (!domail) { s_displayansi(socket, "mailmenu"); @@ -208,6 +415,10 @@ int mail_menu(int socket, struct user_record *user) { switch(tolower(c)) { case 'p': { + if (user->sec_level < conf.mail_conferences[user->cur_mail_conf]->mail_areas[user->cur_mail_area]->write_sec_level) { + s_putstring(socket, "\r\nSorry, you are not allowed to post in this area\r\n"); + break; + } s_putstring(socket, "\r\nTO: "); s_readstring(socket, buffer, 16); @@ -228,7 +439,7 @@ int mail_menu(int socket, struct user_record *user) { subject = strdup(buffer); // post a message - msg = editor(socket, NULL); + msg = editor(socket, NULL, NULL); if (msg != NULL) { jb = open_jam_base(conf.mail_conferences[user->cur_mail_conf]->mail_areas[user->cur_mail_area]->path); @@ -243,11 +454,17 @@ int mail_menu(int socket, struct user_record *user) { JAM_ClearMsgHeader( &jmh ); jmh.DateWritten = time(NULL); + if (conf.mail_conferences[user->cur_mail_conf]->realnames == 0) { + strcpy(buffer, user->loginname); + } else { + sprintf(buffer, "%s %s", user->firstname, user->lastname); + } + jsp = JAM_NewSubPacket(); jsf.LoID = JAMSFLD_SENDERNAME; jsf.HiID = 0; - jsf.DatLen = strlen(user->loginname); - jsf.Buffer = (uchar *)user->loginname; + jsf.DatLen = strlen(buffer); + jsf.Buffer = (uchar *)buffer; JAM_PutSubfield(jsp, &jsf); jsf.LoID = JAMSFLD_RECVRNAME; @@ -411,9 +628,10 @@ int mail_menu(int socket, struct user_record *user) { { s_putstring(socket, "\r\n\r\nMail Conferences:\r\n\r\n"); for (i=0;iname); - s_putstring(socket, buffer); - + if (conf.mail_conferences[i]->sec_level <= user->sec_level) { + sprintf(buffer, " %d. %s\r\n", i, conf.mail_conferences[i]->name); + s_putstring(socket, buffer); + } if (i != 0 && i % 22 == 0) { s_putstring(socket, "Press any key to continue...\r\n"); c = s_getc(socket); @@ -423,7 +641,7 @@ int mail_menu(int socket, struct user_record *user) { s_readstring(socket, buffer, 5); if (tolower(buffer[0]) != 'q') { j = atoi(buffer); - if (j < 0 || j >= conf.mail_conference_count) { + if (j < 0 || j >= conf.mail_conference_count || conf.mail_conferences[j]->sec_level > user->sec_level) { s_putstring(socket, "\r\nInvalid conference number!\r\n"); } else { s_putstring(socket, "\r\n"); @@ -437,9 +655,10 @@ int mail_menu(int socket, struct user_record *user) { { s_putstring(socket, "\r\n\r\nMail Areas:\r\n\r\n"); for (i=0;icur_mail_conf]->mail_area_count;i++) { - sprintf(buffer, " %d. %s\r\n", i, conf.mail_conferences[user->cur_mail_conf]->mail_areas[i]->name); - s_putstring(socket, buffer); - + if (conf.mail_conferences[user->cur_mail_conf]->mail_areas[i]->read_sec_level <= user->sec_level) { + sprintf(buffer, " %d. %s\r\n", i, conf.mail_conferences[user->cur_mail_conf]->mail_areas[i]->name); + s_putstring(socket, buffer); + } if (i != 0 && i % 22 == 0) { s_putstring(socket, "Press any key to continue...\r\n"); c = s_getc(socket); @@ -449,7 +668,7 @@ int mail_menu(int socket, struct user_record *user) { s_readstring(socket, buffer, 5); if (tolower(buffer[0]) != 'q') { j = atoi(buffer); - if (j < 0 || j >= conf.mail_conferences[user->cur_mail_conf]->mail_area_count) { + if (j < 0 || j >= conf.mail_conferences[user->cur_mail_conf]->mail_area_count || conf.mail_conferences[user->cur_mail_conf]->mail_areas[j]->read_sec_level > user->sec_level) { s_putstring(socket, "\r\nInvalid area number!\r\n"); } else { s_putstring(socket, "\r\n"); @@ -473,7 +692,369 @@ int mail_menu(int socket, struct user_record *user) { } } break; - + case 'e': + { + s_putstring(socket, "\r\nTO: "); + s_readstring(socket, buffer, 16); + + if (strlen(buffer) == 0) { + s_putstring(socket, "\r\nAborted\r\n"); + break; + } + if (check_user(buffer)) { + s_putstring(socket, "\r\n\r\nInvalid Username\r\n"); + break; + } + + to = strdup(buffer); + s_putstring(socket, "\r\nSUBJECT: "); + s_readstring(socket, buffer, 25); + subject = strdup(buffer); + + // post a message + msg = editor(socket, NULL, NULL); + + if (msg != NULL) { + jb = open_jam_base(conf.email_path); + if (!jb) { + printf("Error opening JAM base.. %s\n", conf.email_path); + free(msg); + free(to); + free(subject); + break; + } + + JAM_ClearMsgHeader( &jmh ); + jmh.DateWritten = time(NULL); + jmh.Attribute |= MSG_PRIVATE; + + strcpy(buffer, user->loginname); + + jsp = JAM_NewSubPacket(); + jsf.LoID = JAMSFLD_SENDERNAME; + jsf.HiID = 0; + jsf.DatLen = strlen(buffer); + jsf.Buffer = (uchar *)buffer; + JAM_PutSubfield(jsp, &jsf); + + jsf.LoID = JAMSFLD_RECVRNAME; + jsf.HiID = 0; + jsf.DatLen = strlen(to); + jsf.Buffer = (uchar *)to; + JAM_PutSubfield(jsp, &jsf); + + jsf.LoID = JAMSFLD_SUBJECT; + jsf.HiID = 0; + jsf.DatLen = strlen(subject); + jsf.Buffer = (uchar *)subject; + JAM_PutSubfield(jsp, &jsf); + + + while (1) { + z = JAM_LockMB(jb, 100); + if (z == 0) { + break; + } else if (z == JAM_LOCK_FAILED) { + sleep(1); + } else { + free(msg); + free(to); + free(subject); + printf("Failed to lock msg base!\n"); + break; + } + } + if (z != 0) { + JAM_CloseMB(jb); + break; + } + + if (JAM_AddMessage(jb, &jmh, jsp, (uchar *)msg, strlen(msg))) { + printf("Failed to add message\n"); + } + + JAM_UnlockMB(jb); + + JAM_DelSubPacket(jsp); + free(msg); + JAM_CloseMB(jb); + } + free(to); + free(subject); + + } + break; + case 'r': + { + // Read your email... + s_putstring(socket, "\r\n"); + // list mail in message base + jb = open_jam_base(conf.email_path); + if (!jb) { + printf("Error opening JAM base.. %s\n", conf.mail_conferences[user->cur_mail_conf]->mail_areas[user->cur_mail_area]->path); + break; + } else { + jam_crc = JAM_Crc32((uchar *)user->loginname, strlen(user->loginname)); + lastmsg = 0; + while (JAM_FindUser(jb, jam_crc, lastmsg, &currmsg) == 0) { + if (JAM_ReadMsgHeader(jb, currmsg, &jmh, &jsp) != 0) { + continue; + } + + if (jmh.Attribute & MSG_DELETED) { + JAM_DelSubPacket(jsp); + continue; + } + + if (jmh.Attribute & MSG_NODISP) { + JAM_DelSubPacket(jsp); + continue; + } + subject = NULL; + from = NULL; + + for (z=0;zNumFields;z++) { + if (jsp->Fields[z]->LoID == JAMSFLD_SUBJECT) { + subject = (char *)malloc(jsp->Fields[z]->DatLen + 1); + memset(subject, 0, jsp->Fields[z]->DatLen + 1); + memcpy(subject, jsp->Fields[z]->Buffer, jsp->Fields[z]->DatLen); + } + if (jsp->Fields[z]->LoID == JAMSFLD_SENDERNAME) { + from = (char *)malloc(jsp->Fields[z]->DatLen + 1); + memset(from, 0, jsp->Fields[z]->DatLen + 1); + memcpy(from, jsp->Fields[z]->Buffer, jsp->Fields[z]->DatLen); + } + } + sprintf(buffer, "[%3d]. %s From %s\r\n", currmsg, subject, from); + if (subject != NULL) { + free(subject); + } + if (from != NULL) { + free(from); + } + s_putstring(socket, buffer); + + lastmsg = currmsg + 1; + } + + if (lastmsg == 0) { + s_putstring(socket, "\r\nYou have no mail...\r\n"); + JAM_CloseMB(jb); + } else { + s_putstring(socket, "(#) View Message\r\n"); + s_readstring(socket, buffer, 5); + currmsg = atoi(buffer); + + if (JAM_ReadMsgHeader(jb, currmsg, &jmh, &jsp) != 0) { + JAM_CloseMB(jb); + break; + } + + if (jmh.Attribute & MSG_DELETED) { + JAM_DelSubPacket(jsp); + JAM_CloseMB(jb); + break; + } + + if (jmh.Attribute & MSG_NODISP) { + JAM_DelSubPacket(jsp); + JAM_CloseMB(jb); + break; + } + subject = NULL; + from = NULL; + to = NULL; + + for (z=0;zNumFields;z++) { + if (jsp->Fields[z]->LoID == JAMSFLD_SUBJECT) { + subject = (char *)malloc(jsp->Fields[z]->DatLen + 1); + memset(subject, 0, jsp->Fields[z]->DatLen + 1); + memcpy(subject, jsp->Fields[z]->Buffer, jsp->Fields[z]->DatLen); + } + if (jsp->Fields[z]->LoID == JAMSFLD_SENDERNAME) { + from = (char *)malloc(jsp->Fields[z]->DatLen + 1); + memset(from, 0, jsp->Fields[z]->DatLen + 1); + memcpy(from, jsp->Fields[z]->Buffer, jsp->Fields[z]->DatLen); + } + if (jsp->Fields[z]->LoID == JAMSFLD_RECVRNAME) { + to = (char *)malloc(jsp->Fields[z]->DatLen + 1); + memset(to, 0, jsp->Fields[z]->DatLen + 1); + memcpy(to, jsp->Fields[z]->Buffer, jsp->Fields[z]->DatLen); + } + } + + if (strcasecmp(from, user->loginname) == 0) { + sprintf(buffer, "\e[2JFrom : %s\r\n", from); + s_putstring(socket, buffer); + sprintf(buffer, "To : %s\r\n", to); + s_putstring(socket, buffer); + sprintf(buffer, "Subject : %s\r\n", subject); + s_putstring(socket, buffer); + s_putstring(socket, "-------------------------------------------------------------------------------\r\n"); + + body = (char *)malloc(jmh.TxtLen); + + JAM_ReadMsgText(jb, jmh.TxtOffset, jmh.TxtLen, (uchar *)body); + + JAM_CloseMB(jb); + + lines = 0; + + for (z=0;zloginname) + 1); + strcpy(from, user->loginname); + + if (to != NULL) { + free(to); + } + to = (char *)malloc(strlen(buffer) + 1); + strcpy(to, buffer); + + replybody = editor(socket, body, to); + + if (replybody != NULL) { + jb = open_jam_base(conf.email_path); + if (!jb) { + printf("Error opening JAM base.. %s\n", conf.email_path); + free(replybody); + free(body); + free(subject); + free(to); + free(from); + break; + } + + JAM_ClearMsgHeader( &jmh ); + jmh.DateWritten = time(NULL); + jmh.Attribute |= MSG_PRIVATE; + + jsp = JAM_NewSubPacket(); + jsf.LoID = JAMSFLD_SENDERNAME; + jsf.HiID = 0; + jsf.DatLen = strlen(from); + jsf.Buffer = (uchar *)from; + JAM_PutSubfield(jsp, &jsf); + + jsf.LoID = JAMSFLD_RECVRNAME; + jsf.HiID = 0; + jsf.DatLen = strlen(to); + jsf.Buffer = (uchar *)to; + JAM_PutSubfield(jsp, &jsf); + + jsf.LoID = JAMSFLD_SUBJECT; + jsf.HiID = 0; + jsf.DatLen = strlen(subject); + jsf.Buffer = (uchar *)subject; + JAM_PutSubfield(jsp, &jsf); + + free(body); + free(subject); + free(to); + free(from); + + while (1) { + z = JAM_LockMB(jb, 100); + if (z == 0) { + break; + } else if (z == JAM_LOCK_FAILED) { + sleep(1); + } else { + free(replybody); + printf("Failed to lock msg base!\n"); + break; + } + } + + if (z != 0) { + break; + } + + if (JAM_AddMessage(jb, &jmh, jsp, (uchar *)replybody, strlen(replybody))) { + printf("Failed to add message\n"); + } + + JAM_UnlockMB(jb); + + JAM_DelSubPacket(jsp); + free(replybody); + JAM_CloseMB(jb); + } + } else if (tolower(c) == 'd') { + jb = open_jam_base(conf.email_path); + if (!jb) { + printf("Error opening JAM base.. %s\n", conf.email_path); + free(body); + free(subject); + free(to); + free(from); + break; + } + + while (1) { + z = JAM_LockMB(jb, 100); + if (z == 0) { + break; + } else if (z == JAM_LOCK_FAILED) { + sleep(1); + } else { + free(body); + free(subject); + free(to); + free(from); + printf("Failed to lock msg base!\n"); + break; + } + } + if (z != 0) { + break; + } + + JAM_DeleteMessage(jb, currmsg); + JAM_UnlockMB(jb); + JAM_CloseMB(jb); + free(body); + free(subject); + free(to); + free(from); + } + + } else { + s_putstring(socket, "\r\nInvalid E-Mail\r\n"); + JAM_CloseMB(jb); + } + } + } + } + break; } }