2308 lines
52 KiB
C
2308 lines
52 KiB
C
/*****************************************************************************
|
|
*
|
|
* $Id$
|
|
* Purpose ...............: Message reading and writing.
|
|
* Todo ..................: Implement message groups.
|
|
*
|
|
*****************************************************************************
|
|
* Copyright (C) 1997-2002
|
|
*
|
|
* Michiel Broek FIDO: 2:280/2802
|
|
* Beekmansbos 10
|
|
* 1971 BV IJmuiden
|
|
* the Netherlands
|
|
*
|
|
* This file is part of MBSE BBS.
|
|
*
|
|
* This BBS is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
|
* later version.
|
|
*
|
|
* MBSE BBS is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with MBSE BBS; see the file COPYING. If not, write to the Free
|
|
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*****************************************************************************
|
|
*
|
|
* JAM(mbp) - Copyright 1993 Joaquim Homrighausen, Andrew Milner,
|
|
* Mats Birch, Mats Wallin.
|
|
* ALL RIGHTS RESERVED.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include "../config.h"
|
|
#include "../lib/libs.h"
|
|
#include "../lib/memwatch.h"
|
|
#include "../lib/mbse.h"
|
|
#include "../lib/structs.h"
|
|
#include "../lib/users.h"
|
|
#include "../lib/records.h"
|
|
#include "../lib/common.h"
|
|
#include "../lib/msgtext.h"
|
|
#include "../lib/clcomm.h"
|
|
#include "../lib/msg.h"
|
|
#include "mail.h"
|
|
#include "funcs.h"
|
|
#include "input.h"
|
|
#include "language.h"
|
|
#include "misc.h"
|
|
#include "timeout.h"
|
|
#include "oneline.h"
|
|
#include "exitinfo.h"
|
|
#include "lineedit.h"
|
|
#include "fsedit.h"
|
|
#include "filesub.h"
|
|
#include "msgutil.h"
|
|
#include "pop3.h"
|
|
#include "email.h"
|
|
#include "door.h"
|
|
#include "whoson.h"
|
|
|
|
|
|
|
|
/*
|
|
* Global variables
|
|
*/
|
|
unsigned long LastNum; /* Last read message number */
|
|
int Kludges = FALSE; /* Show kludges or not */
|
|
int Line = 1; /* Line counter in editor */
|
|
char *Message[TEXTBUFSIZE +1];/* Message compose text buffer */
|
|
FILE *qf; /* Quote file */
|
|
extern int do_mailout;
|
|
extern int LC_Wrote; /* Lastcaller info write message */
|
|
|
|
|
|
/*
|
|
* Internal prototypes
|
|
*/
|
|
|
|
void ShowMsgHdr(void); /* Show message header */
|
|
int Read_a_Msg(unsigned long Num, int);/* Read a message */
|
|
int Export_a_Msg(unsigned long Num);/* Export message to homedir */
|
|
int ReadPanel(void); /* Read panel bar */
|
|
int Save_Msg(int, faddr *); /* Save a message */
|
|
void Reply_Msg(int); /* Reply to message */
|
|
void Delete_MsgNum(unsigned long); /* Delete specified message */
|
|
int CheckUser(char *); /* Check if user exists */
|
|
int IsMe(char *); /* Test if this is my userrecord */
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
|
|
/*
|
|
* More prompt, returns 1 if user decides not to look any further.
|
|
*/
|
|
int LC(int Lines)
|
|
{
|
|
int z;
|
|
|
|
iLineCount += Lines;
|
|
|
|
if (iLineCount >= exitinfo.iScreenLen && iLineCount < 1000) {
|
|
iLineCount = 1;
|
|
|
|
pout(CFG.MoreF, CFG.MoreB, (char *) Language(61));
|
|
fflush(stdout);
|
|
alarm_on();
|
|
z = toupper(Getone());
|
|
|
|
if (z == Keystroke(61, 1)) {
|
|
printf("\n");
|
|
return(1);
|
|
}
|
|
|
|
if (z == Keystroke(61, 2))
|
|
iLineCount = 50000;
|
|
|
|
Blanker(strlen(Language(61)));
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Check if posting is allowed
|
|
*/
|
|
int Post_Allowed(void);
|
|
int Post_Allowed(void)
|
|
{
|
|
if (msgs.MsgKinds == RONLY) {
|
|
/* Message area is Readonly */
|
|
pout(LIGHTRED, BLACK, (char *) Language(437));
|
|
fflush(stdout);
|
|
sleep(3);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Check if Alias is allowed, and if so if the user
|
|
* wants to use this in the From: field.
|
|
*/
|
|
int Alias_Option(void);
|
|
int Alias_Option(void)
|
|
{
|
|
int rc = TRUE;
|
|
|
|
if (!msgs.Aliases)
|
|
return FALSE;
|
|
if (strlen(exitinfo.sHandle) == 0)
|
|
return FALSE;
|
|
|
|
/* Use your alias ( */
|
|
pout(CYAN, BLACK, (char *)Language(477));
|
|
pout(CYAN, BLACK, exitinfo.sHandle);
|
|
/* YN|) to post this message [Y/n]: */
|
|
pout(CYAN, BLACK, (char *)Language(478));
|
|
colour(CFG.MsgInputColourF, CFG.MsgInputColourB);
|
|
fflush(stdout);
|
|
alarm_on();
|
|
if (toupper(Getone()) == Keystroke(478, 1)) {
|
|
rc = FALSE;
|
|
printf("%c", Keystroke(478, 1));
|
|
} else {
|
|
printf("%c", Keystroke(478, 0));
|
|
}
|
|
Enter(2);
|
|
fflush(stdout);
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Check if netmail may be send crash or immediate.
|
|
*/
|
|
int Crash_Option(faddr *);
|
|
int Crash_Option(faddr *Dest)
|
|
{
|
|
node *Nlent;
|
|
int rc = 0;
|
|
unsigned short point;
|
|
|
|
if (exitinfo.Security.level < CFG.iCrashLevel)
|
|
return 0;
|
|
|
|
point = Dest->point;
|
|
Dest->point = 0;
|
|
|
|
if (((Nlent = getnlent(Dest)) != NULL) && (Nlent->addr.zone)) {
|
|
if (Nlent->oflags & OL_CM) {
|
|
/* Crash [y/N]: */
|
|
pout(CYAN, BLACK, (char *)Language(461));
|
|
colour(CFG.MsgInputColourF, CFG.MsgInputColourB);
|
|
fflush(stdout);
|
|
alarm_on();
|
|
if (toupper(Getone()) == Keystroke(461, 0)) {
|
|
rc = 1;
|
|
printf("%c", Keystroke(461, 0));
|
|
} else
|
|
printf("%c", Keystroke(461, 1));
|
|
} else {
|
|
/* Warning: node is not CM, send Immediate [y/N]: */
|
|
pout(CYAN, BLACK, (char *)Language(462));
|
|
colour(CFG.MsgInputColourF, CFG.MsgInputColourB);
|
|
fflush(stdout);
|
|
alarm_on();
|
|
if (toupper(Getone()) == Keystroke(462, 0)) {
|
|
rc = 2;
|
|
printf("%c", Keystroke(462, 0));
|
|
} else
|
|
printf("%c", Keystroke(462, 1));
|
|
}
|
|
fflush(stdout);
|
|
}
|
|
|
|
Dest->point = point;
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Ask if message must be private, only allowed in areas which allow
|
|
* both public and private. Private areas are forced to private.
|
|
*/
|
|
int IsPrivate(void);
|
|
int IsPrivate(void)
|
|
{
|
|
int rc = FALSE;
|
|
|
|
if (msgs.MsgKinds == BOTH) {
|
|
Enter(1);
|
|
/* Private [y/N]: */
|
|
pout(CYAN, BLACK, (char *) Language(163));
|
|
fflush(stdout);
|
|
alarm_on();
|
|
if (toupper(Getone()) == Keystroke(163, 0)) {
|
|
rc = TRUE;
|
|
printf("%c", Keystroke(163, 0));
|
|
} else {
|
|
printf("%c", Keystroke(163, 1));
|
|
}
|
|
fflush(stdout);
|
|
}
|
|
|
|
/*
|
|
* Allways set the private flag in Private areas.
|
|
*/
|
|
if (msgs.MsgKinds == PRIVATE)
|
|
rc = TRUE;
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
void Check_Attach(void);
|
|
void Check_Attach(void)
|
|
{
|
|
char *Attach, *dospath;
|
|
struct stat sb;
|
|
|
|
/*
|
|
* This is a dangerous option! Every file on the system to which the
|
|
* bbs has read access and is in the range of paths translatable by
|
|
* Unix to DOS can be attached to the netmail.
|
|
*/
|
|
if ((msgs.Type == NETMAIL) && (exitinfo.Security.level >= CFG.iAttachLevel)) {
|
|
|
|
Attach = calloc(PATH_MAX, sizeof(char));
|
|
while (TRUE) {
|
|
Enter(1);
|
|
/* Attach file [y/N]: */
|
|
pout(CYAN, BLACK, (char *)Language(463));
|
|
fflush(stdout);
|
|
alarm_on();
|
|
if (toupper(Getone()) == Keystroke(463, 0)) {
|
|
|
|
printf("%c", Keystroke(463, 0));
|
|
Enter(1);
|
|
/* Please enter filename: */
|
|
pout(YELLOW, BLACK, (char *)Language(245));
|
|
colour(CFG.MsgInputColourF, CFG.MsgInputColourB);
|
|
fflush(stdout);
|
|
alarm_on();
|
|
sprintf(Attach, "%s/", CFG.uxpath);
|
|
printf("%s", Attach);
|
|
fflush(stdout);
|
|
GetstrP(Attach, 71, strlen(Attach));
|
|
if (strcmp(Attach, "") == 0)
|
|
break;
|
|
|
|
if ((stat(Attach, &sb) == 0) && (S_ISREG(sb.st_mode))) {
|
|
dospath = xstrcpy(Unix2Dos(Attach));
|
|
if (strncasecmp(Attach, CFG.uxpath, strlen(CFG.uxpath)) == 0) {
|
|
Syslog('+', "FileAttach \"%s\"", Attach);
|
|
if (strlen(CFG.dospath))
|
|
strcpy(Msg.Subject, dospath);
|
|
else
|
|
sprintf(Msg.Subject, "%s", Attach);
|
|
Msg.FileAttach = TRUE;
|
|
Enter(1);
|
|
colour(11, 0);
|
|
/* File */ /* will be attached */
|
|
printf("%s %s %s", (char *)Language(464), Msg.Subject, Language(465));
|
|
Enter(1);
|
|
fflush(stdout);
|
|
sleep(2);
|
|
break;
|
|
} else {
|
|
Enter(1);
|
|
colour(10, 0);
|
|
/* File not within */
|
|
printf("%s \"%s\"", Language(466), CFG.uxpath);
|
|
Enter(1);
|
|
Pause();
|
|
}
|
|
} else {
|
|
Enter(1);
|
|
/* File does not exist, please try again ... */
|
|
pout(10, 0, (char *)Language(296));
|
|
Enter(1);
|
|
Pause();
|
|
}
|
|
} else {
|
|
break;
|
|
} /* if attach */
|
|
} /* while true */
|
|
free(Attach);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Comment to sysop
|
|
*/
|
|
void SysopComment(char *Cmt)
|
|
{
|
|
unsigned long tmp;
|
|
char *temp;
|
|
FILE *fp;
|
|
|
|
tmp = iMsgAreaNumber;
|
|
|
|
/*
|
|
* Make sure that the .quote file is empty.
|
|
*/
|
|
temp = calloc(PATH_MAX, sizeof(char));
|
|
sprintf(temp, "%s/%s/.quote", CFG.bbs_usersdir, exitinfo.Name);
|
|
if ((fp = fopen(temp, "w")) != NULL)
|
|
fclose(fp);
|
|
free(temp);
|
|
|
|
SetMsgArea(CFG.iSysopArea -1);
|
|
sprintf(Msg.From, "%s", CFG.sysop_name);
|
|
sprintf(Msg.Subject, "%s", Cmt);
|
|
Reply_Msg(FALSE);
|
|
|
|
SetMsgArea(tmp);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Edit a message. Call the users preffered editor.
|
|
*/
|
|
int Edit_Msg()
|
|
{
|
|
switch (exitinfo.MsgEditor) {
|
|
case LINEEDIT: return Line_Edit();
|
|
case FSEDIT: return Fs_Edit();
|
|
case EXTEDIT: return Ext_Edit();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Post a message, called from the menu or ReadPanel().
|
|
*/
|
|
void Post_Msg()
|
|
{
|
|
int i, x;
|
|
char *FidoNode;
|
|
faddr *Dest = NULL;
|
|
node *Nlent;
|
|
unsigned short point;
|
|
|
|
Line = 1;
|
|
WhosDoingWhat(READ_POST);
|
|
SetMsgArea(iMsgAreaNumber);
|
|
|
|
clear();
|
|
if (!Post_Allowed())
|
|
return;
|
|
|
|
for (i = 0; i < (TEXTBUFSIZE + 1); i++)
|
|
Message[i] = (char *) calloc(81, sizeof(char));
|
|
Line = 1;
|
|
|
|
Msg_New();
|
|
|
|
colour(LIGHTBLUE, BLACK);
|
|
/* Posting message in area: */
|
|
printf("\n%s\"%s\"\n", (char *) Language(156), sMsgAreaDesc);
|
|
|
|
if (Alias_Option()) {
|
|
/*
|
|
* Set Handle
|
|
*/
|
|
strcpy(Msg.From, exitinfo.sHandle);
|
|
tlcap(Msg.From); // Do we want this???
|
|
/* From : */
|
|
pout(YELLOW, BLACK, (char *) Language(157));
|
|
} else {
|
|
/*
|
|
* Normal from address, no alias
|
|
*/
|
|
/* From : */
|
|
pout(YELLOW, BLACK, (char *) Language(157));
|
|
if (msgs.Type == NEWS) {
|
|
if (CFG.EmailMode != E_PRMISP) {
|
|
/*
|
|
* If no internet mail domain, use fidonet addressing.
|
|
*/
|
|
Dest = fido2faddr(CFG.EmailFidoAka);
|
|
strcpy(Msg.From, exitinfo.sUserName);
|
|
tlcap(Msg.From);
|
|
} else {
|
|
sprintf(Msg.From, "%s@%s (%s)", exitinfo.Name, CFG.sysdomain, exitinfo.sUserName);
|
|
}
|
|
} else {
|
|
strcpy(Msg.From, exitinfo.sUserName);
|
|
tlcap(Msg.From);
|
|
}
|
|
}
|
|
|
|
pout(CFG.MsgInputColourF, CFG.MsgInputColourB, Msg.From);
|
|
Syslog('b', "Setting From: %s", Msg.From);
|
|
|
|
if ((msgs.Type == NEWS) || (msgs.Type == LIST)) {
|
|
/*
|
|
* Newsmode or maillist mode, automatic addressing to All.
|
|
* */
|
|
strcpy(Msg.To, "All");
|
|
} else {
|
|
while (TRUE) {
|
|
Enter(1);
|
|
/* To : */
|
|
pout(YELLOW, BLACK, (char *) Language(158));
|
|
|
|
colour(CFG.MsgInputColourF, CFG.MsgInputColourB);
|
|
Getname(Msg.To, 35);
|
|
|
|
if ((strcmp(Msg.To, "")) == 0) {
|
|
for(i = 0; i < (TEXTBUFSIZE + 1); i++)
|
|
free(Message[i]);
|
|
return;
|
|
}
|
|
|
|
if ((strcasecmp(Msg.To, "sysop")) == 0)
|
|
strcpy(Msg.To, CFG.sysop_name);
|
|
|
|
/*
|
|
* Localmail and Echomail may be addressed to All
|
|
*/
|
|
if ((msgs.Type == LOCALMAIL) || (msgs.Type == ECHOMAIL) || (msgs.Type == LIST)) {
|
|
if (strcasecmp(Msg.To, "all") == 0)
|
|
x = TRUE;
|
|
else {
|
|
/*
|
|
* Local users must exist in the userbase.
|
|
*/
|
|
if (msgs.Type == LOCALMAIL) {
|
|
/* Verifying user ... */
|
|
pout(CYAN, BLACK, (char *) Language(159));
|
|
x = CheckUser(Msg.To);
|
|
} else
|
|
x = TRUE;
|
|
}
|
|
} else if (msgs.Type == NETMAIL) {
|
|
x = FALSE;
|
|
pout(YELLOW, BLACK, (char *)"Address : ");
|
|
FidoNode = calloc(61, sizeof(char));
|
|
colour(CFG.MsgInputColourF, CFG.MsgInputColourB);
|
|
GetstrC(FidoNode, 60);
|
|
|
|
if ((Dest = parsefnode(FidoNode)) != NULL) {
|
|
point = Dest->point;
|
|
Dest->point = 0;
|
|
if (((Nlent = getnlent(Dest)) != NULL) && (Nlent->addr.zone)) {
|
|
colour(YELLOW, BLACK);
|
|
if (point)
|
|
printf("Boss : ");
|
|
else
|
|
printf("Node : ");
|
|
Dest->point = point;
|
|
colour(CFG.MsgInputColourF, CFG.MsgInputColourB);
|
|
printf("%s in %s", Nlent->name, Nlent->location);
|
|
colour(14, 0);
|
|
printf(" Is this correct Y/N: ");
|
|
colour(CFG.MsgInputColourF, CFG.MsgInputColourB);
|
|
fflush(stdout);
|
|
alarm_on();
|
|
|
|
if (toupper(Getone()) == 'Y') {
|
|
Enter(1);
|
|
sprintf(Msg.ToAddress, "%s", ascfnode(Dest, 0x1f));
|
|
x = TRUE;
|
|
switch (Crash_Option(Dest)) {
|
|
case 1: Msg.Crash = TRUE;
|
|
break;
|
|
case 2: Msg.Immediate = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
Dest->point = point;
|
|
printf("\r");
|
|
pout(CYAN, BLACK, (char *) Language(241));
|
|
fflush(stdout);
|
|
alarm_on();
|
|
if (toupper(Getone()) == Keystroke(241, 0)) {
|
|
x = TRUE;
|
|
Syslog('+', "Node %s not found, forced continue", FidoNode);
|
|
}
|
|
}
|
|
} else {
|
|
Syslog('m', "Can't parse address %s", FidoNode);
|
|
}
|
|
free(FidoNode);
|
|
} else {
|
|
x = FALSE;
|
|
}
|
|
|
|
if(!x) {
|
|
printf("\r");
|
|
/* User not found. Try again, or (Enter) to quit */
|
|
pout(CYAN, BLACK, (char *) Language(160));
|
|
} else
|
|
break;
|
|
}
|
|
}
|
|
|
|
Enter(1);
|
|
/* Subject : */
|
|
pout(YELLOW, BLACK, (char *) Language(161));
|
|
colour(CFG.MsgInputColourF, CFG.MsgInputColourB);
|
|
fflush(stdout);
|
|
alarm_on();
|
|
GetstrP(Msg.Subject, 65, 0);
|
|
tlf(Msg.Subject);
|
|
|
|
if((strcmp(Msg.Subject, "")) == 0) {
|
|
Enter(1);
|
|
/* Abort Message [y/N] ?: */
|
|
pout(CYAN, BLACK, (char *) Language(162));
|
|
fflush(stdout);
|
|
alarm_on();
|
|
|
|
if (toupper(Getone()) == Keystroke(162, 0)) {
|
|
for(i = 0; i < (TEXTBUFSIZE + 1); i++)
|
|
free(Message[i]);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If not addressed to "all" and the area is Private/Public we
|
|
* ask the user for the private flag.
|
|
*/
|
|
if ((strcasecmp(Msg.To, "all")) != 0)
|
|
Msg.Private = IsPrivate();
|
|
|
|
Check_Attach();
|
|
|
|
if (Edit_Msg())
|
|
Save_Msg(FALSE, Dest);
|
|
|
|
for (i = 0; i < (TEXTBUFSIZE + 1); i++)
|
|
free(Message[i]);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Save the message to disk.
|
|
*/
|
|
int Save_Msg(int IsReply, faddr *Dest)
|
|
{
|
|
int i;
|
|
char *temp;
|
|
FILE *fp;
|
|
|
|
if (Line < 2)
|
|
return TRUE;
|
|
|
|
if (!Open_Msgbase(msgs.Base, 'w'))
|
|
return FALSE;
|
|
|
|
Msg.Arrived = time(NULL) - (gmt_offset((time_t)0) * 60);
|
|
Msg.Written = Msg.Arrived;
|
|
Msg.Local = TRUE;
|
|
temp = calloc(PATH_MAX, sizeof(char));
|
|
|
|
if (strlen(Msg.ReplyTo) && (msgs.Type == NETMAIL)) {
|
|
/*
|
|
* Send message to internet gateway.
|
|
*/
|
|
Syslog('m', "UUCP message to %s", Msg.ReplyAddr);
|
|
sprintf(Msg.To, "UUCP");
|
|
Add_Headkludges(Dest, IsReply);
|
|
sprintf(temp, "To: %s", Msg.ReplyAddr);
|
|
MsgText_Add2(temp);
|
|
MsgText_Add2((char *)"");
|
|
} else {
|
|
Add_Headkludges(Dest, IsReply);
|
|
}
|
|
|
|
/*
|
|
* Add message text
|
|
*/
|
|
for (i = 1; i <= Line; i++) {
|
|
MsgText_Add2(Message[i]);
|
|
}
|
|
|
|
Add_Footkludges(TRUE, NULL);
|
|
|
|
/*
|
|
* Save if to disk
|
|
*/
|
|
Msg_AddMsg();
|
|
Msg_UnLock();
|
|
|
|
ReadExitinfo();
|
|
exitinfo.iPosted++;
|
|
WriteExitinfo();
|
|
|
|
do_mailout = TRUE;
|
|
LC_Wrote = TRUE;
|
|
|
|
Syslog('+', "Msg (%ld) to \"%s\", \"%s\", in %ld", Msg.Id, Msg.To, Msg.Subject, iMsgAreaNumber + 1);
|
|
|
|
colour(CFG.HiliteF, CFG.HiliteB);
|
|
/* Saving message to disk */
|
|
printf("\n%s(%ld)\n\n", (char *) Language(202), Msg.Id);
|
|
fflush(stdout);
|
|
sleep(2);
|
|
|
|
msgs.LastPosted = time(NULL);
|
|
msgs.Posted.total++;
|
|
msgs.Posted.tweek++;
|
|
msgs.Posted.tdow[Diw]++;
|
|
msgs.Posted.month[Miy]++;
|
|
|
|
sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT"));
|
|
|
|
if ((fp = fopen(temp, "r+")) != NULL) {
|
|
fseek(fp, msgshdr.hdrsize + (iMsgAreaNumber * (msgshdr.recsize + msgshdr.syssize)), SEEK_SET);
|
|
fwrite(&msgs, msgshdr.recsize, 1, fp);
|
|
fclose(fp);
|
|
}
|
|
|
|
/*
|
|
* Add quick mailscan info
|
|
*/
|
|
if (msgs.Type != LOCALMAIL) {
|
|
sprintf(temp, "%s/tmp/%smail.jam", getenv("MBSE_ROOT"),
|
|
((msgs.Type == ECHOMAIL) || (msgs.Type == LIST))? "echo" : "net");
|
|
if ((fp = fopen(temp, "a")) != NULL) {
|
|
fprintf(fp, "%s %lu\n", msgs.Base, Msg.Id);
|
|
fclose(fp);
|
|
}
|
|
}
|
|
free(temp);
|
|
Msg_Close();
|
|
|
|
SetMsgArea(iMsgAreaNumber);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Show message header screen top for reading messages.
|
|
*/
|
|
void ShowMsgHdr()
|
|
{
|
|
static char Buf1[35], Buf2[35], Buf3[81];
|
|
struct tm *tm;
|
|
time_t now;
|
|
int color;
|
|
|
|
Buf1[0] = '\0';
|
|
Buf2[0] = '\0';
|
|
Buf3[0] = '\0';
|
|
|
|
clear();
|
|
colour(BLUE, LIGHTGRAY);
|
|
printf(" %-70s", sMsgAreaDesc);
|
|
|
|
colour(RED, LIGHTGRAY);
|
|
printf("#%-5lu\n", Msg.Id);
|
|
|
|
/* Date : */
|
|
pout(YELLOW, BLACK, (char *) Language(206));
|
|
colour(GREEN, BLACK);
|
|
/* Use intermediate variable to prevent SIGBUS on Sparc's */
|
|
now = Msg.Written;
|
|
tm = gmtime(&now);
|
|
printf("%02d-%02d-%d %02d:%02d:%02d", tm->tm_mday, tm->tm_mon+1,
|
|
tm->tm_year+1900, tm->tm_hour, tm->tm_min, tm->tm_sec);
|
|
colour(LIGHTRED, BLACK);
|
|
if (Msg.Local) printf(" Local");
|
|
if (Msg.Intransit) printf(" Transit");
|
|
if (Msg.Private) printf(" Priv.");
|
|
if (Msg.Received) printf(" Rcvd");
|
|
if (Msg.Sent) printf(" Sent");
|
|
if (Msg.KillSent) printf(" KillSent");
|
|
if (Msg.ArchiveSent) printf(" ArchiveSent");
|
|
if (Msg.Hold) printf(" Hold");
|
|
if (Msg.Crash) printf(" Crash");
|
|
if (Msg.Immediate) printf(" Imm.");
|
|
if (Msg.Direct) printf(" Dir");
|
|
if (Msg.Gate) printf(" Gate");
|
|
if (Msg.FileRequest) printf(" Freq");
|
|
if (Msg.FileAttach) printf(" File");
|
|
if (Msg.TruncFile) printf(" TruncFile");
|
|
if (Msg.KillFile) printf(" KillFile");
|
|
if (Msg.ReceiptRequest) printf(" RRQ");
|
|
if (Msg.ConfirmRequest) printf(" CRQ");
|
|
if (Msg.Orphan) printf(" Orphan");
|
|
if (Msg.Encrypt) printf(" Crypt");
|
|
if (Msg.Compressed) printf(" Comp");
|
|
if (Msg.Escaped) printf(" 7bit");
|
|
if (Msg.ForcePU) printf(" FPU");
|
|
if (Msg.Localmail) printf(" Localmail");
|
|
if (Msg.Netmail) printf(" Netmail");
|
|
if (Msg.Echomail) printf(" Echomail");
|
|
if (Msg.News) printf(" News");
|
|
if (Msg.Email) printf(" E-mail");
|
|
if (Msg.Nodisplay) printf(" Nodisp");
|
|
if (Msg.Locked) printf(" LCK");
|
|
if (Msg.Deleted) printf(" Del");
|
|
printf("\n");
|
|
|
|
/* From : */
|
|
pout(YELLOW, BLACK, (char *) Language(209));
|
|
if (IsMe(Msg.From))
|
|
color = LIGHTGREEN;
|
|
else
|
|
color = GREEN;
|
|
colour(color++, BLACK);
|
|
printf("%s ", Msg.From);
|
|
if (iMsgAreaType != LOCALMAIL) {
|
|
colour(color, BLACK);
|
|
printf("(%s)", Msg.FromAddress);
|
|
}
|
|
printf("\n");
|
|
|
|
/* To : */
|
|
pout(YELLOW, BLACK, (char *) Language(208));
|
|
if (IsMe(Msg.To))
|
|
color = LIGHTGREEN;
|
|
else
|
|
color = GREEN;
|
|
colour(color++, BLACK);
|
|
printf("%s ", Msg.To);
|
|
if (iMsgAreaType == NETMAIL) {
|
|
colour(color, BLACK);
|
|
printf("(%s)", Msg.ToAddress);
|
|
}
|
|
printf("\n");
|
|
|
|
/* Subject : */
|
|
pout(YELLOW, BLACK, (char *) Language(210));
|
|
colour(GREEN, BLACK);
|
|
printf("%s\n", Msg.Subject);
|
|
|
|
colour(CFG.HiliteF, CFG.HiliteB);
|
|
colour(YELLOW, BLUE);
|
|
if (Msg.Reply)
|
|
sprintf(Buf1, "\"+\" %s %lu", (char *)Language(211), Msg.Reply);
|
|
if (Msg.Original)
|
|
sprintf(Buf2, " \"-\" %s %lu", (char *)Language(212), Msg.Original);
|
|
sprintf(Buf3, "%s%s ", Buf1, Buf2);
|
|
colour(YELLOW, BLUE);
|
|
printf("%78s \n", Buf3);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Export a message to file in the users home directory.
|
|
*/
|
|
int Export_a_Msg(unsigned long Num)
|
|
{
|
|
char *p;
|
|
int ShowMsg = TRUE;
|
|
|
|
LastNum = Num;
|
|
iLineCount = 7;
|
|
WhosDoingWhat(READ_POST);
|
|
Syslog('+', "Export msg %d in area #%d (%s)", Num, iMsgAreaNumber + 1, sMsgAreaDesc);
|
|
|
|
/*
|
|
* The area data is already set, so we can do the next things
|
|
*/
|
|
if (MsgBase.Total == 0) {
|
|
colour(WHITE, BLACK);
|
|
/* There are no messages in this area */
|
|
printf("\n%s\n\n", (char *) Language(205));
|
|
sleep(3);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!Msg_Open(sMsgAreaBase)) {
|
|
WriteError("Error open JAM base %s", sMsgAreaBase);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!Msg_ReadHeader(Num)) {
|
|
perror("");
|
|
colour(WHITE, BLACK);
|
|
printf("\n%s\n\n", (char *)Language(77));
|
|
Msg_Close();
|
|
sleep(3);
|
|
return FALSE;
|
|
}
|
|
|
|
if (Msg.Private) {
|
|
ShowMsg = FALSE;
|
|
if ((strcasecmp(exitinfo.sUserName, Msg.From) == 0) || (strcasecmp(exitinfo.sUserName, Msg.To) == 0))
|
|
ShowMsg = TRUE;
|
|
if (exitinfo.Security.level >= msgs.SYSec.level)
|
|
ShowMsg = TRUE;
|
|
}
|
|
|
|
if (!ShowMsg) {
|
|
printf("\n%s\n\n", (char *) Language(82));
|
|
Msg_Close();
|
|
sleep(3);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Export the message text to the file in the users home/wrk directory.
|
|
* Create the filename as <areanum>_<msgnum>.msg The message is
|
|
* written in M$DOS <cr/lf> format.
|
|
*/
|
|
p = calloc(128, sizeof(char));
|
|
sprintf(p, "%s/%s/wrk/%d_%lu.msg", CFG.bbs_usersdir, exitinfo.Name, iMsgAreaNumber + 1, Num);
|
|
if ((qf = fopen(p, "w")) != NULL) {
|
|
free(p);
|
|
p = NULL;
|
|
if (Msg_Read(Num, 80)) {
|
|
if ((p = (char *)MsgText_First()) != NULL)
|
|
do {
|
|
if ((p[0] == '\001') || (!strncmp(p, "SEEN-BY:", 8)) || (!strncmp(p, "AREA:", 5))) {
|
|
if (Kludges) {
|
|
if (p[0] == '\001') {
|
|
p[0] = 'a';
|
|
fprintf(qf, "^%s\r\n", p);
|
|
} else
|
|
fprintf(qf, "%s\r\n", p);
|
|
}
|
|
} else
|
|
fprintf(qf, "%s\r\n", p);
|
|
} while ((p = (char *)MsgText_Next()) != NULL);
|
|
}
|
|
fclose(qf);
|
|
} else {
|
|
WriteError("$Can't open %s", p);
|
|
}
|
|
Msg_Close();
|
|
|
|
/*
|
|
* Report the result.
|
|
*/
|
|
colour(CFG.TextColourF, CFG.TextColourB);
|
|
printf("\n\n%s", (char *) Language(46));
|
|
colour(CFG.HiliteF, CFG.HiliteB);
|
|
printf("%d_%lu.msg\n\n", iMsgAreaNumber + 1, Num);
|
|
Pause();
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Read a message on screen. Update the lastread pointers,
|
|
* except while scanning and reading new mail at logon.
|
|
*/
|
|
int Read_a_Msg(unsigned long Num, int UpdateLR)
|
|
{
|
|
char *p = NULL, *fn;
|
|
int ShowMsg = TRUE;
|
|
lastread LR;
|
|
|
|
LastNum = Num;
|
|
iLineCount = 7;
|
|
WhosDoingWhat(READ_POST);
|
|
|
|
/*
|
|
* The area data is already set, so we can do the next things
|
|
*/
|
|
if (MsgBase.Total == 0) {
|
|
colour(WHITE, BLACK);
|
|
/* There are no messages in this area */
|
|
printf("\n%s\n\n", (char *) Language(205));
|
|
sleep(3);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!Msg_Open(sMsgAreaBase)) {
|
|
WriteError("Error open JAM base %s", sMsgAreaBase);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!Msg_ReadHeader(Num)) {
|
|
perror("");
|
|
colour(WHITE, BLACK);
|
|
printf("\n%s\n\n", (char *)Language(77));
|
|
Msg_Close();
|
|
sleep(3);
|
|
return FALSE;
|
|
}
|
|
if (Msg.Private) {
|
|
ShowMsg = FALSE;
|
|
if ((strcasecmp(exitinfo.sUserName, Msg.From) == 0) || (strcasecmp(exitinfo.sUserName, Msg.To) == 0))
|
|
ShowMsg = TRUE;
|
|
if (exitinfo.Security.level >= msgs.SYSec.level)
|
|
ShowMsg = TRUE;
|
|
}
|
|
if (!ShowMsg) {
|
|
printf("\n%s\n\n", (char *) Language(82));
|
|
Msg_Close();
|
|
sleep(3);
|
|
return FALSE;
|
|
}
|
|
ShowMsgHdr();
|
|
|
|
/*
|
|
* Fill Quote file in case the user wants to reply. Note that line
|
|
* wrapping is set lower then normal message read, to create room
|
|
* for the Quote> strings at the start of each line.
|
|
*/
|
|
fn = calloc(128, sizeof(char));
|
|
sprintf(fn, "%s/%s/.quote", CFG.bbs_usersdir, exitinfo.Name);
|
|
if ((qf = fopen(fn, "w")) != NULL) {
|
|
if (Msg_Read(Num, 75)) {
|
|
if ((p = (char *)MsgText_First()) != NULL)
|
|
do {
|
|
if ((p[0] == '\001') || (!strncmp(p, "SEEN-BY:", 8)) || (!strncmp(p, "AREA:", 5))) {
|
|
if (Kludges) {
|
|
if (p[0] == '\001') {
|
|
p[0] = 'a';
|
|
fprintf(qf, "^%s\n", p);
|
|
} else
|
|
fprintf(qf, "%s\n", p);
|
|
}
|
|
} else
|
|
fprintf(qf, "%s\n", p);
|
|
} while ((p = (char *)MsgText_Next()) != NULL);
|
|
}
|
|
fclose(qf);
|
|
} else {
|
|
WriteError("$Can't open %s", p);
|
|
}
|
|
free(fn);
|
|
|
|
/*
|
|
* Show message text
|
|
*/
|
|
colour(CFG.TextColourF, CFG.TextColourB);
|
|
if (Msg_Read(Num, 78)) {
|
|
if ((p = (char *)MsgText_First()) != NULL) {
|
|
do {
|
|
if ((p[0] == '\001') || (!strncmp(p, "SEEN-BY:", 8)) || (!strncmp(p, "AREA:", 5))) {
|
|
if (Kludges) {
|
|
colour(7, 0);
|
|
printf("%s\n", p);
|
|
if (CheckLine(CFG.TextColourF, CFG.TextColourB, FALSE))
|
|
break;
|
|
}
|
|
} else {
|
|
colour(CFG.TextColourF, CFG.TextColourB);
|
|
if (strchr(p, '>') != NULL)
|
|
if ((strlen(p) - strlen(strchr(p, '>'))) < 10)
|
|
colour(CFG.HiliteF, CFG.HiliteB);
|
|
printf("%s\n", p);
|
|
if (CheckLine(CFG.TextColourF, CFG.TextColourB, FALSE))
|
|
break;
|
|
}
|
|
} while ((p = (char *)MsgText_Next()) != NULL);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set the Received status on this message if it's for the user.
|
|
*/
|
|
if ((!Msg.Received) && (strlen(Msg.To) > 0) &&
|
|
((strcasecmp(Msg.To, exitinfo.sUserName) == 0) || (strcasecmp(exitinfo.sHandle, Msg.To) == 0))) {
|
|
Syslog('m', "Marking message received");
|
|
Msg.Received = TRUE;
|
|
Msg.Read = time(NULL) - (gmt_offset((time_t)0) * 60);
|
|
if (Msg_Lock(30L)) {
|
|
Msg_WriteHeader(Num);
|
|
Msg_UnLock();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Update lastread pointer if needed. Netmail boards are always updated.
|
|
*/
|
|
if (Msg_Lock(30L) && (UpdateLR || msgs.Type == NETMAIL)) {
|
|
LR.UserID = grecno;
|
|
p = xstrcpy(exitinfo.sUserName);
|
|
if (Msg_GetLastRead(&LR) == TRUE) {
|
|
LR.LastReadMsg = Num;
|
|
if (Num > LR.HighReadMsg)
|
|
LR.HighReadMsg = Num;
|
|
if (LR.HighReadMsg > MsgBase.Highest)
|
|
LR.HighReadMsg = MsgBase.Highest;
|
|
LR.UserCRC = StringCRC32(tl(p));
|
|
if (!Msg_SetLastRead(LR))
|
|
WriteError("Error update lastread");
|
|
} else {
|
|
/*
|
|
* Append new lastread pointer
|
|
*/
|
|
LR.UserCRC = StringCRC32(tl(p));
|
|
LR.UserID = grecno;
|
|
LR.LastReadMsg = Num;
|
|
LR.HighReadMsg = Num;
|
|
if (!Msg_NewLastRead(LR))
|
|
WriteError("Can't append lastread");
|
|
}
|
|
free(p);
|
|
Msg_UnLock();
|
|
}
|
|
|
|
Msg_Close();
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Read Messages, called from menu
|
|
*/
|
|
void Read_Msgs()
|
|
{
|
|
char *temp;
|
|
unsigned long Start;
|
|
lastread LR;
|
|
|
|
colour(CFG.TextColourF, CFG.TextColourB);
|
|
/* Message area \"%s\" contains %lu messages. */
|
|
printf("\n%s\"%s\" %s%lu %s", (char *) Language(221), sMsgAreaDesc,
|
|
(char *) Language(222), MsgBase.Total, (char *) Language(223));
|
|
|
|
/*
|
|
* Check for lastread pointer, suggest lastread number for start.
|
|
*/
|
|
Start = MsgBase.Lowest;
|
|
if (Msg_Open(sMsgAreaBase)) {
|
|
LR.UserID = grecno;
|
|
if (Msg_GetLastRead(&LR))
|
|
Start = LR.HighReadMsg + 1;
|
|
else
|
|
Start = 1;
|
|
Msg_Close();
|
|
/*
|
|
* If we already have read the last message, the pointer is
|
|
* higher then HighMsgNum, we set it at HighMsgNum to prevent
|
|
* errors and read that message again.
|
|
*/
|
|
if (Start > MsgBase.Highest)
|
|
Start = MsgBase.Highest;
|
|
}
|
|
|
|
colour(WHITE, BLACK);
|
|
/* Please enter a message between */
|
|
printf("\n%s(%lu - %lu)", (char *) Language(224), MsgBase.Lowest, MsgBase.Highest);
|
|
/* Message number [ */
|
|
printf("\n%s%lu]: ", (char *) Language(225), Start);
|
|
|
|
temp = calloc(81, sizeof(char));
|
|
colour(CFG.InputColourF, CFG.InputColourB);
|
|
GetstrC(temp, 80);
|
|
if ((strcmp(temp, "")) != 0)
|
|
Start = atoi(temp);
|
|
free(temp);
|
|
|
|
if (!Read_a_Msg(Start, TRUE))
|
|
return;
|
|
|
|
if (MsgBase.Total == 0)
|
|
return;
|
|
|
|
while(ReadPanel()) {}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* The panel bar under the messages while reading
|
|
*/
|
|
int ReadPanel()
|
|
{
|
|
int input;
|
|
|
|
WhosDoingWhat(READ_POST);
|
|
|
|
colour(WHITE, RED);
|
|
if (msgs.UsrDelete || exitinfo.Security.level >= CFG.sysop_access) {
|
|
/* (A)gain, (N)ext, (L)ast, (R)eply, (E)nter, (D)elete, (Q)uit, e(X)port */
|
|
printf("%s", (char *) Language(214));
|
|
} else {
|
|
/* (A)gain, (N)ext, (L)ast, (R)eply, (E)nter, (Q)uit, e(X)port */
|
|
printf("%s", (char *) Language(215));
|
|
}
|
|
if (exitinfo.Security.level >= CFG.sysop_access)
|
|
printf(", (!)");
|
|
|
|
printf(": ");
|
|
|
|
fflush(stdout);
|
|
alarm_on();
|
|
input = toupper(Getone());
|
|
|
|
if (input == '!') {
|
|
if (exitinfo.Security.level >= CFG.sysop_access) {
|
|
if (Kludges)
|
|
Kludges = FALSE;
|
|
else
|
|
Kludges = TRUE;
|
|
}
|
|
Read_a_Msg(LastNum, TRUE);
|
|
} else if (input == Keystroke(214, 0)) { /* (A)gain */
|
|
Read_a_Msg(LastNum, TRUE);
|
|
|
|
} else if (input == Keystroke(214, 4)) { /* (P)ost */
|
|
Post_Msg();
|
|
Read_a_Msg(LastNum, TRUE);
|
|
|
|
} else if (input == Keystroke(214, 2)) { /* (L)ast */
|
|
if (LastNum > MsgBase.Lowest)
|
|
LastNum--;
|
|
Read_a_Msg(LastNum, TRUE);
|
|
|
|
} else if (input == Keystroke(214, 3)) { /* (R)eply */
|
|
Reply_Msg(TRUE);
|
|
Read_a_Msg(LastNum, TRUE);
|
|
|
|
} else if (input == Keystroke(214, 5)) { /* (Q)uit */
|
|
/* Quit */
|
|
printf("%s\n", (char *) Language(189));
|
|
return FALSE;
|
|
|
|
} else if (input == Keystroke(214, 7)) { /* e(X)port */
|
|
Export_a_Msg(LastNum);
|
|
Read_a_Msg(LastNum, TRUE);
|
|
|
|
} else if (input == '+') {
|
|
if (Msg.Reply)
|
|
LastNum = Msg.Reply;
|
|
Read_a_Msg(LastNum, TRUE);
|
|
|
|
} else if (input == '-') {
|
|
if (Msg.Original)
|
|
LastNum = Msg.Original;
|
|
Read_a_Msg(LastNum, TRUE);
|
|
|
|
} else if (input == Keystroke(214, 6)) { /* (D)elete */
|
|
Delete_MsgNum(LastNum);
|
|
if (LastNum < MsgBase.Highest) {
|
|
LastNum++;
|
|
Read_a_Msg(LastNum, TRUE);
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
/* Next */
|
|
pout(WHITE, BLACK, (char *) Language(216));
|
|
if (LastNum < MsgBase.Highest)
|
|
LastNum++;
|
|
else
|
|
return FALSE;
|
|
Read_a_Msg(LastNum, TRUE);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Reply message, in Msg.From and Msg.Subject must be the
|
|
* name to reply to and the subject. IsReply is true if the
|
|
* message is a real reply, and false for forced messages such
|
|
* as "message to sysop"
|
|
*/
|
|
void Reply_Msg(int IsReply)
|
|
{
|
|
int i, j, x;
|
|
char to[65];
|
|
char from[65];
|
|
char subj[72];
|
|
char msgid[81];
|
|
char replyto[81];
|
|
char replyaddr[81];
|
|
char *tmp, *buf;
|
|
char qin[6];
|
|
faddr *Dest = NULL;
|
|
|
|
if (!Post_Allowed())
|
|
return;
|
|
|
|
sprintf(from, "%s", Msg.To);
|
|
sprintf(to, "%s", Msg.From);
|
|
sprintf(replyto, "%s", Msg.ReplyTo);
|
|
sprintf(replyaddr, "%s", Msg.ReplyAddr);
|
|
Dest = parsefnode(Msg.FromAddress);
|
|
Syslog('m', "Parsed from address %s", ascfnode(Dest, 0x1f));
|
|
|
|
if (strncasecmp(Msg.Subject, "Re:", 3) && strncasecmp(Msg.Subject, "Re^2:", 5) && IsReply) {
|
|
sprintf(subj, "Re: %s", Msg.Subject);
|
|
} else {
|
|
sprintf(subj, "%s", Msg.Subject);
|
|
}
|
|
Syslog('m', "Reply msg to %s, subject %s", to, subj);
|
|
Syslog('m', "Msgid was %s", Msg.Msgid);
|
|
sprintf(msgid, "%s", Msg.Msgid);
|
|
|
|
x = 0;
|
|
WhosDoingWhat(READ_POST);
|
|
clear();
|
|
colour(BLUE, LIGHTGRAY);
|
|
printf(" %-71s", sMsgAreaDesc);
|
|
colour(RED, LIGHTGRAY);
|
|
printf("#%-5lu", MsgBase.Highest + 1);
|
|
|
|
colour(CFG.HiliteF, CFG.HiliteB);
|
|
sLine();
|
|
|
|
for (i = 0; i < (TEXTBUFSIZE + 1); i++)
|
|
Message[i] = (char *) calloc(81, sizeof(char));
|
|
Msg_New();
|
|
|
|
sprintf(Msg.Replyid, "%s", msgid);
|
|
sprintf(Msg.ReplyTo, "%s", replyto);
|
|
sprintf(Msg.ReplyAddr, "%s", replyaddr);
|
|
|
|
/* From : */
|
|
sprintf(Msg.From, "%s", exitinfo.sUserName);
|
|
pout(YELLOW, BLACK, (char *) Language(209));
|
|
pout(CFG.MsgInputColourF, CFG.MsgInputColourB, Msg.From);
|
|
Enter(1);
|
|
|
|
/* To : */
|
|
sprintf(Msg.To, "%s", to);
|
|
pout(YELLOW, BLACK, (char *) Language(208));
|
|
pout(CFG.MsgInputColourF, CFG.MsgInputColourB, Msg.To);
|
|
Enter(1);
|
|
|
|
/* Enter to keep Subject. */
|
|
pout(LIGHTRED, BLACK, (char *) Language(219));
|
|
Enter(1);
|
|
/* Subject : */
|
|
pout(YELLOW, BLACK, (char *) Language(210));
|
|
sprintf(Msg.Subject, "%s", subj);
|
|
pout(CFG.MsgInputColourF, CFG.MsgInputColourB, Msg.Subject);
|
|
|
|
x = strlen(subj);
|
|
fflush(stdout);
|
|
colour(CFG.MsgInputColourF, CFG.MsgInputColourB);
|
|
GetstrP(subj, 50, x);
|
|
fflush(stdout);
|
|
|
|
if (strlen(subj))
|
|
strcpy(Msg.Subject, subj);
|
|
tlf(Msg.Subject);
|
|
|
|
Msg.Private = IsPrivate();
|
|
Enter(1);
|
|
|
|
/*
|
|
* If netmail reply and enough security level, allow crashmail.
|
|
*/
|
|
if (msgs.Type == NETMAIL) {
|
|
switch (Crash_Option(Dest)) {
|
|
case 1: Msg.Crash = TRUE;
|
|
break;
|
|
case 2: Msg.Immediate = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Check_Attach();
|
|
|
|
/*
|
|
* Quote original message now, format the original users
|
|
* initials into qin. No quoting if this is a message to Sysop.
|
|
*/
|
|
Line = 1;
|
|
if (IsReply) {
|
|
sprintf(Message[1], "%s wrote to %s:", to, from);
|
|
memset(&qin, 0, sizeof(qin));
|
|
x = TRUE;
|
|
j = 0;
|
|
for (i = 0; i < strlen(to); i++) {
|
|
if (x && isalpha(to[i])) {
|
|
qin[j] = to[i];
|
|
j++;
|
|
x = FALSE;
|
|
}
|
|
if (to[i] == ' ' || to[i] == '.')
|
|
x = TRUE;
|
|
if (j == 6)
|
|
break;
|
|
}
|
|
Line = 2;
|
|
|
|
tmp = calloc(128, sizeof(char));
|
|
buf = calloc(128, sizeof(char));
|
|
|
|
sprintf(tmp, "%s/%s/.quote", CFG.bbs_usersdir, exitinfo.Name);
|
|
if ((qf = fopen(tmp, "r")) != NULL) {
|
|
while ((fgets(buf, 128, qf)) != NULL) {
|
|
Striplf(buf);
|
|
sprintf(Message[Line], "%s> %s", (char *)qin, buf);
|
|
Line++;
|
|
if (Line == TEXTBUFSIZE)
|
|
break;
|
|
}
|
|
fclose(qf);
|
|
} else
|
|
WriteError("$Can't read %s", tmp);
|
|
|
|
free(buf);
|
|
free(tmp);
|
|
}
|
|
|
|
if (Edit_Msg())
|
|
Save_Msg(IsReply, Dest);
|
|
|
|
for (i = 0; i < (TEXTBUFSIZE + 1); i++)
|
|
free(Message[i]);
|
|
}
|
|
|
|
|
|
|
|
int IsMe(char *Name)
|
|
{
|
|
char *p, *q;
|
|
int i, rc = FALSE;
|
|
|
|
if (strlen(Name) == 0)
|
|
return FALSE;
|
|
|
|
if (strcasecmp(Name, exitinfo.sUserName) == 0)
|
|
rc = TRUE;
|
|
|
|
if (strcasecmp(Name, exitinfo.sHandle) == 0)
|
|
rc = TRUE;
|
|
|
|
q = xstrcpy(Name);
|
|
if (strstr(q, (char *)"@")) {
|
|
p = strtok(q, "@");
|
|
for (i = 0; i < strlen(p); i++)
|
|
if (p[i] == '_')
|
|
p[i] = ' ';
|
|
if (strcasecmp(p, exitinfo.sUserName) == 0)
|
|
rc = TRUE;
|
|
if (strcasecmp(p, exitinfo.sHandle) == 0)
|
|
rc = TRUE;
|
|
if (strcasecmp(p, exitinfo.Name) == 0)
|
|
rc = TRUE;
|
|
}
|
|
free(q);
|
|
return rc ;
|
|
}
|
|
|
|
|
|
|
|
void QuickScan_Msgs()
|
|
{
|
|
int FoundMsg = FALSE;
|
|
long i;
|
|
|
|
iLineCount = 2;
|
|
WhosDoingWhat(READ_POST);
|
|
|
|
if (MsgBase.Total == 0) {
|
|
Enter(1);
|
|
/* There are no messages in this area. */
|
|
pout(WHITE, BLACK, (char *) Language(205));
|
|
Enter(3);
|
|
sleep(3);
|
|
return;
|
|
}
|
|
|
|
clear();
|
|
/* # From To Subject */
|
|
poutCR(YELLOW, BLUE, (char *) Language(220));
|
|
|
|
if (Msg_Open(sMsgAreaBase)) {
|
|
for (i = MsgBase.Lowest; i <= MsgBase.Highest; i++) {
|
|
if (Msg_ReadHeader(i) && ((msgs.Type != NETMAIL) ||
|
|
((msgs.Type == NETMAIL) && ((IsMe(Msg.From)) || (IsMe(Msg.To)))))) {
|
|
|
|
colour(WHITE, BLACK);
|
|
printf("%-6lu", Msg.Id);
|
|
if (IsMe(Msg.From))
|
|
colour(LIGHTCYAN, BLACK);
|
|
else
|
|
colour(CYAN, BLACK);
|
|
printf("%s ", padleft(Msg.From, 20, ' '));
|
|
|
|
if (IsMe(Msg.To))
|
|
colour(LIGHTGREEN, BLACK);
|
|
else
|
|
colour(GREEN, BLACK);
|
|
printf("%s ", padleft(Msg.To, 20, ' '));
|
|
colour(MAGENTA, BLACK);
|
|
printf("%s", padleft(Msg.Subject, 31, ' '));
|
|
printf("\n");
|
|
FoundMsg = TRUE;
|
|
if (LC(1))
|
|
break;
|
|
}
|
|
}
|
|
Msg_Close();
|
|
}
|
|
|
|
if(!FoundMsg) {
|
|
Enter(1);
|
|
/* There are no messages in this area. */
|
|
pout(LIGHTGREEN, BLACK, (char *) Language(205));
|
|
Enter(2);
|
|
sleep(3);
|
|
}
|
|
|
|
iLineCount = 2;
|
|
Pause();
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Called from the menu
|
|
*/
|
|
void Delete_Msg()
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Check linecounter for reading messages.
|
|
*/
|
|
int CheckLine(int FG, int BG, int Email)
|
|
{
|
|
int i, x, z;
|
|
|
|
x = strlen(Language(61));
|
|
iLineCount++;
|
|
|
|
if ((iLineCount >= (exitinfo.iScreenLen -1)) && (iLineCount < 1000)) {
|
|
iLineCount = 7;
|
|
|
|
DoNop();
|
|
pout(CFG.MoreF, CFG.MoreB, (char *) Language(61));
|
|
|
|
fflush(stdout);
|
|
alarm_on();
|
|
z = tolower(Getone());
|
|
|
|
for (i = 0; i < x; i++)
|
|
putchar('\b');
|
|
for (i = 0; i < x; i++)
|
|
putchar(' ');
|
|
for (i = 0; i < x; i++)
|
|
putchar('\b');
|
|
fflush(stdout);
|
|
|
|
switch(z) {
|
|
|
|
case 'n':
|
|
printf("\n");
|
|
return TRUE;
|
|
break;
|
|
case '=':
|
|
iLineCount = 1000;
|
|
}
|
|
if (Email)
|
|
ShowEmailHdr();
|
|
else
|
|
ShowMsgHdr();
|
|
colour(FG, BG);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Select message area from the list.
|
|
*/
|
|
void MsgArea_List(char *Option)
|
|
{
|
|
FILE *pAreas;
|
|
int iAreaCount = 6, Recno = 0;
|
|
int iOldArea = 0, iAreaNum = 0;
|
|
int iGotArea = FALSE; /* Flag to check if user typed in area */
|
|
long offset;
|
|
char *temp;
|
|
|
|
temp = calloc(PATH_MAX, sizeof(char));
|
|
|
|
sprintf(temp,"%s/etc/mareas.data", getenv("MBSE_ROOT"));
|
|
|
|
/*
|
|
* Save old area, incase he picks a invalid area
|
|
*/
|
|
iOldArea = iMsgAreaNumber;
|
|
|
|
if(( pAreas = fopen(temp, "rb")) == NULL) {
|
|
WriteError("Can't open msg areas file: %s", temp);
|
|
free(temp);
|
|
fclose(pAreas);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Count how many records there are
|
|
*/
|
|
fread(&msgshdr, sizeof(msgshdr), 1, pAreas);
|
|
fseek(pAreas, 0, SEEK_END);
|
|
iAreaNum = (ftell(pAreas) - msgshdr.hdrsize) / (msgshdr.recsize + msgshdr.syssize);
|
|
|
|
/*
|
|
* If there are menu options, select area direct.
|
|
*/
|
|
if (strlen(Option) != 0) {
|
|
|
|
if (strcmp(Option, "M+") == 0)
|
|
while(TRUE) {
|
|
iMsgAreaNumber++;
|
|
if (iMsgAreaNumber >= iAreaNum)
|
|
iMsgAreaNumber = 0;
|
|
|
|
offset = msgshdr.hdrsize + (iMsgAreaNumber * (msgshdr.recsize + msgshdr.syssize));
|
|
if(fseek(pAreas, offset, 0) != 0) {
|
|
printf("Can't move pointer there.");
|
|
}
|
|
|
|
fread(&msgs, msgshdr.recsize, 1, pAreas);
|
|
if ((Access(exitinfo.Security, msgs.RDSec)) && (msgs.Active) && (strlen(msgs.Password) == 0))
|
|
break;
|
|
}
|
|
|
|
if (strcmp(Option, "M-") == 0)
|
|
while(TRUE) {
|
|
iMsgAreaNumber--;
|
|
if (iMsgAreaNumber < 0)
|
|
iMsgAreaNumber = iAreaNum -1;
|
|
|
|
offset = msgshdr.hdrsize + (iMsgAreaNumber * (msgshdr.recsize + msgshdr.syssize));
|
|
if(fseek(pAreas, offset, 0) != 0) {
|
|
printf("Can't move pointer there.");
|
|
}
|
|
|
|
fread(&msgs, msgshdr.recsize, 1, pAreas);
|
|
if ((Access(exitinfo.Security, msgs.RDSec)) && (msgs.Active) && (strlen(msgs.Password) == 0))
|
|
break;
|
|
}
|
|
SetMsgArea(iMsgAreaNumber);
|
|
Syslog('+', "Msg area %lu %s", iMsgAreaNumber, sMsgAreaDesc);
|
|
free(temp);
|
|
fclose(pAreas);
|
|
return;
|
|
}
|
|
|
|
clear();
|
|
Enter(1);
|
|
pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(231));
|
|
Enter(2);
|
|
|
|
fseek(pAreas, msgshdr.hdrsize, 0);
|
|
|
|
while (fread(&msgs, msgshdr.recsize, 1, pAreas) == 1) {
|
|
/*
|
|
* Skip the echomail systems
|
|
*/
|
|
fseek(pAreas, msgshdr.syssize, SEEK_CUR);
|
|
if ((Access(exitinfo.Security, msgs.RDSec)) && (msgs.Active)) {
|
|
msgs.Name[31] = '\0';
|
|
|
|
colour(WHITE, BLACK);
|
|
printf("%5d", Recno + 1);
|
|
|
|
colour(LIGHTBLUE, BLACK);
|
|
printf(" %c ", 46);
|
|
|
|
colour(CYAN, BLACK);
|
|
printf("%-31s", msgs.Name);
|
|
|
|
iAreaCount++;
|
|
|
|
if ((iAreaCount % 2) == 0)
|
|
printf("\n");
|
|
else
|
|
printf(" ");
|
|
}
|
|
|
|
Recno++;
|
|
|
|
if((iAreaCount / 2) == exitinfo.iScreenLen) {
|
|
/* More (Y/n/=/Area #): */
|
|
pout(CFG.MoreF, CFG.MoreB, (char *) Language(207));
|
|
/*
|
|
* Ask user for Area or enter to continue
|
|
*/
|
|
colour(CFG.InputColourF, CFG.InputColourB);
|
|
fflush(stdout);
|
|
GetstrC(temp, 7);
|
|
|
|
if (toupper(temp[0]) == Keystroke(207, 1))
|
|
break;
|
|
|
|
if ((strcmp(temp, "")) != 0) {
|
|
iGotArea = TRUE;
|
|
break;
|
|
}
|
|
|
|
iAreaCount = 2;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If user type in area above during area listing
|
|
* don't ask for it again
|
|
*/
|
|
if (!iGotArea) {
|
|
Enter(1);
|
|
pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(232));
|
|
colour(CFG.InputColourF, CFG.InputColourB);
|
|
GetstrC(temp, 80);
|
|
}
|
|
|
|
/*
|
|
* Check if user pressed ENTER
|
|
*/
|
|
if ((strcmp(temp, "")) == 0) {
|
|
fclose(pAreas);
|
|
return;
|
|
}
|
|
iMsgAreaNumber = atoi(temp);
|
|
iMsgAreaNumber--;
|
|
|
|
/*
|
|
* Do a check in case user presses Zero
|
|
*/
|
|
if (iMsgAreaNumber == -1)
|
|
iMsgAreaNumber = 0;
|
|
|
|
offset = msgshdr.hdrsize + (iMsgAreaNumber * (msgshdr.recsize + msgshdr.syssize));
|
|
if(fseek(pAreas, offset, 0) != 0) {
|
|
printf("Can't move pointer there.");
|
|
}
|
|
fread(&msgs, msgshdr.recsize, 1, pAreas);
|
|
|
|
/*
|
|
* Do a check if area is greater or less number than allowed,
|
|
* security acces (level, flags and age) is oke, and the area
|
|
* is active.
|
|
*/
|
|
if (iMsgAreaNumber > iAreaNum || iMsgAreaNumber < 0 || (Access(exitinfo.Security, msgs.RDSec) == FALSE) || (!msgs.Active)) {
|
|
Enter(1);
|
|
/*
|
|
* Invalid area specified - Please try again ...
|
|
*/
|
|
pout(LIGHTRED, BLACK, (char *) Language(233));
|
|
Enter(2);
|
|
Pause();
|
|
fclose(pAreas);
|
|
iMsgAreaNumber = iOldArea;
|
|
SetMsgArea(iMsgAreaNumber);
|
|
free(temp);
|
|
return;
|
|
}
|
|
|
|
SetMsgArea(iMsgAreaNumber);
|
|
Syslog('+', "Msg area %lu %s", iMsgAreaNumber, sMsgAreaDesc);
|
|
|
|
/*
|
|
* Check if msg area has a password, if it does ask user for it
|
|
*/
|
|
if((strlen(msgs.Password)) > 2) {
|
|
Enter(2);
|
|
/* Please enter Area Password: */
|
|
pout(WHITE, BLACK, (char *) Language(233));
|
|
fflush(stdout);
|
|
colour(CFG.InputColourF, CFG.InputColourB);
|
|
GetstrC(temp, 20);
|
|
|
|
if((strcmp(temp, msgs.Password)) != 0) {
|
|
Enter(1);
|
|
pout(WHITE, BLACK, (char *) Language(234));
|
|
Syslog('!', "Incorrect Message Area # %d password given: %s", iMsgAreaNumber, temp);
|
|
SetMsgArea(iOldArea);
|
|
} else {
|
|
Enter(1);
|
|
pout(WHITE, BLACK, (char *) Language(235));
|
|
Enter(2);
|
|
}
|
|
Pause();
|
|
}
|
|
|
|
free(temp);
|
|
fclose(pAreas);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Function deletes a specified message.
|
|
*/
|
|
void Delete_MsgNum(unsigned long MsgNum)
|
|
{
|
|
int Result = FALSE;
|
|
|
|
pout(LIGHTRED, BLACK, (char *) Language(230));
|
|
|
|
if (Msg_Open(sMsgAreaBase)) {
|
|
if (Msg_Lock(15L)) {
|
|
Result = Msg_Delete(MsgNum);
|
|
Msg_UnLock();
|
|
}
|
|
Msg_Close();
|
|
}
|
|
|
|
if (Result)
|
|
Syslog('+', "Deleted msg #%lu in Area #%d (%s)", MsgNum, iMsgAreaNumber, sMsgAreaDesc);
|
|
else
|
|
WriteError("ERROR delete msg #%lu in Area #%d (%s)", MsgNum, iMsgAreaNumber, sMsgAreaDesc);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* This Function checks to see if the user exists in the user database
|
|
* and returns a int TRUE or FALSE
|
|
*/
|
|
int CheckUser(char *To)
|
|
{
|
|
FILE *pUsrConfig;
|
|
int Found = FALSE;
|
|
char *temp;
|
|
long offset;
|
|
unsigned long Crc;
|
|
|
|
temp = calloc(PATH_MAX, sizeof(char));
|
|
sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT"));
|
|
if ((pUsrConfig = fopen(temp,"rb")) == NULL) {
|
|
perror("");
|
|
WriteError("Can't open file %s for reading", temp);
|
|
Pause();
|
|
free(temp);
|
|
return FALSE;
|
|
}
|
|
free(temp);
|
|
fread(&usrconfighdr, sizeof(usrconfighdr), 1, pUsrConfig);
|
|
Crc = StringCRC32(tl(To));
|
|
|
|
while (fread(&usrconfig, usrconfighdr.recsize, 1, pUsrConfig) == 1) {
|
|
if (StringCRC32(tl(usrconfig.sUserName)) == Crc) {
|
|
Found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!Found)
|
|
Syslog('!', "User attempted to mail unknown user: %s", tlcap(To));
|
|
|
|
/*
|
|
* Restore users record
|
|
*/
|
|
offset = usrconfighdr.hdrsize + (grecno * usrconfighdr.recsize);
|
|
if (fseek(pUsrConfig, offset, 0) != 0)
|
|
printf("Can't move pointer there.");
|
|
else
|
|
fread(&usrconfig, usrconfighdr.recsize, 1, pUsrConfig);
|
|
fclose(pUsrConfig);
|
|
|
|
return Found;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Check for new mail
|
|
*/
|
|
void CheckMail()
|
|
{
|
|
FILE *pMsgArea, *Tmp;
|
|
int x, Found = 0;
|
|
int Color, Count = 0, Reading;
|
|
int OldMsgArea;
|
|
char *temp;
|
|
char *sFileName;
|
|
unsigned long i, Start;
|
|
typedef struct _Mailrec {
|
|
long Area;
|
|
unsigned long Msg;
|
|
} _Mail;
|
|
_Mail Mail;
|
|
lastread LR;
|
|
|
|
OldMsgArea = iMsgAreaNumber;
|
|
iMsgAreaNumber = 0;
|
|
Syslog('+', "Start checking for new mail");
|
|
|
|
clear();
|
|
/* Checking your mail box ... */
|
|
language(LIGHTGREEN, BLACK, 150);
|
|
Enter(2);
|
|
Color = LIGHTBLUE;
|
|
fflush(stdout);
|
|
|
|
/*
|
|
* Open temporary file
|
|
*/
|
|
if ((Tmp = tmpfile()) == NULL) {
|
|
WriteError("$unable to open temporary file");
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* First check the e-mail mailbox
|
|
*/
|
|
temp = calloc(PATH_MAX, sizeof(char));
|
|
if (exitinfo.Email && strlen(exitinfo.Password)) {
|
|
check_popmail(exitinfo.Name, exitinfo.Password);
|
|
colour(Color++, BLACK);
|
|
printf("\re-mail Private e-mail mailbox");
|
|
fflush(stdout);
|
|
Count = 0;
|
|
sprintf(temp, "%s/%s/mailbox", CFG.bbs_usersdir, exitinfo.Name);
|
|
SetEmailArea((char *)"mailbox");
|
|
if (Msg_Open(temp)) {
|
|
/*
|
|
* Check lastread pointer, if none found start
|
|
* at the begin of the messagebase.
|
|
*/
|
|
LR.UserID = grecno;
|
|
if (Msg_GetLastRead(&LR))
|
|
Start = LR.HighReadMsg + 1;
|
|
else
|
|
Start = EmailBase.Lowest;
|
|
|
|
for (i = Start; i <= EmailBase.Highest; i++) {
|
|
if (Msg_ReadHeader(i)) {
|
|
/*
|
|
* Only check the received status of the email. The mail
|
|
* may not be direct addressed to this user (aliases database)
|
|
* but if it is in his mailbox it is always for the user.
|
|
*/
|
|
if (!Msg.Received) {
|
|
/*
|
|
* Store area and message number in temporary file.
|
|
*/
|
|
Mail.Area = -1; /* Means e-mail mailbox */
|
|
Mail.Msg = Msg.Id + EmailBase.Lowest -1;
|
|
fwrite(&Mail, sizeof(Mail), 1, Tmp);
|
|
Count++;
|
|
Found++;
|
|
}
|
|
}
|
|
}
|
|
Msg_Close();
|
|
}
|
|
if (Count) {
|
|
colour(CFG.TextColourF, CFG.TextColourB);
|
|
/* messages in */
|
|
printf("\n\n%d %s private e-mail mailbox\n\n", Count, (char *)Language(213));
|
|
Syslog('m', " %d messages in private e-mail mailbox", Count);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Open the message base configuration
|
|
*/
|
|
sFileName = calloc(PATH_MAX, sizeof(char));
|
|
sprintf(sFileName,"%s/etc/mareas.data", getenv("MBSE_ROOT"));
|
|
if((pMsgArea = fopen(sFileName, "r+")) == NULL) {
|
|
WriteError("$Can't open: %s", sFileName);
|
|
free(temp);
|
|
free(sFileName);
|
|
return;
|
|
}
|
|
fread(&msgshdr, sizeof(msgshdr), 1, pMsgArea);
|
|
|
|
/*
|
|
* Check all normal areas one by one
|
|
*/
|
|
while (fread(&msgs, msgshdr.recsize, 1, pMsgArea) == 1) {
|
|
fseek(pMsgArea, msgshdr.syssize, SEEK_CUR);
|
|
if ((msgs.Active) && (exitinfo.Security.level >= msgs.RDSec.level)) {
|
|
SetMsgArea(iMsgAreaNumber);
|
|
sprintf(temp, "%d", iMsgAreaNumber + 1);
|
|
colour(Color, 0);
|
|
if (Color < WHITE)
|
|
Color++;
|
|
else
|
|
Color = LIGHTBLUE;
|
|
printf("\r%6s %-40s", temp, sMsgAreaDesc);
|
|
fflush(stdout);
|
|
Count = 0;
|
|
Nopper();
|
|
|
|
if (Msg_Open(sMsgAreaBase)) {
|
|
/*
|
|
* Check lastread pointer, if none found start
|
|
* at the begin of the messagebase.
|
|
*/
|
|
LR.UserID = grecno;
|
|
if (Msg_GetLastRead(&LR))
|
|
Start = LR.HighReadMsg + 1;
|
|
else
|
|
Start = MsgBase.Lowest;
|
|
|
|
for (i = Start; i <= MsgBase.Highest; i++) {
|
|
if (Msg_ReadHeader(i)) {
|
|
if ((!Msg.Received) && (IsMe(Msg.To))) {
|
|
/*
|
|
* Store area and message number
|
|
* in temporary file.
|
|
*/
|
|
Mail.Area = iMsgAreaNumber;
|
|
Mail.Msg = Msg.Id + MsgBase.Lowest -1;
|
|
fwrite(&Mail, sizeof(Mail), 1, Tmp);
|
|
Count++;
|
|
Found++;
|
|
}
|
|
}
|
|
}
|
|
Msg_Close();
|
|
}
|
|
if (Count) {
|
|
colour(CFG.TextColourF, CFG.TextColourB);
|
|
/* messages in */
|
|
printf("\n\n%d %s %s\n\n", Count, (char *)Language(213), sMsgAreaDesc);
|
|
Syslog('m', " %d messages in %s", Count, sMsgAreaDesc);
|
|
}
|
|
}
|
|
iMsgAreaNumber++;
|
|
}
|
|
|
|
fclose(pMsgArea);
|
|
putchar('\r');
|
|
for (i = 0; i < 48; i++)
|
|
putchar(' ');
|
|
putchar('\r');
|
|
|
|
if (Found) {
|
|
colour(YELLOW, BLACK);
|
|
/* You have messages, read your mail now? [Y/n]: */
|
|
printf("\n%s%d %s", (char *) Language(142), Found, (char *) Language(143));
|
|
colour(CFG.InputColourF, CFG.InputColourB);
|
|
fflush(stdout);
|
|
fflush(stdin);
|
|
alarm_on();
|
|
|
|
if (toupper(Getone()) != Keystroke(143,1)) {
|
|
rewind(Tmp);
|
|
Reading = TRUE;
|
|
|
|
while ((Reading) && (fread(&Mail, sizeof(Mail), 1, Tmp) == 1)) {
|
|
if (Mail.Area == -1) {
|
|
/*
|
|
* Private e-mail
|
|
*/
|
|
Read_a_Email(Mail.Msg);
|
|
} else {
|
|
SetMsgArea(Mail.Area);
|
|
Read_a_Msg(Mail.Msg, FALSE);
|
|
}
|
|
/* (R)eply, (N)ext, (Q)uit */
|
|
pout(CFG.CRColourF, CFG.CRColourB, (char *)Language(218));
|
|
fflush(stdout);
|
|
fflush(stdin);
|
|
alarm_on();
|
|
x = toupper(Getone());
|
|
|
|
if (x == Keystroke(218, 0)) {
|
|
Syslog('m', " Reply!");
|
|
if (Mail.Area == -1) {
|
|
} else {
|
|
Reply_Msg(TRUE);
|
|
}
|
|
}
|
|
if (x == Keystroke(218, 2)) {
|
|
Syslog('m', " Quit check for new mail");
|
|
iMsgAreaNumber = OldMsgArea;
|
|
fclose(Tmp);
|
|
SetMsgArea(OldMsgArea);
|
|
printf("\n\n");
|
|
free(temp);
|
|
free(sFileName);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
language(LIGHTRED, BLACK, 144);
|
|
Enter(1);
|
|
sleep(3);
|
|
} /* if (Found) */
|
|
|
|
iMsgAreaNumber = OldMsgArea;
|
|
fclose(Tmp);
|
|
SetMsgArea(OldMsgArea);
|
|
printf("\n\n");
|
|
free(temp);
|
|
free(sFileName);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Status of all mail areas.
|
|
*/
|
|
void MailStatus()
|
|
{
|
|
FILE *pMsgArea;
|
|
int Count = 0;
|
|
int OldMsgArea;
|
|
char temp[81];
|
|
char *sFileName;
|
|
unsigned long i;
|
|
|
|
sFileName = calloc(PATH_MAX, sizeof(char));
|
|
OldMsgArea = iMsgAreaNumber;
|
|
iMsgAreaNumber = 0;
|
|
clear();
|
|
colour(YELLOW, BLUE);
|
|
/* Area Type Description Messages Personal */
|
|
printf("%-79s", (char *)Language(226));
|
|
Enter(1);
|
|
iLineCount = 2;
|
|
fflush(stdout);
|
|
|
|
if (exitinfo.Email) {
|
|
sprintf(temp, "%s", sMailbox);
|
|
for (i = 0; i < 3; i++) {
|
|
switch (i) {
|
|
case 0: SetEmailArea((char *)"mailbox");
|
|
break;
|
|
case 1: SetEmailArea((char *)"archive");
|
|
break;
|
|
case 2: SetEmailArea((char *)"trash");
|
|
break;
|
|
}
|
|
colour(LIGHTRED, BLACK);
|
|
printf(" Email");
|
|
colour(LIGHTCYAN, BLACK);
|
|
printf(" %-40s", Language(467 + i));
|
|
colour(YELLOW, BLACK);
|
|
if (EmailBase.Highest)
|
|
printf(" %8lu", EmailBase.Highest - EmailBase.Lowest + 1);
|
|
else
|
|
printf(" 0");
|
|
colour(LIGHTBLUE, BLACK);
|
|
if (EmailBase.Highest)
|
|
printf(" %8lu\n", EmailBase.Highest - EmailBase.Lowest + 1);
|
|
else
|
|
printf(" 0\n");
|
|
}
|
|
iLineCount = 5;
|
|
SetEmailArea(temp);
|
|
}
|
|
|
|
/*
|
|
* Open the message base configuration
|
|
*/
|
|
sprintf(sFileName,"%s/etc/mareas.data", getenv("MBSE_ROOT"));
|
|
if((pMsgArea = fopen(sFileName, "r+")) == NULL) {
|
|
WriteError("Can't open file: %s", sFileName);
|
|
free(sFileName);
|
|
return;
|
|
}
|
|
fread(&msgshdr, sizeof(msgshdr), 1, pMsgArea);
|
|
|
|
/*
|
|
* Check all areas one by one
|
|
*/
|
|
while (fread(&msgs, msgshdr.recsize, 1, pMsgArea) == 1) {
|
|
fseek(pMsgArea, msgshdr.syssize, SEEK_CUR);
|
|
if ((msgs.Active) && (exitinfo.Security.level >= msgs.RDSec.level)) {
|
|
SetMsgArea(iMsgAreaNumber);
|
|
sprintf(temp, "%d", iMsgAreaNumber + 1);
|
|
colour(WHITE, BLACK);
|
|
printf("%5s", temp);
|
|
colour(LIGHTRED, BLACK);
|
|
switch(msgs.Type) {
|
|
case LOCALMAIL:
|
|
printf(" Local");
|
|
break;
|
|
|
|
case NETMAIL:
|
|
printf(" Net ");
|
|
break;
|
|
|
|
case LIST:
|
|
case ECHOMAIL:
|
|
printf(" Echo ");
|
|
break;
|
|
|
|
case NEWS:
|
|
printf(" News ");
|
|
break;
|
|
}
|
|
colour(LIGHTCYAN, BLACK);
|
|
printf(" %-40s", sMsgAreaDesc);
|
|
Count = 0;
|
|
|
|
if (Msg_Open(sMsgAreaBase)) {
|
|
for (i = MsgBase.Lowest; i <= MsgBase.Highest; i++) {
|
|
if (Msg_ReadHeader(i)) {
|
|
if (IsMe(Msg.To) || IsMe(Msg.From))
|
|
Count++;
|
|
}
|
|
}
|
|
Msg_Close();
|
|
} else
|
|
WriteError("Error open JAM %s", sMsgAreaBase);
|
|
colour(YELLOW, BLACK);
|
|
if (MsgBase.Highest)
|
|
printf(" %8lu", MsgBase.Highest - MsgBase.Lowest + 1);
|
|
else
|
|
printf(" 0");
|
|
colour(LIGHTBLUE, BLACK);
|
|
printf(" %8d\n", Count);
|
|
if (LC(1))
|
|
break;
|
|
}
|
|
iMsgAreaNumber++;
|
|
}
|
|
|
|
fclose(pMsgArea);
|
|
SetMsgArea(OldMsgArea);
|
|
free(sFileName);
|
|
Pause();
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Set message area number, set global area description and JAM path
|
|
*/
|
|
void SetMsgArea(unsigned long AreaNum)
|
|
{
|
|
FILE *pMsgArea;
|
|
long offset;
|
|
char *sFileName;
|
|
|
|
sFileName = calloc(PATH_MAX, sizeof(char));
|
|
sprintf(sFileName,"%s/etc/mareas.data", getenv("MBSE_ROOT"));
|
|
memset(&msgs, 0, sizeof(msgs));
|
|
|
|
if((pMsgArea = fopen(sFileName, "r")) == NULL) {
|
|
WriteError("$Can't open file: %s", sFileName);
|
|
free(sFileName);
|
|
return;
|
|
}
|
|
|
|
fread(&msgshdr, sizeof(msgshdr), 1, pMsgArea);
|
|
offset = msgshdr.hdrsize + (AreaNum * (msgshdr.recsize + msgshdr.syssize));
|
|
if(fseek(pMsgArea, offset, 0) != 0) {
|
|
WriteError("$Can't move pointer in %s",sFileName);
|
|
free(sFileName);
|
|
return;
|
|
}
|
|
|
|
fread(&msgs, msgshdr.recsize, 1, pMsgArea);
|
|
strcpy(sMsgAreaDesc, msgs.Name);
|
|
strcpy(sMsgAreaBase, msgs.Base);
|
|
iMsgAreaNumber = AreaNum;
|
|
iMsgAreaType = msgs.Type;
|
|
|
|
fclose(pMsgArea);
|
|
|
|
/*
|
|
* Get information from the message base
|
|
*/
|
|
|
|
if (Msg_Open(sMsgAreaBase)) {
|
|
|
|
MsgBase.Lowest = Msg_Lowest();
|
|
MsgBase.Highest = Msg_Highest();
|
|
MsgBase.Total = Msg_Number();
|
|
Msg_Close();
|
|
} else
|
|
WriteError("Error open JAM %s", sMsgAreaBase);
|
|
free(sFileName);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* External Message Editor
|
|
*/
|
|
int Ext_Edit()
|
|
{
|
|
int changed;
|
|
int j, i;
|
|
char *l, *tmpname;
|
|
FILE *fd;
|
|
struct stat st1,st2;
|
|
|
|
changed=FALSE;
|
|
|
|
tmpname = calloc(PATH_MAX, sizeof(char));
|
|
|
|
sprintf(tmpname, "%s/%s/%s", CFG.bbs_usersdir, exitinfo.Name, "data.msg");
|
|
if ((fd = fopen(tmpname, "w")) == NULL) {
|
|
Syslog('+',"EXT_EDIT: Unable to open %s for writing", tmpname);
|
|
} else {
|
|
fprintf(fd,"AREA='%s'\n",sMsgAreaDesc);
|
|
fprintf(fd,"AREANUM='%d'\n",iMsgAreaNumber+1);
|
|
fprintf(fd,"AREATYPE='%d'\n",iMsgAreaType);
|
|
fprintf(fd,"MSGFROM='%s'\n",Msg.From);
|
|
fprintf(fd,"MSGTO='%s'\n",Msg.To);
|
|
fprintf(fd,"MSGTOADDR='%s'\n",Msg.ToAddress);
|
|
fprintf(fd,"MSGSUBJECT='%s'\n",Msg.Subject);
|
|
fprintf(fd,"BBSLANGUAGE='%c'\n",exitinfo.iLanguage);
|
|
fprintf(fd,"BBSFSEDKEYS='%d'\n",exitinfo.FSemacs);
|
|
fclose(fd);
|
|
}
|
|
|
|
sprintf(tmpname, "%s/%s/%s", CFG.bbs_usersdir, exitinfo.Name, "edit.msg");
|
|
if ((fd = fopen(tmpname, "w")) == NULL) {
|
|
Syslog('+',"EXT_EDIT: Unable to open %s for writing", tmpname);
|
|
} else {
|
|
for (i = 1; i <= Line; i++) {
|
|
fprintf(fd,"%s\n",Message[i]);
|
|
}
|
|
fclose(fd);
|
|
stat( tmpname, &st1 );
|
|
ExtDoor(CFG.externaleditor,FALSE,TRUE,TRUE,FALSE,TRUE);
|
|
stat( tmpname, &st2 );
|
|
}
|
|
|
|
if ( st1.st_mtime != st2.st_mtime ) {
|
|
l = calloc(81, sizeof(char));
|
|
if ((fd = fopen(tmpname, "r")) == NULL) {
|
|
Syslog('+',"EXT_EDIT: Unable to open %s for reading", tmpname);
|
|
} else {
|
|
i=1;
|
|
while ( (fgets(l,80,fd) != NULL) && (i < TEXTBUFSIZE ) ) {
|
|
for (j = 0; i < strlen(l); j++) {
|
|
if (*(l + j) == '\0')
|
|
break;
|
|
if (*(l + j) == '\n')
|
|
*(l + j) = '\0';
|
|
if (*(l + j) == '\r')
|
|
*(l + j) = '\0';
|
|
/*
|
|
* Make sure that any tear or origin lines are
|
|
* made invalid.
|
|
*/
|
|
if (strncmp(l, (char *)"--- ", 4) == 0)
|
|
l[1] = 'v';
|
|
if (strncmp(l, (char *)" * Origin:", 10) == 0)
|
|
l[1] = '+';
|
|
}
|
|
sprintf(Message[i],"%s",l);
|
|
i++;
|
|
}
|
|
changed=TRUE;
|
|
Line=i;
|
|
fclose(fd);
|
|
}
|
|
free(l);
|
|
}
|
|
free(tmpname);
|
|
return changed;
|
|
}
|
|
|
|
|