Filewatcher File Search
FTP Search
  
Directory (beta)
  
Content Search (beta)
   
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 <
Results 1 - 1
Help - FTP Sites List - Software Dir.
Searching half a billion files worldwide
© 1997-2008 IT MARUHN