pkg://jmr-0.7.20.1.src.tar.gz:172426/
jmrsrc-0.7.20.1/
src/jmr.cc
downloads
// $Id: jmr.cc,v 1.39 1998/07/18 19:49:39 jvuokko Exp $
/****************************************************************************
* *
* * MODULE : jmr.cc
* *
* **************************************************************************
* *
* * This file is part of jmr offline mail reader.
* * Copyright (C) 1997,1998 Jukka Vuokko <jvuokko@iki.fi>
* *
* * This program 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 of the License, or
* * (at your option) any later version.
* *
* * This program 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 this program; if not, write to the Free Software
* * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *
* **************************************************************************
* *
* * Main program and signal handling
* *
***************************************************************************/
#include <new.h> // set_new_handler()
#include <stdio.h> // sprintf(), rand(), srand()
#ifdef __WATCOMC__
#include <io.h> // access()
#endif
#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS
#include <signal.h>
#include <time.h> // time()
#ifdef __WATCOMC__
# include <direct.h>
#elif defined (__EMX__)
# include <unistd.h> // F_OK
# include <sys/types.h>
# include <dirent.h>
#else
# include <unistd.h> // F_OK
# include <dirent.h>
#endif
#include "jmr.hh"
#include "menu.hh"
#include "mail.hh"
#include "filelist.hh"
#include "tree.hh"
/*
* Defaults for a resources
*/
const char DEFAULT_PACK_CMD[] = "zip -jkq";
const char DEFAULT_UNPACK_CMD[] = "unzip -oLqq";
const char DEFAULT_QUOTEPREFIX[] = "> ";
const char DEFAULT_WILDCARD[] = "*.[qQ]*";
const char DEFAULT_PTAG[] = "";
const char DEFAULT_TAG[] = "";
const char DEFAULT_FULL_SYSNAME[] = "no";
const bool DEFAULT_CONFIRM_RETURN = true;
const int DEFAULT_REPLYLOGSIZE = 200;
const int DEFAULT_DATABASESIZE = 5000;
const int DEFAULT_QUOTECOLOR = GREEN;
const int DEFAULT_BODYCOLOR = CYAN;
const int DEFAULT_MENU_COLOR = WHITE | BOLD;
const int DEFAULT_MENU_BCOLOR = BLUE | BOLD;
const int DEFAULT_SLINE_COLOR = YELLOW | BOLD;
const int DEFAULT_SLINE_BCOLOR = BLUE | BOLD;
const int DEFAULT_DASHLINE_COLOR = DEFAULT_FCOLOR;
const int DEFAULT_DASHLINE_BCOLOR = DEFAULT_BCOLOR;
const int DEFAULT_BASEGROUP_COLOR = GREEN | BOLD;
const int DEFAULT_SUBJECT_COLOR = GREEN;
const int DEFAULT_AUTHOR_COLOR = CYAN;
const int DEFAULT_ILINE_COLOR = DEFAULT_FCOLOR;
const int DEFAULT_ILINE_ERRCOLOR = RED | BOLD;
const int DEFAULT_HEADER_SUBJECT_COLOR = BOLD;
const int DEFAULT_HEADER_AUTHOR_COLOR = GREEN;
const int DEFAULT_PERSONAL_COLOR = YELLOW | BOLD;
const char DEFAULT_FOLLOWUPSTR[] = "In article <%m> %n wrote:";
const char DEFAULT_REPLYSTR[] = "On a message dated %d you wrote:";
const char DEFAULT_DATESTR[] = "%D.%M.%Y";
const char DEFAULT_WRAPIND = '>';
const char DEFAULT_RECEIVER[] = "";
const char DEFAULT_FOLDER[] = "";
const char DEFAULT_TAGLINE_PROGRAM[] = "";
const char DEFAULT_SIGNATUREFILE[] = "";
const bool DEFAULT_RMOLDPACKET = false;
#ifdef F_TO_ALL
const String DEFAULT_FOLLOWUPTO = FUT_WRITER;
#endif
#ifdef __unix__
const char DEFAULT_EDITOR[] = "/usr/bin/jed";
#else
const char DEFAULT_EDITOR[] = "jed.exe";
#endif
//**************************************************************************/
//
// CLASS: Jmrmain
//
//
// DESCRIPTION: Methods for handling mainloop of program.
//
//**************************************************************************/
class Jmrmain {
public:
Jmrmain (int ac, char **av);
~Jmrmain(){};
private:
void init();
void init_paths();
void init_defaults();
void init_settings();
void parse_arguments ();
void init_extractdir();
void get_jmrdir();
void check_jmrdir();
void create_rc_file (char *file);
void read_lines ();
bool parse_rcline (String&, int);
void mainloop();
bool check_argument (int&);
void show_help();
void set_textcolor_value (int& c, String& value);
//void set_backcolor_value (int&, String& );
bool init_all; // if this is true, then write new rc-file
int argc; // number of items in commandline
char **argv; // command parameters
Filelist filelist; // qwk-packet selection level
Groupmenu *groupmenu; // group selection level
String resource_file; // name of resource file
key_tree keywords; // Syntax tree for resources
// Extra variables by Yka
String open_jmr; // Name of packet or database to open.
// If empty assume normal jmr behaviour
};
/************************ GLOBAL VARIABLES ***********************************/
Terminal_screen Screen;
settings_t Settings;
Mail* mail;
Window *Wscript;
#ifdef NO_EXCEPTIONS
bool Quit_flag = false;
#endif
// This array defines rules for keywords in a resource file.
// "*" means that the keyword must have a value.
// "" a value of the keyword can be empty.
// "$" a value must be a number.
//
// Format of an array:
// Keyword, rule1, rule2, ruleN,
// "@NEXT",
// .
// .
// .
// "@NEXT", "@END"
static const char *rc_values[] = {
RC_MAILPATH,"*",
"@NEXT",
RC_REPLYPATH,"*",
"@NEXT",
RC_QUOTEPREFIX,"*",
"@NEXT",
RC_EDITOR, "*",
"@NEXT",
RC_UNPACK, "*",
"@NEXT",
RC_PACK, "*",
"@NEXT",
RC_SYSCHARSET, "latin1", "ibmpc", "7bit",
"@NEXT",
RC_BBSCHARSET, "latin1", "ibmpc", "7bit",
"@NEXT",
RC_WILDCARD, "*",
"@NEXT",
RC_PTAG, "",
"@NEXT",
RC_EXTRACTDIR, "",
"@NEXT",
RC_REPLYLOGSIZE, "$",
"@NEXT",
RC_DATABASESIZE, "$",
"@NEXT",
RC_QUOTECOLOR, COLOR_VALUES,
"@NEXT",
RC_BODYCOLOR, COLOR_VALUES,
"@NEXT",
RC_WRAPMODE, "yes", "no",
"@NEXT",
RC_FOLLOWUPSTR, "",
"@NEXT",
RC_REPLYSTR, "",
"@NEXT",
RC_TAG, "",
"@NEXT",
RC_FULL_SYSNAME, "yes", "no",
"@NEXT",
RC_CONFIRM_RETURN, "yes", "no",
"@NEXT",
RC_DATESTR, "*",
"@NEXT",
RC_MENU_COLOR, COLOR_VALUES,
"@NEXT",
RC_MENU_BCOLOR, COLOR_VALUES,
"@NEXT",
RC_SLINE_COLOR, COLOR_VALUES,
"@NEXT",
RC_SLINE_BCOLOR, COLOR_VALUES,
"@NEXT",
RC_DASHLINE_COLOR, COLOR_VALUES,
"@NEXT",
RC_DASHLINE_BCOLOR, COLOR_VALUES,
"@NEXT",
RC_SUBJECT_COLOR, COLOR_VALUES,
"@NEXT",
RC_AUTHOR_COLOR, COLOR_VALUES,
"@NEXT",
RC_ILINE_COLOR, COLOR_VALUES,
"@NEXT",
RC_ILINE_ERROR_COLOR, COLOR_VALUES,
"@NEXT",
RC_HEADER_SUBJECT_COLOR, COLOR_VALUES,
"@NEXT",
RC_BASEGROUP_COLOR, COLOR_VALUES,
"@NEXT",
RC_HEADER_AUTHOR_COLOR, COLOR_VALUES,
"@NEXT",
RC_PERSONAL_COLOR, COLOR_VALUES,
"@NEXT",
RC_DEFAULT_RECEIVER,"",
"@NEXT",
RC_DEFAULT_FOLDER,"",
"@NEXT",
RC_TAGLINE_PROGRAM,"",
"@NEXT",
RC_SIGNATUREFILE,"",
"@NEXT",
RC_RMOLDPACKET, "yes", "no",
"@NEXT",
#ifdef F_TO_ALL
RC_FOLLOWUPTO, "*",
"@NEXT",
#endif
"@END"
};
/************* PROTOTYPES FOR FUNCTIONS IN THIS MODULE ***********************/
void memory_error_handler();
/***************************************************************************
* FUNCTION: main
***************************************************************************
*
* DESCRIPTION: main function of the jmr.
*
* EXTERNAL REFERENCES
* IN :
* OUT: Settings.currentdir, Screen
*
* RETURN : EXIT_SUCCESS
***************************************************************************/
int main(int argc, char** argv)
{
signal (SIGINT, die);
signal (SIGTERM, die);
#ifndef __WATCOMC__
signal (SIGKILL, die);
#endif
#ifdef __unix__
signal (SIGTSTP, suspend);
#endif
set_new_handler (memory_error_handler);
set_misc_lib_error_handler( fatal_error );
Settings.currentdir[0] = '\0';
// initialize random generator
srand( (unsigned int) time( NULL ) );
int h = Screen.get_ymax();
if ( h < 19 || Screen.get_xmax() < 79 ) {
cerr << "Required size of the terminal is 20x80.\n";
cerr << "Your terminal has " << h+1 << " lines and "
<< Screen.get_xmax()+1 << " columns." << endl;
exit( EXIT_FAILURE );
}
Wscript = Screen.newwin( 0, 1, Screen.get_xmax()+1, h - 1,
WIN_SLINE);
Wscript->set_border_colors( DEFAULT_FCOLOR| INVERSE,
DEFAULT_BCOLOR);
Wscript->set_sline_text("* Message Buffer *");
Jmrmain jmrmain (argc, argv);
return EXIT_SUCCESS;
}
/************************************************************************
* FUNCTION : die
************************************************************************
*
* If SIGTERM, SIGKILL or SIGINT signal received, this procedure tries to
* save all necessary data before exit.
*
* EXTERNAL VARIABLE REFERENCES:
* IN : mail
* OUT:
*
* Parameters:
* int sig signal
*
***********************************************************************/
void
die(int sig)
{
//Screen.bottom();
Screen.enable();
Wscript->enable();
Wscript->print( "\n\nTerminate signal (%d) received.\n", sig);
Screen.set_origmode();
if (mail == 0) {
exit (EXIT_FAILURE);
}
if (mail->have_replies() == true) {
Wscript->print( "Emergency exit. Storing new replies...\n");
Screen.refresh();
mail->emergency_exit();
}
exit (EXIT_FAILURE);
}
/***************************************************************************
* FUNCTION: memory_error_handler
***************************************************************************
*
* Function for handling memory errors. The new[]-operator calls this if
* memory is exceed.
*
* EXTERNAL VARIABLE REFERENCES:
* IN :
* OUT:
*
* RETURN:
***************************************************************************/
void
memory_error_handler()
{
handle_error (NO_MEMORY_ERROR, HALT_FL);
}
/***************************************************************************
* FUNCTION: suspend
***************************************************************************
*
* DESCRIPTION: Caughts SIGTSTP-signal (^Z).
*
* EXTERNAL REFERENCES
* IN : Screen
* OUT:
*
***************************************************************************/
#ifdef __unix__
void
suspend(int )
{
sigset_t mask;
sigemptyset( &mask );
sigaddset( &mask, SIGTSTP );
Screen.set_origmode();
sigprocmask( SIG_UNBLOCK, &mask, NULL );
signal (SIGTSTP, SIG_DFL);
kill( getpid(), SIGTSTP );
signal( SIGTSTP, suspend );
Screen.set_rawmode();
Screen.refresh( REDRAW_ALL );
}
#endif
//**************************************************************************/
// CLASS: Jmrmain
// MEMBER FUNCTION: Jmrmain
//
// DESCRIPTION: Main funtion of class.
//
//
// EXTERNAL REFERENCES
// IN : Settings, Screen
// OUT: Quit_flag
//
// RETURNS:
//**************************************************************************/
Jmrmain::Jmrmain(int ac, char** av)
{
argc = ac;
argv = av;
init_all = false;
open_jmr = "";
#ifdef NO_EXCEPTIONS
Quit_flag = false;
#endif
parse_arguments();
Screen.enable();
Wscript->enable();
init();
if (Screen.is_color_term()) {
Wscript->set_border_colors( Settings.sline_color,
Settings.slineback_color );
}
// change to working directory
if (change_dir (Settings.workdir.get())) {
char buf[1024];
sprintf (buf, "Cannot change to direcetory : %s",
Settings.workdir.get());
handle_error (buf, HALT_FL);
}
mainloop();
Wscript->enable();
// back to original directory
change_dir (Settings.currentdir);
}
//**************************************************************************/
// CLASS: Jmrmain
// MEMBER FUNCTION: mainloop
//
// DESCRIPTION: Main loop of program
//
//
// EXTERNAL REFERENCES
// IN : Settings, mail, Quit_flag
// OUT: mail
//
//**************************************************************************/
void
Jmrmain::mainloop()
{
bool open_new;
loop:
open_new = false;
mail = 0;
if (ACCESS (DEADJMR_FILENAME, F_OK) == 0) {
Wscript->enable();
Wscript->print( "\nPrevious session was killed and replies was"
"wrote to recovery file.\n" );
Wscript->print( "Continue killed session with these "
"replies? (y/n)? y" );
Screen.refresh();
if (get_yesno('y') == 'n') {
remove (DEADJMR_FILENAME);
} else if (0 == (mail = Mail::open_dead())) {
handle_error("Cannot open recovery file.",
REPORT_FL);
}
}
if (mail == 0) {
if (open_jmr.is_empty()) {
Wscript->disable();
mail = filelist.open_file();
if (mail == 0) {
return;
}
} else {
Wscript->disable();
mail = filelist.open_file(open_jmr);
// skip interactive mode
if (!mail) {
return;
}
if (Settings.rmoldpacket) {
String tmppath = Settings.qwkpath;
correct_path( tmppath );
tmppath += open_jmr + ".[qQ][wW][kK]";
rm_files( tmppath );
}
}
}
Wscript->disable();
#ifdef NO_EXCEPTIONS
groupmenu = new Groupmenu();
#else
try {
groupmenu = new Groupmenu();
}
catch( quit_exception ) {
Wscript->enable();
Wscript->reset_attr();
Wscript->textcolor( BOLD );
Wscript->print("\n'Quit immediately' command received!");
Wscript->reset_attr();
Screen.refresh();
delete mail;
Wscript->print( "\nCleaning working directory..." );
Screen.refresh();
clear_workdir();
Wscript->print("OK");
return;
}
#endif
delete groupmenu;
delete mail;
Wscript->enable();
Wscript->print( "\nCleaning working directory..." );
Screen.refresh();
clear_workdir();
Wscript->print("OK");
#ifdef NO_EXCEPTIONS
if (Quit_flag == true || !open_jmr.is_empty()) { // --open-jmr means immediate quit after reading.
return;
}
#endif
goto loop;
}
//**************************************************************************/
// CLASS: Jmrmain
// MEMBER FUNCTION: init
//
// DESCRIPTION: Reads contents of a resource file and initializes Settings.
//
//
// EXTERNAL REFERENCES
// IN : rc_values[]
// OUT: Settings
//
// RETURNS:
//**************************************************************************/
void Jmrmain::init()
{
Wscript->enable();
Wscript->print( "\n*** jmr %s (alpha) ***", VERSION );
Wscript->print( " (compiled@ %s )\n", __DATE__ );
Screen.refresh();
keywords.init( rc_values );
init_paths();
read_lines();
init_defaults();
init_settings();
init_extractdir();
if( Settings.full_sysname == "no" ) {
Settings.system = get_system_info();
} else {
Settings.system = get_system_info( ALL_FL );
}
Settings.version_str = "jmr " VERSION " ";
Settings.version_str += Settings.system;
Settings.tag = "* " + Settings.version_str + " * ";
// set up wrap indicator
switch ( Settings.syscharset ) {
case ISO_LATIN_CHARSET:
Settings.wrap_indicator = 0xbb;
break;
case IBM_PC_CHARSET:
Settings.wrap_indicator = 175;
break;
default:
Settings.wrap_indicator = DEFAULT_WRAPIND;
};
Wscript->enable();
Wscript->print( "Resource file is OK" );
Screen.refresh();
DEBUG("---------- SETTINGS ---------");
DEBUG("zipcmd ="<<Settings.zipcmd);
DEBUG("unzipcmd ="<<Settings.unzipcmd);
DEBUG("qwkpath ="<<Settings.qwkpath);
DEBUG("replypath ="<<Settings.replypath);
DEBUG("quoteprefix ="<<Settings.quoteprefix);
DEBUG("searchpattern ="<<Settings.searchpattern);
DEBUG("ptagline ="<<Settings.ptagline);
DEBUG("tagline ="<<Settings.tagline);
DEBUG("replylogsize ="<<Settings.replylogsize);
DEBUG("datebasesize ="<<Settings.databasesize);
DEBUG("extractdir ="<<Settings.extractdir);
DEBUG("quotecolor ="<<Settings.quote_color);
DEBUG("textcolor ="<<Settings.article_color);
DEBUG("followup ="<<Settings.followup);
DEBUG("reply ="<<Settings.reply);
DEBUG("syscharset ="<<Settings.syscharset);
DEBUG("bbscharset ="<<Settings.bbscharset);
DEBUG("menucolor =" <<Settings.menu_color);
DEBUG("menuback = "<<Settings.menuback_color);
DEBUG("slinecolor = "<<Settings.sline_color);
DEBUG("slineback = "<<Settings.slineback_color);
DEBUG("dashcolor = "<<Settings.dash_color);
DEBUG("dashback = "<<Settings.dashback_color);
DEBUG("subjectcolor = "<<Settings.subject_color);
DEBUG("ilinecolor = "<<Settings.iline_color);
DEBUG("default_receiver = "<<Settings.default_receiver);
DEBUG("signaturefile = " << Settings.signaturefile );
DEBUG("taglinre = " << Settings.tagliner );
DEBUG("rmoldpacket = " << Settings.rmoldpacket );
#ifdef F_TO_ALL
DEBUG("followupto = " << Settings.followupto );
#endif
DEBUG("-------- END OF SETTINGS ----");
}
//**************************************************************************/
// CLASS: jmrmain
// MEMBER FUNCTION: init_defaults
//**************************************************************************/
//
// This function initializes contents of Settings structure with a
// default values.
//
// NOTE: All paths must be initialised (init_paths()) before using this.
//
// EXTERNAL VARIABLE REFERENCES
// IN : Settings.currentdir
// OUT: Settings
//
// PARAMETERS:
//
// RETURN:
//**************************************************************************/
void Jmrmain::init_defaults()
{
Settings.zipcmd = DEFAULT_PACK_CMD;
Settings.unzipcmd = DEFAULT_UNPACK_CMD;
Settings.qwkpath = Settings.currentdir;
correct_path( Settings.qwkpath );
Settings.replypath = Settings.currentdir;
correct_path( Settings.replypath );
Settings.quoteprefix = DEFAULT_QUOTEPREFIX;
Settings.searchpattern = DEFAULT_WILDCARD;
Settings.ptagline = DEFAULT_PTAG;
Settings.tagline = DEFAULT_TAG;
Settings.full_sysname = DEFAULT_FULL_SYSNAME;
Settings.confirm_return = DEFAULT_CONFIRM_RETURN;
Settings.replylogsize = DEFAULT_REPLYLOGSIZE;
Settings.databasesize = DEFAULT_DATABASESIZE;
Settings.extractdir = ""; // this is initialized later
Settings.max_subject_len = MAX_SUBJECT_LEN;
Settings.max_bbs_subject_len = MAX_SUBJECT_LEN;
Settings.is_pcboard = false;
Settings.quote_color = DEFAULT_QUOTECOLOR;
Settings.article_color = DEFAULT_BODYCOLOR;
Settings.followup = DEFAULT_FOLLOWUPSTR;
Settings.reply = DEFAULT_REPLYSTR;
Settings.date_fmt = DEFAULT_DATESTR;
Settings.editor = DEFAULT_EDITOR;
Settings.menu_color = DEFAULT_MENU_COLOR;
Settings.menuback_color = DEFAULT_MENU_BCOLOR;
Settings.sline_color = DEFAULT_SLINE_COLOR;
Settings.slineback_color = DEFAULT_SLINE_BCOLOR;
Settings.dash_color = DEFAULT_DASHLINE_COLOR;
Settings.dashback_color = DEFAULT_DASHLINE_BCOLOR;
Settings.subject_color = DEFAULT_SUBJECT_COLOR;
Settings.author_color = DEFAULT_AUTHOR_COLOR;
Settings.iline_color = DEFAULT_ILINE_COLOR;
Settings.iline_err_color = DEFAULT_ILINE_ERRCOLOR;
Settings.header_subject_color = DEFAULT_HEADER_SUBJECT_COLOR;
Settings.basegroup_color = DEFAULT_BASEGROUP_COLOR;
Settings.personal_color = DEFAULT_PERSONAL_COLOR;
Settings.header_author_color = DEFAULT_HEADER_AUTHOR_COLOR;
Settings.is_wrapmode = false;
Settings.default_receiver = DEFAULT_RECEIVER;
Settings.default_folder = DEFAULT_FOLDER;
Settings.tagliner = DEFAULT_TAGLINE_PROGRAM;
Settings.signaturefile = DEFAULT_SIGNATUREFILE;
Settings.rmoldpacket = DEFAULT_RMOLDPACKET;
#ifdef F_TO_ALL
Settings.followupto = DEFAULT_FOLLOWUPTO;
#endif
}
//**************************************************************************/
// CLASS: Jmrmain
// MEMBER FUNCTION: init_settings
//
// DESCRIPTION: Initializes settings with a values readed from
// a resource file.
//
//
// EXTERNAL REFERENCES
// IN :
// OUT: Settings
//
// RETURNS:
//**************************************************************************/
void Jmrmain::init_settings()
{
String value;
String tmp;
int errors = 0;
// first init required resources
value = keywords.get_value( RC_SYSCHARSET );
if (value.is_empty()) {
++errors;
tmp = "Resource \'";
tmp += RC_SYSCHARSET;
tmp += "\' not found";
handle_error(tmp.get(), REPORT_FL );
} else {
if (value == "ibmpc") {
Settings.syscharset = IBM_PC_CHARSET;
} else if (value == "latin1") {
Settings.syscharset = ISO_LATIN_CHARSET;
} else {
Settings.syscharset = ASCII_7BIT_CHARSET;
}
}
value = keywords.get_value( RC_BBSCHARSET );
if (value.is_empty()) {
++errors;
tmp = "Resource \'";
tmp += RC_BBSCHARSET;
tmp += "\' not found";
handle_error( tmp.get(), REPORT_FL );
} else {
if (value == "ibmpc") {
Settings.bbscharset = IBM_PC_CHARSET;
} else if (value == "latin1") {
Settings.bbscharset = ISO_LATIN_CHARSET;
} else {
Settings.bbscharset = ASCII_7BIT_CHARSET;
}
}
#ifdef F_TO_ALL
value = keywords.get_value( RC_FOLLOWUPTO );
if ( value.is_empty() == false ) {
Settings.followupto = value;
} else {
++errors;
tmp = "Resource \'";
tmp += RC_FOLLOWUPTO;
tmp += "\' not found";
handle_error( tmp.get(), REPORT_FL );
}
#endif
if (errors) {
handle_error("All required resources are not defined!",
HALT_FL);
}
// if resource is defined in file, then override default
value = keywords.get_value( RC_EDITOR );
if (value.is_empty() == false) {
Settings.editor = value;
}
value = keywords.get_value( RC_PACK );
if (value.is_empty() == false) {
Settings.zipcmd = value;
}
value = keywords.get_value( RC_UNPACK );
if (value.is_empty() == false) {
Settings.unzipcmd = value;
}
value = keywords.get_value( RC_MAILPATH );
if (value.is_empty() == false) {
Settings.qwkpath = value;
correct_path( Settings.qwkpath );
}
value = keywords.get_value( RC_REPLYPATH );
if (value.is_empty() == false) {
Settings.replypath = value;
correct_path( Settings.replypath );
}
value = keywords.get_value( RC_QUOTEPREFIX );
if (value.is_empty() == false) {
value.replace_ch( '_', ' ' );
Settings.quoteprefix = value;
}
value = keywords.get_value( RC_WILDCARD );
if (value.is_empty() == false) {
Settings.searchpattern = value;
}
value = keywords.get_value( RC_WRAPMODE );
if ( value.is_empty() == false ) {
Settings.is_wrapmode = value == "yes" ? true : false;
}
value = keywords.get_value( RC_PTAG );
if (value.is_empty() == false) {
Settings.ptagline = value;
}
value = keywords.get_value( RC_TAG );
if (value.is_empty() == false) {
Settings.tagline = value;
}
value = keywords.get_value( RC_FULL_SYSNAME );
if (value.is_empty() == false) {
Settings.full_sysname = value;
}
value = keywords.get_value( RC_CONFIRM_RETURN );
if (value.is_empty() == false) {
Settings.confirm_return = value == "yes" ? true : false;
}
value = keywords.get_value( RC_REPLYLOGSIZE );
if (value.is_empty() == false) {
Settings.replylogsize = atoi( value.get() );
}
value = keywords.get_value( RC_DATABASESIZE );
if (value.is_empty() == false) {
Settings.databasesize = atoi( value.get() );
}
value = keywords.get_value( RC_EXTRACTDIR );
if (value.is_empty() == false) {
correct_path( value );
Settings.extractdir = value;
}
value = keywords.get_value( RC_QUOTECOLOR );
set_textcolor_value (Settings.quote_color, value);
value = keywords.get_value( RC_BODYCOLOR );
set_textcolor_value (Settings.article_color, value);
value = keywords.get_value( RC_FOLLOWUPSTR );
if (value.is_empty() == false) {
Settings.followup = value;
}
value = keywords.get_value( RC_REPLYSTR );
if (value.is_empty() == false) {
Settings.reply = value;
}
value = keywords.get_value( RC_DATESTR );
if (value.is_empty() == false) {
Settings.date_fmt = value;
}
value = keywords.get_value( RC_MENU_COLOR );
set_textcolor_value (Settings.menu_color, value);
value = keywords.get_value( RC_MENU_BCOLOR );
set_textcolor_value( Settings.menuback_color, value );
value = keywords.get_value( RC_SLINE_COLOR );
set_textcolor_value (Settings.sline_color, value);
value = keywords.get_value( RC_SLINE_BCOLOR );
set_textcolor_value( Settings.slineback_color, value );
value = keywords.get_value( RC_DASHLINE_COLOR );
set_textcolor_value (Settings.dash_color, value);
value = keywords.get_value( RC_DASHLINE_BCOLOR );
set_textcolor_value( Settings.dashback_color, value );
value = keywords.get_value( RC_SUBJECT_COLOR );
set_textcolor_value (Settings.subject_color, value);
value = keywords.get_value( RC_AUTHOR_COLOR );
set_textcolor_value (Settings.author_color, value);
value = keywords.get_value( RC_ILINE_COLOR );
set_textcolor_value (Settings.iline_color, value);
value = keywords.get_value( RC_ILINE_ERROR_COLOR );
set_textcolor_value (Settings.iline_err_color, value);
value = keywords.get_value( RC_BASEGROUP_COLOR );
set_textcolor_value (Settings.basegroup_color, value);
value = keywords.get_value( RC_HEADER_SUBJECT_COLOR );
set_textcolor_value (Settings.header_subject_color, value);
value = keywords.get_value( RC_HEADER_AUTHOR_COLOR );
set_textcolor_value (Settings.header_author_color, value);
value = keywords.get_value( RC_PERSONAL_COLOR );
set_textcolor_value (Settings.personal_color, value);
value = keywords.get_value( RC_DEFAULT_RECEIVER );
if (value.is_empty() == false) {
Settings.default_receiver = value;
}
value = keywords.get_value( RC_DEFAULT_FOLDER );
if (value.is_empty() == false) {
Settings.default_folder = value;
}
value = keywords.get_value( RC_SIGNATUREFILE );
if ( value.is_empty() == false ) {
Settings.signaturefile = value;
expand_path( Settings.signaturefile );
}
value = keywords.get_value( RC_TAGLINE_PROGRAM );
if ( value.is_empty() == false ) {
Settings.tagliner = value;
expand_path( Settings.tagliner );
}
value = keywords.get_value( RC_RMOLDPACKET );
if ( value.is_empty() == false ) {
Settings.rmoldpacket = value == "yes" ? true : false;
}
}
void
Jmrmain::set_textcolor_value (int& c, String& value)
{
if (value.is_empty() == false) {
c = atoi( value.get() );
if( c > 7 ) {
c -= 7;
c |= BOLD;
}
}
}
//**************************************************************************/
// CLASS: Jmrmain
// MEMBER FUNCTION: read_lines
//
// This function reads contents of a resource file to a tree structure.
// If syntax of the resource file is not correct, then program is halted.
//
// EXTERNAL REFERENCES
// IN : Settigs.jmrdir
// OUT:
//
// RETURNS:
//**************************************************************************/
void
Jmrmain::read_lines ()
{
String tmp;
char line[MAX_LINE_LEN+1];
int linenum = 1;
bool rc = true;
tmp = Settings.jmrdir + resource_file;
ifstream rcfile( tmp.get(), ios::in );
if (rcfile.fail()) {
String err_str = "Cannot open resource file : " + tmp;
handle_error (err_str.get(), HALT_FL);
}
Wscript->print( "\nParsing resource file \'%s\'....", tmp.c_str() );
Screen.refresh();
do {
rcfile.getline (line, MAX_LINE_LEN);
tmp = line;
// remove preceeding spaces
tmp.cut_first();
// if line is not empty and it is not commented,
// then check syntax of line and get value
// of keyword.
if (tmp.is_empty() == false && tmp[0] != '#') {
// remove trailing spaces
tmp.cut_tail();
// parse the line
if (parse_rcline( tmp, linenum ) == false) {
rc = false;
}
}
++linenum;
} while (!rcfile.eof());
rcfile.close();
if (rc == false) {
handle_error("Fatal errors in resource file.",
HALT_FL);
}
}
//**************************************************************************/
// CLASS: Jmrmain
// MEMBER FUNCTION: parse_rcline
//
// Checks that syntax of a line is right, and initializes keyword that
// is defined in a line with a value given to it.
// If syntax error occures, then false is returned.
//
// EXTERNAL REFERENCES
// IN :
// OUT:
//
// RETURNS: true if success.
//**************************************************************************/
bool
Jmrmain::parse_rcline (String& line, int num)
{
int n=0;
String tmp;
// check that assigment operator is in it's place
n = line.findch ('=');
if (n == NOTHING) {
String error_str;
error_str = "Assigment operator is missing in line ";
error_str += num;
handle_error( error_str.get(), REPORT_FL);
return false;
}
// Then get word before an assigment operator and check
// if it matches with some of keywords in a trie
tmp.copy( line, 0, n);
tmp.cut_tail();
if (false == keywords.goto_keyword( tmp )) {
String error_str = "At line ";
error_str += num;
error_str += ": Illegal keyword : \'" + tmp + "\'";
handle_error( error_str.get(), REPORT_FL);
return false;
}
// Check that given value is legal, and store it
// in a trie.
tmp.copy( line, n + 1 );
tmp.cut_first();
tmp.cut_tail();
if (false == keywords.set_value( tmp )) {
String error_str = "Invalid value at line ";
error_str += num;
error_str += ": \'" + tmp + "\'";
handle_error( error_str.get(), REPORT_FL );
return false;
}
return true;
}
//**************************************************************************/
// CLASS: Jmrmain
// MEMBER FUNCTION: init_paths
//
// DESCRIPTION: Initializes directories for use.
//
//
// EXTERNAL REFERENCES
// IN : Settings
// OUT: Settings.workdir
//
// RETURNS:
//**************************************************************************/
void
Jmrmain::init_paths()
{
String cmd;
// initialize jmr's directory
get_jmrdir();
// Create directories for working files and for data files if
// them not exist.
Settings.datadir = Settings.jmrdir + DATA_DIRECTORY;
Settings.workdir = Settings.jmrdir + WORK_DIRECTORY;
if (ACCESS (Settings.datadir.get(), F_OK)) {
// FIXME: use mknod() or similar function instead
cmd = CREATE_DIRECTORY_COMMAND;
cmd += Settings.datadir;
jmrsystem (cmd.get());
}
if (ACCESS (Settings.workdir.get(), F_OK)) {
// FIXME: use mknod() or similar function instead
cmd = CREATE_DIRECTORY_COMMAND;
cmd += Settings.workdir;
jmrsystem (cmd.get());
}
// append path separator ('\' or '/')
correct_path (Settings.datadir);
correct_path (Settings.workdir);
// store current directory
getcwd (Settings.currentdir, MAXPATH);
}
//**************************************************************************/
// CLASS: Jmrmain
// MEMBER FUNCTION: get_jmrdir
//
// DESCRIPTION: Initializes jmr's directory.
//
//
// EXTERNAL REFERENCES
// IN :
// OUT: Settings.jmrdir
//
// RETURNS:
//**************************************************************************/
void
Jmrmain::get_jmrdir()
{
char *dir;
// get jmr's directory (where logs, resources etc. are)
dir = getenv (DIR_ENVIRONMENT);
if (dir == NULL) {
// if environment variable is not set, then read variable
// HOME, and use directory HOME/.jmr
dir = getenv ("HOME");
if (dir == NULL) {
handle_error ("Environment variable JMRDIR or HOME is not set!", HALT_FL);
}
Settings.jmrdir = dir;
correct_path (Settings.jmrdir);
Settings.jmrdir += DEFAULT_DIRECTORY;
} else {
Settings.jmrdir = dir;
}
correct_path (Settings.jmrdir);
check_jmrdir();
}
//**************************************************************************/
// CLASS: Jmrmain
// MEMBER FUNCTION: check_jmrdir
//
// DESCRIPTION: Checks if directory exist. If not, then creates it.
// If directory does not contain file jmrrc, then create file
// and tell user that it's necessary to modify it.
//
// EXTERNAL REFERENCES
// IN : Settings.jmrdir
// OUT:
//
// RETURNS:
//**************************************************************************/
void
Jmrmain::check_jmrdir()
{
String cmd;
String rcfile;
int c = 0;
// check if directory exists. If not, then create it
if (ACCESS (Settings.jmrdir.get(), F_OK)) {
Wscript->enable();
Wscript->print( "\nDirectory \'%s\' does not exist.",
Settings.jmrdir.c_str() );
Wscript->print( "\n\nShall I create it ? (y/n) y" );
Screen.refresh();
c = get_yesno('y');
if (c == 'n') {
Wscript->print( "\nExiting...." );
exit(EXIT_SUCCESS);
}
cmd = CREATE_DIRECTORY_COMMAND;
cmd += Settings.jmrdir;
if (jmrsystem (cmd.get())) {
handle_error("Directory creating failed.",HALT_FL);
}
}
rcfile = Settings.jmrdir;
rcfile += RESOURCE_FILE_NAME;
// check if resource-file exists. If not, create it.
if (ACCESS (rcfile.get(), F_OK) || init_all == true) {
create_rc_file(rcfile.get());
}
}
//**************************************************************************/
// CLASS: Jmrmain
// MEMBER FUNCTION: init_extractdir
//
// DESCRIPTION: Gets directory for storing articles.
//
// EXTERNAL REFERENCES
// IN :
// OUT: Settings.extractdir
//
// RETURN :
//**************************************************************************/
void
Jmrmain::init_extractdir()
{
String cmd;
if ( Settings.extractdir == "" ) {
char *path = getenv ("HOME");
if (path == NULL) {
handle_error ("Either key 'extractdir' must defined in resource file\nor environment variable HOME must set.", HALT_FL);
}
Settings.extractdir = path;
correct_path(Settings.extractdir);
Settings.extractdir += EXTRACT_DIRECTORY;
}
if (ACCESS (Settings.extractdir.get(), F_OK)) {
// FIXME: Should use mknod() or similar function...
cmd = CREATE_DIRECTORY_COMMAND;
cmd += Settings.extractdir;
DEBUG( "Exractdir = '" << Settings.extractdir.c_str() << "'" );
jmrsystem (cmd.get());
}
correct_path( Settings.extractdir );
}
//**************************************************************************/
// CLASS: Jmrmain
// MEMBER FUNCTION: create_rc_file
//
// DESCRIPTION: Writes new resource file
//
//
// EXTERNAL REFERENCES
// IN :
// OUT:
//
// RETURNS:
//**************************************************************************/
void
Jmrmain::create_rc_file (char *file)
{
ofstream fout (file);
if (fout.fail()) {
handle_error ("Cannot create default rc-file.",HALT_FL);
}
fout <<"\n########################################################################";
fout <<"\n#";
fout <<"\n#";
fout <<"\n# Configuration file for jmr QWK offline mail reader. This file sets";
fout <<"\n# up the runtime parameters and options.";
fout <<"\n#";
fout <<"\n# Parameters defined here are global for each bbs, but you can override";
fout <<"\n# some of these using local, bbs related configuration files.";
fout <<"\n# Sample for the local configuration file should be found at";
fout <<"\n# /usr/local/lib/jmr/sample.rc, if jmr is properly installed.";
fout <<"\n#";
fout <<"\n#";
fout <<"\n# Lines that start with a '#' are ignored.";
fout <<"\n#";
fout <<"\n# NOTE: Name of this file should be 'jmrrc' unless you specify name using";
fout <<"\n# parameter -f at commandline.";
fout <<"\n# This file must allways be in the directory, that ";
fout <<"\n# environment variable JMRDIR points or in directory";
fout <<"\n# $HOME/.jmr/";
fout <<"\n#";
fout <<"\n# NOTE: All paths must be absolute, and if your system uses drive-letters";
fout <<"\n# (like MS-DOG), path must start with drive-letter.";
fout <<"\n# e.g. in Unix systems replypath might be something like:";
fout <<"\n# /spool/send/";
fout <<"\n#";
fout <<"\n# And in DOS-familian systems it might be:";
fout <<"\n# c:\\work\\uploads\\";
fout <<"\n#";
fout <<"\n#";
fout <<"\n# Resources are divited to these sections:";
fout <<"\n# Required settings -- Without these jmr wont run";
fout <<"\n# Basic settings -- Defines paths, editor, zip command etc.";
fout <<"\n# Replying & quoting -- Sets up quoteprefix, tagline etc.";
fout <<"\n# Database -- Define size of database and replylog";
fout <<"\n# Colors -- Set up colors ";
fout <<"\n#";
fout <<"\n########################################################################";
fout <<"\n";
fout <<"\n";
fout <<"\n";
fout <<"\n";
fout <<"\n########################################################################";
fout <<"\n#";
fout <<"\n# REQUIRED SETTINGS";
fout <<"\n#";
fout <<"\n# You must set up at least these two resources in order to run jmr.";
fout <<"\n#";
fout <<"\n########################################################################";
fout <<"\n";
fout <<"\n";
fout <<"\n # Define your systems characterset here. Possible values are:";
fout <<"\n # latin1 for ISO-LATIN1 character set. (e.g. Linux uses it)";
fout <<"\n # ibmpc for PC 437 codepage. (e.g. OS/2, MS-DOG)";
fout <<"\n # 7bit for 7bit ascii character set. Some old machines (?)";
fout <<"\n #";
fout <<"\n # E.g. systemcharset = latin1";
fout <<"\nsystemcharset = ";
fout <<"\n";
fout <<"\n";
fout <<"\n #";
fout <<"\n # Character set that bbs is using.";
fout <<"\n #";
fout <<"\nbbscharset = ";
fout <<"\n";
fout <<"\n";
fout <<"\n########################################################################";
fout <<"\n#";
fout <<"\n# BASIC SETTINGS";
fout <<"\n#";
fout <<"\n########################################################################";
fout <<"\n";
fout <<"\n";
fout <<"\n # Shell command to unzip qwk-packet. Normally you don't need to change ";
fout <<"\n # this, unless you are using MS-DOG and you want to use pkzip/pkunzip.";
fout <<"\n # NOTE: Use unzip-program with option, that overwrites existing files!";
fout <<"\n # Default command is 'unzip -oLqq'";
fout <<"\n#unzipcmd = pkunzip";
fout <<"\n";
fout <<"\n";
fout <<"\n # Shell command to pack replies. This should also work in your ";
fout <<"\n # system without changes.";
fout <<"\n # Default command is 'zip -jkq'";
fout <<"\n#zipcmd = pkzip";
fout <<"\n";
fout <<"\n";
fout <<"\n # Set up path to directory, that holds your QWK mail packets.";
fout <<"\n # Default value is './'";
fout <<"\n#qwkpath = c:\\work\\download";
fout <<"\n#qwkpath = ~/work/download";
fout <<"\n";
fout <<"\n";
fout <<"\n # Set up path to directory, where replies goes. Usually it should be";
fout <<"\n # same directory, that you use for uploads in your terminal software.";
fout <<"\n # Default is './'";
fout <<"\n#replypath = ~/work/upload";
fout <<"\n";
fout <<"\n";
fout <<"\n # This is the wildcard file specification to use when searching for";
fout <<"\n # packets to read. Accepts *, ? and list [].";
fout <<"\n # Default pattern is '*.[qQ]*'";
fout <<"\n # NOTE: Pattern is case-sensitive even in Os/2!";
fout <<"\n#searchpattern = *.qwk";
fout <<"\n";
fout <<"\n";
fout <<"\n # Define the editor use for replies.";
fout <<"\n # Default is '/usr/bin/jed' in unix and 'jed.exe' in DOS-style";
fout <<"\n # operating systems.";
fout <<"\n#editor = ";
fout <<"\n";
fout <<"\n";
fout <<"\n # Set up path to directory for saved messages.";
fout <<"\n #";
fout <<"\n # Normally program reads environment variable HOME, and extracts saved";
fout <<"\n # messages to subdirectory 'Messages' of directory that HOME points";
fout <<"\n # ($HOME/Messages/).";
fout <<"\n # ";
fout <<"\n # If You want to override HOME-environment variable, uncomment next line";
fout <<"\n#extractdir = ~/work/articles";
fout <<"\n";
fout <<"\n";
fout <<"\n # Default name for file to save articles. ";
fout <<"\n # This name can be simple name like `saved_articles', when jmr creates";
fout <<"\n # it under directory defined by key `extractdir' or $HOME/Messages.";
fout <<"\n # Name of folder can also be relative like `../saved_articles',";
fout <<"\n # absolute like `/home/my_name/saved_articles' or `~/texts/saved_artcles";
fout <<"\n # ";
fout <<"\n#default_folder = saved_articles";
fout <<"\n";
fout <<"\n";
fout <<"\n # This format string defines how date should be displayed. Default format";
fout <<"\n # for date is dd.mm.yyyy (%D.%M.%Y as a format string).";
fout <<"\n # Format specifiers are: %M for month, %D for day and %Y for year.";
fout <<"\n#dateformat = %M/%D/%Y";
fout <<"\n";
fout <<"\n";
fout <<"\n # With this option set, lines are word wrapped at the end of screen,";
fout <<"\n # avoiding truncated messages.";
fout <<"\n # Note that wrap mode can also be changed in jmr using key 'ESC-w'.";
fout <<"\n # Default value is 'no'";
fout <<"\n#wrapmode = yes";
fout <<"\n";
fout <<"\n";
fout <<"\n # If this is set to 'yes', then jmr asks confirm when returning to";
fout <<"\n # packet selection level from group selection level.";
fout <<"\n # Default value is 'yes'";
fout <<"\n#confirm_return = no";
fout <<"\n";
fout <<"\n";
fout <<"\n########################################################################";
fout <<"\n#";
fout <<"\n# SETTINGS FOR REPLYING & QUOTING";
fout <<"\n#";
fout <<"\n########################################################################";
fout <<"\n";
fout <<"\n";
fout <<"\n # Default value for name of receiver when composing new article.";
fout <<"\n#default_receiver = All";
fout <<"\n";
fout <<"\n";
fout <<"\n # This describes how jmr will quote the lines of the source message when";
fout <<"\n # creating a new reply file. '_' indicates space.";
fout <<"\n # Default prefix is '> '";
fout <<"\n#quoteprefix = :_";
fout <<"\n";
fout <<"\n";
fout <<"\n # This sets up follow-up string. The following format specifiers are";
fout <<"\n # recognized:";
fout <<"\n # %d = date of quoted article";
fout <<"\n # %t = time";
fout <<"\n # %n = name of author";
fout <<"\n # %s = subject of article";
fout <<"\n # %m = reference message id";
fout <<"\n # %M = number of month";
fout <<"\n # %D = number of day";
fout <<"\n # %Y = year";
fout <<"\n # %% = percent";
fout <<"\n #";
fout <