Filewatcher File Search
FTP Search
  
Directory (beta)
  
Content Search (beta)
   
pkg://jmr-0.7.23-1.src.rpm:177179/jmr-0.7.23.src.tar.gz  info  downloads

jmrsrc-0.7.23/ 40755    764    764           0  6623366026  12452 5ustar  jvuokkojvuokkojmrsrc-0.7.23/src/ 40775    764    764           0  6623366026  13243 5ustar  jvuokkojvuokkojmrsrc-0.7.23/src/filelist.cc100664    764    764       37750  6623366026  15516 0ustar  jvuokkojvuokko// 	$Id: filelist.cc,v 1.14 1998/11/14 20:40:56 jvuokko Exp $	

/****************************************************************************
 * *
 * *  MODULE : filelist.cc
 * *
 * *  Copyright (c) 1997 Jukka Vuokko
 * *  See file COPYING for more information about copyrights.
 * *
 ****************************************************************************
 * *
 * *
 * *      This module contains methods for handling file lists
 * *      (expand wildcards, select file etc...)
 * *
 * *
 * *
 ***************************************************************************/

#include <stdio.h> // sprintf()
#ifdef __EMX__
#   include <sys/types.h>
#endif 
#ifdef __WATCOMC__
#   include <direct.h>
#else
#   include <dirent.h>
#endif
#include "jmr.hh"
#include "filelist.hh"
#include "../utilib/String.hh"
#include "../utilib/List.hh"
#include "mail.hh"

extern Terminal_screen Screen;
extern settings_t Settings;
extern Window* Wscript;

static const menuinfo filelist_menu_array[] = {
        {"[jmr]", 0 },
        {"Exit from menu", 0},
        {"Quit jmr", FORCED_QUIT_CMD},
        {"@NEXT", 0 },
        {"@END", 0 }
};



Filelist::Filelist()
{
        menubar.init( filelist_menu_array );
        menubar.set_text( MENUBAR_TEXT );
        for( int i = Screen.get_xmax(); i >= 0; i--) {
                dashline += '-';
        }
}

/***************************************************************************
 * FUNCTION: compare_name
 ***************************************************************************
 *
 * DESCRIPTION: compares two strings. This is for qsort().
 *
 * EXTERNAL REFERENCES
 * IN : 
 * OUT: 
 *
 * RETURN: <0, 0 or >0
 ***************************************************************************/
int compare_name (const void *a, const void *b)
{
        String **aa, **bb;
        aa = (String**) a;
        bb = (String**) b;
        return (*aa)->compare (*(*bb));
}


Mail*
Filelist::open_file(const String& bbsid)
{
        Mail *mail;
        open_new = false;
        int c;
		if (bbsid.is_empty()) {
        for (;;) {
                mail = 0;
                if (open_new == true) {
                        read_files (Settings.qwkpath);
                        pattern = Settings.searchpattern;
                } else {
                        read_files (Settings.datadir);
                        pattern = "*.[gG][dD][bB]";
                }
                
                // keep only entries, that matches with pattern
                search_matches();
                
                c = select ();
                Screen.bottom();
                Screen.clr_eol();
                //Screen.clear();
                if (c == QUIT_CMD || c == FORCED_QUIT_CMD) {
                        break;
                } else if (c == LOAD_CMD) {
                        open_new = open_new == true ? false : true;
                } else if (c == SELECT_CMD) {
                        mail = Mail::create (filelist.get()->get(), open_new);
                        break;
                }
        }
		} else {
			mail = 0;
			read_files(Settings.qwkpath);
			pattern = bbsid + ".[qQ][wW][kK]";
			if (search_matches()) {
				mail = Mail::create (filelist.get()->get(), true);
			} else {
				filelist.destroy();
				read_files (Settings.datadir);
				pattern = bbsid + ".[gG][dD][bB]";
				if (search_matches()) {
					mail = Mail::create(filelist.get()->get(), false);
				}
			}
		}
        filelist.destroy();
        return mail;
}


//**************************************************************************/
//  CLASS: Filelist
//  MEMBER FUNCTION: read_files
// 
// 
//  DESCRIPTION: Reads all names of files from directory path
// 
//  EXTERNAL REFERENCES
//  IN :  
//  OUT: 
// 
//**************************************************************************/
void
Filelist::read_files (const String& path)
{
        DIR *dir;
        struct dirent *ent;
        String *str;

        filelist.destroy();
        if ( (dir = opendir ( path.get() )) == NULL) {
                String tmp = "Unable to open mail directory: " + path;
                handle_error (tmp.get(), HALT_FL);
        }
        while ((ent = readdir(dir)) != NULL) {
                if (ent->d_name[0] != '.') {
                        str = new String;
                        str->put(ent->d_name);
                        filelist.add (str);
                }
        }

        filelist.sort (compare_name);

        if (closedir(dir) != 0)
                handle_error("Unable to close mail directory", HALT_FL);

}

//**************************************************************************/
//  CLASS: Filelist
//  MEMBER FUNCTION: search_matches
// 
// 
//  DESCRIPTION: Removes all files that does not match with pattern from list
// 
// 
//  EXTERNAL REFERENCES
//  IN :  
//  OUT: 
// 
//  RETURNS: false if list is empty
// 
//**************************************************************************/
bool
Filelist::search_matches()
{
        bool rc;
        String *str;
                
        if (filelist.first() == false) {
                return false;
        }
        
        do {
                str = filelist.get();
                if (check_matches (str->get(), pattern.get()) == false) {
                        rc = filelist.remove();
                } else {
                        rc = filelist.next();
                }
        } while (rc == true);

        return filelist.first();
}


//**************************************************************************/
//  CLASS: Filelist
//  MEMBER FUNCTION: select
// 
// 
//  DESCRIPTION: 'User interface'. 
// 
// 
//  EXTERNAL REFERENCES
//  IN :  
//  OUT: 
// 
//  RETURNS: selected event.
// 
//**************************************************************************/
int
Filelist::select()
{
        int c;
        first = 0;
        current = 0;
        ypos = ymin = 6;
        ymax = Screen.get_ymax() - 5;
        lines = ymax - ymin;
        ++lines;
        //Screen.clear();
        sline.init( Screen.get_xmax() + 1);

        if (open_new == true) {
                iline.set_default( PACKET_LIST_KEYS_MSG );
        } else {
                iline.set_default( DATABASE_LIST_KEYS_MSG );
        }
        
        display();
        iline.show_default();
        
        while(1) {
                Screen.refresh();
                c = Screen.get_ch();
                iline.reset();
                if (c == ESCAPE ) {
                        iline.set( MENU_MSG );
                        iline.show();
                        c = menubar.select();
                        display();
                        iline.reset();
                }
                switch (c) {
                case MESSAGEWIN_CMD:
                        Wscript->enable();
                        iline.set ( MESSAGES_MSG );
                        iline.show();
                        Screen.get_ch();
                        iline.reset();
                        Wscript->disable();
                        break;
                case CODE_UP:
                case PREV_CMD:
                        prev();
                        break;
                case CODE_DOWN:
                case NEXT_CMD:
                        next();
                        break;
                case CODE_NPAGE:
                case PAGE_DOWN_CMD:
                        page_down();
                        break;
                case CODE_PPAGE:
                case PAGE_UP_CMD:
                        page_up();
                        break;
                        //case CODE_CTRL_L:
                        //display();
                        //break;
                case CODE_HOME:
                        first = 0;
                        current = 0;
                        ypos = ymin;
                        display();
                        break;
                case CODE_END:
                        current = filelist.count_items()-1;
                        // next line is not a bug! It's the only
                        // way to calc first index of page...
                        first = (current / lines) * lines ;
                        ypos = ymin + (current - first);
                        display();
                        break;
                case SELECT_CMD:
                case CODE_RIGHT:
                        if (filelist.check() == true) {
                                return SELECT_CMD;
                        }
                        break;
                case FORCED_QUIT_CMD:
#ifndef NO_EXCEPTIONS
                        throw quit_exception();
#endif
                case QUIT_CMD:
                        return QUIT_CMD;
                case REFRESH_CMD:
                        return REFRESH_CMD;
                case LOAD_CMD:
                        return LOAD_CMD;
                case HELP_CMD:
                        show_help();
                        display();
                        break;
                case 0:
                        break;
                default:
                        iline.set( INVALID_COMMAND_MSG );
                };
                iline.show();
        }
}


//**************************************************************************/
//  CLASS: Filelist
//  MEMBER FUNCTION: display
// 
// 
//  DESCRIPTION: display files.
// 
// 
//  EXTERNAL REFERENCES
//  IN :  
//  OUT: 
// 
//  RETURNS: 
// 
//**************************************************************************/
void
Filelist::display()
{
        int i = 0;
        int y;
        Screen.erase();
        menubar.show();
        display_header();
        if (open_new == true) {
                sline.set_infotext( "List of QWK packets" );
        } else {
                sline.set_infotext ("List of databases" );
        }
        if (filelist.first() == false) {
                Screen.gotoxy (0, ymin);
                if (open_new == true) {
                        Screen.print( "No files matches with pattern \'%s\' "
                                      "in a directory : \'%s\'",
                                      pattern.c_str(),
                                      Settings.qwkpath.c_str() );
                } else {
                        Screen.print( "No message databases available." );
                }
                return;
        }
        
        while (i < first) {
                filelist.next();
                ++i;
        }

        i = first;
        y = ymin;

        do {
                        
                Screen.gotoxy (0,y);
                if (i == current) {
                        Screen.inverse();
                        ypos = y;

                } 
                draw_current();
                Screen.reset_attr();
                ++y;
                ++i;
        } while (filelist.next() == true && y <= ymax);


        if (filelist.count_items() <= ymax - ymin) {
                sline.set_percent( ALL_PERCENT );
        } else if (0 == first) {
                sline.set_percent( TOP_PERCENT );
        } else {
                sline.set_percent( (100*i)/filelist.count_items() );
        }
        sline.show();

        filelist.first();
        i = current;
        while (i) {
                filelist.next();
                --i;
        }
        iline.show( REFRESH_ALL_FL );
        Screen.gotoxy (0,ypos);
}

//**************************************************************************/
//  CLASS: Filelist
//  MEMBER FUNCTION: draw_current
// 
// 
//  DESCRIPTION: Displays name of the current file.
// 
// 
//  EXTERNAL REFERENCES
//  IN :  
//  OUT: 
// 
//  RETURNS: 
// 
//**************************************************************************/
void
Filelist::draw_current()
{
        Screen.empty_line();
        Screen.goto_x( 8 );
        Screen.print( "%s", filelist.get()->c_str() );
}

//**************************************************************************/
//  CLASS: Filelist
//  MEMBER FUNCTION: display_header
// 
// 
//  DESCRIPTION: Displays header of screen...
// 
// 
//  EXTERNAL REFERENCES
//  IN :  
//  OUT: 
// 
//  RETURNS: 
// 
//**************************************************************************/
void
Filelist::display_header()
{
        Screen.reset_attr();
        Screen.gotoxy( 0, 1 );
        Screen.textcolor( Settings.header_subject_color );
        Screen.print( "%s -- A QWK compatible offline mail reader",
                      Settings.version_str.c_str() );
        Screen.textcolor( Settings.header_author_color );
        Screen.print("\nCopyright (c) 1997,1998 Jukka Vuokko. All rights reserved.");
        Screen.reset_attr();
        Screen.print( "\nThis version is compiled at %s" , __DATE__ );
        Screen.print( "\nOfficial jmr homepage: http://iki.fi/"
                      "jvuokko/jmr/");
        Screen.gotoxy( 0, 5 );
        set_dashline_color();
        Screen.print( dashline.c_str() );
        Screen.gotoxy( 7, 5 );
        if (open_new == true) {
                Screen.print( " packets: " );
        } else {
                Screen.print( " databases: " );
        }
        Screen.reset_attr ();

}
        
//**************************************************************************/
//  CLASS: Filelist
//  MEMBER FUNCTION: next
// 
// 
//  DESCRIPTION: Moves to next file.
// 
// 
//  EXTERNAL REFERENCES
//  IN :  
//  OUT: 
// 
//  RETURNS: 
// 
//**************************************************************************/
void
Filelist::next()
{
        if (current < (filelist.count_items()-1)) {
                if (ypos == ymax) {
                        first = ++current;
                        display();
                } else {
                        Screen.gotoxy( 0, ypos );
                        Screen.empty_line();
                        draw_current();
                        Screen.gotoxy( 0, ypos+1 );
                        filelist.next();
                        Screen.inverse();
                        draw_current ();
                        Screen.reset_attr();
                        ++current;
                        ++ypos;
                }
        } else {
                iline.set( AT_TOP_MSG );
        }

}

//**************************************************************************/
//  CLASS: Filelist
//  MEMBER FUNCTION: prev
// 
// 
//  DESCRIPTION: Moves to previous file.
// 
// 
//  EXTERNAL REFERENCES
//  IN :  
//  OUT: 
// 
//  RETURNS: 
// 
//**************************************************************************/
void
Filelist::prev()
{
        if (current > 0) {
                if (ypos == ymin && first > 0) {
                        --current;
                        first -= lines;
                        display();
                } else {
                        Screen.gotoxy( 0, ypos );
                        Screen.empty_line();
                        draw_current ();
                        Screen.gotoxy( 0, ypos-1);
                        Screen.inverse();
                        filelist.prev();
                        draw_current ();
                        Screen.reset_attr();
                        --current;
                        --ypos;
                }
        } else {
                iline.set( AT_BOTTOM_MSG );
        }
}

void
Filelist::page_down()
{
        int max = filelist.count_items()-1;
        if (current >= max) {
                iline.set( AT_LAST_PAGE_MSG );
                return;
        }
        if (ypos == ymax) {
                first = ++current;
                for (int i=1; i < lines && current < max; i++, current++);
                ypos = ymin + (current - first);
        } else {
                while (current < max && ypos < ymax) {
                        ++current;
                        ++ypos;
                }
        }
        display();
}

void
Filelist::page_up()
{
        int i = lines;
        if (current == 0) {
                iline.set( AT_FIRST_PAGE_MSG );
                return;
        }
        if (ypos == ymin) {
                while (i && first > 0) {
                        --first;
                        --current;
                        --i;
                }
        } else {
                while (ypos > ymin) {
                        --ypos;
                        --current;
                }
        }
        display();
}



jmrsrc-0.7.23/src/groupselect.cc100664    764    764       12710  6623366026  16224 0ustar  jvuokkojvuokko// $Id: groupselect.cc,v 1.4 1997/11/17 17:16:59 jvuokko Exp $

/*****************************************************************************
 * *
 * *      MODULE:     groupselect.cc
 * *                  --------------
 * ***************************************************************************
 * *
 * *
 * *      COPYRIGHT (C) 1997 JUKKA VUOKKO. ALL RIGHTS RESERVED
 * ***************************************************************************
 * *
 * *      This module contains functions for selecting group from
 * *      list of all groups.
 * *
 *****************************************************************************/


#include "groupselect.hh"
#include "mail.hh"

extern Terminal_screen Screen;
extern Mail *mail;
extern settings_t Settings;

Groupselection::Groupselection()
{
        grpnode *gnode;
        int     savegrp;
        win = Screen.newwin( 0, 0, Screen.get_xmax()+1, Screen.get_ymax(),
                             WIN_SLINE | WIN_TITLEBAR);
        win->set_sline_text("* Available groups *");
        if (Screen.is_color_term() == true ) {
                win->set_border_colors( Settings.sline_color,
                                        Settings.slineback_color);
        } else {
                win->set_border_colors( INVERSE, INVERSE );
        }
        win->disable();
        savegrp = mail->get_group_number();
        mail->first_group();

        do {
                if (mail->get_group_number() >= BASEGROUP_NUMBER) {
                        continue;
                }
                gnode = new grpnode;
                gnode->number = mail->get_group_number();
                gnode->name   = mail->get_group_name();
                itemlist.add( gnode );
                DEBUG("Added to grouplist: " << gnode->name );
        } while (mail->next_group() == true );

        mail->go_group_number( savegrp );
}

Groupselection::~Groupselection()
{
        Screen.endwin( win );
}

grpnode
Groupselection::select()
{
        bool quit = false;
        grpnode selected;
        selected.number = mail->get_group_number();
        selected.name   = mail->get_group_name();
        int savedgrp = selected.number;
        ymin = 0;
        ymax = win->get_ymax();
        current_item = 0;
        pagesize = ymax - ymin + 1;
        maxitem = itemlist.count_items();
        pages = 1+ (maxitem / pagesize);
        --maxitem;

        // go to current group
        itemlist.first();
        do {
                if ( itemlist.get()->number == selected.number ) {
                        break;
                }
        } while( itemlist.next() == true && ++current_item );

        current_page = current_item / pagesize;
        first_of_page = current_page * pagesize;
        ypos = ymin + (current_item - first_of_page );

        win->enable();
        iline.set_default("@ENTER@=select [@n@]ext [@p@]rev [@q@]uit" ); 
        iline.show_default();

        win->clear();
        draw_page();
        do {
                int c = Screen.get_ch();
                iline.reset();
                switch( c ) {
                case PAGE_UP_CMD:
                case CODE_PPAGE:
                        if ( false == ppage() ) {
                                iline.set( AT_FIRST_PAGE_MSG );
                        }
                        break;
                case PAGE_DOWN_CMD:
                case CODE_NPAGE:
                        if( false == npage() ) {
                                iline.set( AT_LAST_PAGE_MSG );
                        }
                        break;
                case CODE_HOME:
                        first();
                        break;
                case CODE_END:
                        last();
                        break;
                case NEXT_CMD:
                case CODE_DOWN:
                        if( false == down() ) {
                                iline.set( AT_BOTTOM_MSG );
                        }
                        break;
                case PREV_CMD:
                case CODE_UP:
                        if( false == up() ) {
                                iline.set( AT_TOP_MSG );
                        }
                        break;
                case FORCED_QUIT_CMD:
#ifndef NO_EXCEPTIONS
                        throw quit_exception();
#else
                        Quit_flag = true;
                        // no break here!!!
#endif
                case QUIT_CMD:
                        quit = true;
                        break;
                case SELECT_CMD:
                        selected = *itemlist.get();
                        quit = true;
                        break;
                default:
                        iline.set( INVALID_COMMAND_MSG );
                        break;
                }
                iline.show();
        } while ( quit == false );

        mail->go_group_number( savedgrp );
        win->disable();
        return selected;
}


void
Groupselection::draw_item( int flag )
{
        String tmp;
        grpnode *grp = itemlist.get();
        win->reset_attr();
        if (flag & EMPHASIZED_FL) {
                win->inverse();
        }
        
        win->clr_line();
        
        win->goto_x (1);
        win->print( "%.3d", current_item );
        
        win->goto_x (10);
        win->print( "Group no: %d", grp->number );
        
        win->goto_x (28);
        if (!(flag & EMPHASIZED_FL)) {
                win->textcolor (Settings.subject_color);
        }
        win->addstr( grp->name.c_str() );
        
        win->reset_attr();

}



jmrsrc-0.7.23/src/jmr.cc100664    764    764      201164  6623366026  14503 0ustar  jvuokkojvuokko// 	$Id: jmr.cc,v 1.43 1998/11/14 20:42: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 = RM_OLD_NO;
#ifdef F_TO_ALL
const String DEFAULT_FOLLOWUPTO = FUT_WRITER;
#endif

const char DEFAULT_QUOTECHARS[] = ":>%&!/#"; 
const int DEFAULT_QUOTEDEPTH = 4;

#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","ask",
        "@NEXT",

	// IV
	RC_QUOTECHARS, "",
	"@NEXT",
	RC_QUOTEDEPTH, "$",
	"@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;
	String tmppath;

        
  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;
                        }
                       

                }

        }
        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
	Wscript->enable();

	switch (Settings.rmoldpacket) 
	  {
	
	  case RM_OLD_YES : 
	    if ( ! mail->get_packet_name().is_empty() ) 
	      {
		Screen.refresh();
		tmppath = Settings.qwkpath;
		correct_path( tmppath );
		tmppath += mail->get_packet_name();
		Wscript->print( "\nRemoving old packet..." );
		Wscript->print( mail->get_packet_name() );
		rm_files( tmppath ); 
		Wscript->print(" OK");
	      }
	    break;


	  case RM_OLD_NO : break;


	  case RM_OLD_ASK : 
	    if ( ! mail->get_packet_name().is_empty() )
	      {
		tmppath = Settings.qwkpath;
		correct_path( tmppath );
		
		Wscript->print( "\nDo you want to delete packet ");
		Wscript->print( mail->get_packet_name() );
		Wscript->print( " (y/n)? n" );
		Screen.refresh();
		if (get_yesno('n') == 'y') {
		  Wscript->print( "\nRemoving old packet..." );
		  tmppath += mail->get_packet_name();
		  rm_files( tmppath );
		  Wscript->print("OK");
		} 
	      }
	    break;
	  }
	
        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();

#ifdef __unix__
           // check for color capable terminal
        char *cterm;
        if ( (cterm = getenv( "COLORTERM" )) ) {
                Screen.force_colormode();
                Wscript->print( "\n\nColor capable terminal '%s' detected!\n",
                                cterm );
                Screen.refresh();
        }
#endif /* __unix__ */

        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 ? Settings.rmoldpacket == RM_OLD_YES ? "yes" : "ask" : "no") );
#ifdef F_TO_ALL
        DEBUG("followupto = " << Settings.followupto );
#endif

	DEBUG("quotechars = " << Settings.quotechars );
	DEBUG("quotedepth = " << Settings.quotedepth );
        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
	Settings.quotechars = DEFAULT_QUOTECHARS;
	Settings.quotedepth = DEFAULT_QUOTEDEPTH;
}

//**************************************************************************/
//  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;
                Settings.confirm_return = (value == "yes");
        }
        
        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 ) {
                if (value == "yes")
                        Settings.rmoldpacket = RM_OLD_YES;
                else if (value == "no")
                        Settings.rmoldpacket = RM_OLD_NO;
                else if (value == "ask")
                        Settings.rmoldpacket = RM_OLD_ASK;
                else {
                        tmp = "Resource \'";
                        tmp += RC_RMOLDPACKET;
                        tmp += "\' is terribly wrong";
                        handle_error( tmp.get(), HALT_FL );
                }
        }

	value = keywords.get_value( RC_QUOTECHARS );
	if ( ! value.is_empty() )
		Settings.quotechars = value;
		
	value = keywords.get_value( RC_QUOTEDEPTH );
	if ( ! value.is_empty() )
		Settings.quotedepth = atoi(value.get());

}


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 specifies all characters that might indicate that the line is";
        fout <<"\n   # quoted from someone else. Default is \":>%&!/#\".";
        fout <<"\n#quote_chars = >";
        fout <<"\n";
        fout <<"\n";
	fout <<"\n   # This tells jmr how deep from the line it should search for";
	fout <<"\n   # quote prefix characters. Default is four";
	fout <<"\n#quote_depth = 4";	
	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 <<"\n   # E.g. next string 'In article dated %d %n wrote:'";
        fout <<"\n   # Expands to something like: ";
        fout <<"\n   #   'In article dated 03-31-1997 John Smith wrote:'";
        fout <<"\n   #";
        fout <<"\n   # Default string is 'In article <%m> %n wrote:'";
        fout <<"\n#followupstring =";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Set up reply string. Syntax is same as in follow-up string, but";
        fout <<"\n   # this is used only in a private replies.";
        fout <<"\n   #";
        fout <<"\n   # Default string is 'On a message dated %d you wrote:'";
        fout <<"\n#replystring = ";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # When this is set to 'no' then only name of the operating system";
        fout <<"\n   # is displayed at the tagline. Default is 'no'.";
        fout <<"\n   # With value 'yes', tagline looks like:";
        fout <<"\n   #         * jmr r.x.y.z [machine/system] *";
        fout <<"\n   # And with 'no', tag is:";
        fout <<"\n   #         * jmr r.x.y.z [system] *";
        fout <<"\n   #";
        fout <<"\n   # Note that this settings works only in Unix-like systems.";
        fout <<"\n#tag_full_sysname = yes";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Write your permanent tagline here.";
        fout <<"\n   # This line will come right after jmr's own tag.";
        fout <<"\n   # Usually you might want leave this empty...";
        fout <<"\n   #      Tagline should not be longer than this!!!";
        fout <<"\n   #      (---------------------------------------------------)";
        fout <<"\n#ptagline = ";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # This sets the default tagline for articles.";
        fout <<"\n   # This string is placed at bottom of each reply, and it will start with";
        fout <<"\n   # three point ( e.g. '...this is the tagline')";
        fout <<"\n   #";
        fout <<"\n   # You can also specify file of taglines by using character '@'";
        fout <<"\n   # at start of tagline. Example: if tagline is:";
        fout <<"\n   #          @my_taglines";
        fout <<"\n   # Then jmr will gets random line from file my_taglines as a tagline.";
        fout <<"\n   #";
        fout <<"\n   # If file name is given without path, then jmr seeks file from jmr's";
        fout <<"\n   # directory ($JMRDIR or ~/.jmr) and if file not found, then jmr seeks";
        fout <<"\n   # from directory /usr/local/lib/jmr ";
        fout <<"\n   #";
        fout <<"\n   # NOTE: if you specify file with path, then you should use full path. e.g:";
        fout <<"\n   # @/home/my_name/sruff/tagline_file";
        fout <<"\n   # @C:\\misc\\taglines.txt";
        fout <<"\n#tagline = This message has been UNIXized for your protection.";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Use external program to generate tagline.";
        fout <<"\n   # This overrides both taglines, 'tagline' and 'ptagline'";
        fout <<"\n#tagline_program = /usr/games/fortune";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Set up signature file.";
        fout <<"\n   # If this is set, then jmr reads singature from the given";
        fout <<"\n   # file. Note that this overrides all tagline settings.";
        fout <<"\n#signaturefile = ~/.signature";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n########################################################################";
        fout <<"\n#";
        fout <<"\n#                         DATABASE SETTINGS";
        fout <<"\n#";
        fout <<"\n########################################################################";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Maximum count of replies to store in log.";
        fout <<"\n   # Default value is 200.";
        fout <<"\n#replylogsize = 1500";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Maximum count of articles to keep in database";
        fout <<"\n   # NOTE: Database for single BBS with 10000 messages requires about";
        fout <<"\n   #       8-10MB free disk space in jmr's home directory, and 8-10MB";
        fout <<"\n   #       free disk space in temporary directory.";
        fout <<"\n   # Default size is 5000";
        fout <<"\n#databasesize = 10000";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n#########################################################################";
        fout <<"\n#";
		fout <<"\n#                    Experimental code and keywords";
		fout <<"\n#";
		fout <<"\n#########################################################################";
		fout <<"\n";
		fout <<"\n";
		fout <<"\n    # If set to 'yes' jmr will automagically remove read qwk packet.";
		fout <<"\n    # Setting it to 'ask', will make jmr to ask permission to delete.";
		fout <<"\n    # Be careful! Not Tested and probably dangerous piece of code!";
                fout <<"\n    # The default value is 'no'.";
		fout <<"\n";
		fout <<"\n#rmoldpacket = ask";
		fout <<"\n";
#ifdef F_TO_ALL
		fout <<"\n    # To whom follow up should be addressed to ?";
		fout <<"\n    # Domain : all, writer, John Doe, ...";
		fout <<"\n    # Setting to writer assumes normal jmr behaviour.";
		fout <<"\n";
		fout <<"\nfollowupto = all";
		fout <<"\n";
#endif
		fout <<"\n";
        fout <<"\n#########################################################################";
        fout <<"\n#";
        fout <<"\n#                              COLORS";
        fout <<"\n#";
        fout <<"\n#########################################################################";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Set up color for quoted part of article";
        fout <<"\n   #";
        fout <<"\n   #    Colors:";
        fout <<"\n   #";
        fout <<"\n   #    0  use default screen color";
        fout <<"\n   #    1  red";
        fout <<"\n   #    2  green";
        fout <<"\n   #    3  brown";
        fout <<"\n   #    4  blue";
        fout <<"\n   #    5  magenta";
        fout <<"\n   #    6  cyan";
        fout <<"\n   #    7  lightgray";
        fout <<"\n   #    8  brightred";
        fout <<"\n   #    9  brightgreen";
        fout <<"\n   #    10 yellow";
        fout <<"\n   #    11 brightblue";
        fout <<"\n   #    12 brightmagenta";
        fout <<"\n   #    13 brightcyan";
        fout <<"\n   #    14 white";
        fout <<"\n   #";
        fout <<"\n   # For non-color terminals, colors are shown : 1 - 7 normal, 8 - 14 bold.";
        fout <<"\n   #";
        fout <<"\n   # Default color is green ";
        fout <<"\n#quote_color = ";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Set up color for normal text of article.";
        fout <<"\n   # Default is cyan ";
        fout <<"\n#article_color = ";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Foreground color for menubar.";
        fout <<"\n   # Default is white ";
        fout <<"\n#menubar_color = ";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Background color for menubar.";
        fout <<"\n   # Default is brightblue ";
        fout <<"\n#menubar_back = ";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Foreground color for statusline.";
        fout <<"\n   # Default is yellow ";
        fout <<"\n#statusline_color = ";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Background color for statusline.";
        fout <<"\n   # Default is brightblue ";
        fout <<"\n#statusline_back = ";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Foreground color for dashed line that splits screen.";
        fout <<"\n   # Default is normal text color";
        fout <<"\n#dashline_color = ";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Background color for dashed line that splits screen.";
        fout <<"\n   # Default is normal text color";
        fout <<"\n#dashline_back = ";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Color for text of infoline (that is line at bottom of the screen)";
        fout <<"\n   # Default is normal text color";
        fout <<"\n#infoline_color = ";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Color for error message that is displayed at the infoline";
        fout <<"\n   # Default is brightred";
        fout <<"\n#infoline_error_color = ";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Color for subject that is displayed at the header part of the screen";
        fout <<"\n   # Default is normal color, but bold text";
        fout <<"\n#header_subject_color = ";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Color for author that is displayed at the header part of the screen";
        fout <<"\n   # Default is color is green";
        fout <<"\n#header_author_color = ";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Color for subject that is displayed at the lists (grouplist, threadlist)";
        fout <<"\n   # Default is color is green";
        fout <<"\n#subject_color = ";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Color for name of the author at the thread list and color for the number";
        fout <<"\n   # of unread articles that is displayed at the group list";
        fout <<"\n   # Default is color is cyan";
        fout <<"\n#author_color = ";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Color for highlighting your name at the personal messages. ";
        fout <<"\n   # Default color is bright yellow";
        fout <<"\n#personal_color = ";
        fout <<"\n";
        fout <<"\n";
        fout <<"\n   # Color for name of the jmrs basegroups at the group list.";
        fout <<"\n   # Default is color is bright green";
        fout <<"\n#basegroup_color = ";
        fout <<"\n";
        fout.close();
        Wscript->enable();
        Wscript->reset_attr();
        Wscript->bold();
        Wscript->print( "\nResource file (%s) created with default settings.\nEdit file and set up required values.", file);

        exit (EXIT_SUCCESS);
}

//**************************************************************************/
//  CLASS: Jmrmain
//  MEMBER FUNCTION: parse_arguments
// 
//  DESCRIPTION: Checks correctness of command line arguments 
//
//  FIXME: Replace by using getopt_long someday... 
// 
// 
//  RETURNS: 
//**************************************************************************/
void Jmrmain::parse_arguments ()
{
        int i;
        resource_file = RESOURCE_FILE_NAME;
        if (argc == 1) {
                return;
        }
        for (i = 1; i < argc; i++) {
                if (check_argument (i) == false) {
                        cerr << "\njmr: illegal option -- "<<argv[i]<<"\n";
                        cerr << "try 'jmr --help' for more information.";
                        cerr << endl;
                        exit(EXIT_FAILURE);
                }
        }
}
//**************************************************************************/
//  CLASS: Jmrmain
//  MEMBER FUNCTION: check_argument
// 
//  DESCRIPTION: Checks if option <n> is legal.
// 
//  RETURNS: true if option is ok. Otherwise false.
//**************************************************************************/
bool Jmrmain::check_argument (int& n)
{
        if (strcmp (argv[n], "-f") == 0 ||
            strcmp (argv[n], "--rcfile") == 0) {
                if (argc > n+1) {
                        resource_file = argv[++n];
                        return true;
                } else {
                        return false;
                }
        }
        if (strcmp (argv[n], "-c") == 0 || strcmp (argv[n], "--color") == 0) {
                Screen.force_colormode();
                return true;
        }
        if (strcmp (argv[n], "-h") == 0 || strcmp (argv[n], "--help") == 0) {
                show_help();
                exit (EXIT_SUCCESS);
        }
        if (strcmp (argv[n], "--init") == 0) {
                init_all = true;
                return true;
        }
        if (strcmp (argv[n], "--open-jmr") == 0) {
                if ( argc > n+1 ) {
                        open_jmr = argv[++n];
                        return true;
                } else
                        return false;
        }
        return false;
}

//**************************************************************************/
//  CLASS: Jmrmain
//  MEMBER FUNCTION: show_help
// 
//  DESCRIPTION: Displays help for options of jmr.
// 
//**************************************************************************/
void Jmrmain::show_help()
{
        cerr << "jmr " << VERSION <<" -- A QWK offline mail reader";
        cerr << "\nCopyright (c) 1997,1998 Jukka Vuokko\n\n" ;
        cerr <<"Usage: jmr [-chl][-f file][--help][--color][--rcfile file][--init]\n\n";
        cerr <<"-h, --help                Show this help and exit.\n";
        cerr <<"-f file, --rcfile file    Use resource file 'file' instead of jmrrc\n";
        cerr <<"-c, --color               Force ANSI-color mode on. Useful in color-xterm\n";
        cerr <<"--init                    Write new jmrrc file\n";
        cerr <<"\nAdvanced option:\n";
        cerr <<"--open-jmr <bbsid>        Opens bbsid.qwk if its is there, otherwise \n";
        cerr <<"                          bbsid dabase is opened.\n";
}


jmrsrc-0.7.23/src/jmrmisc.cc100664    764    764       67740  6623366026  15351 0ustar  jvuokkojvuokko// $Id: jmrmisc.cc,v 1.3 1998/05/25 20:06:04 jvuokko Exp $
/*****************************************************************************
 * *
 * *      MODULE:     jmrmisc.cc
 * *                  ----------
 * *
 * *
 * * Revision  : $Revision: 1.3 $
 * * Date(UTC) : $Date: 1998/05/25 20:06:04 $
 * * Source    : $Source: /usr/local/cvsroot/jmr/src/jmrmisc.cc,v $
 * * Author    : $Author: jvuokko $
 * *
 * ***************************************************************************
 * *    This file is part of jmr offline mail reader.
 * *
 * *    Copyright (C) 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.
 * ***************************************************************************
 * *
 * *      This module contains miscallenous helper functions for jmr
 * *
 *****************************************************************************/

#include <stdio.h>      // sprintf(), rand(), srand(), tmpnam()
#include <time.h>       // time()
#include <stdlib.h>     // EXIT_FAILURE, EXIT_SUCCESS
#include <signal.h>
#include <string.h>     // strerror
#include <errno.h>

#ifdef __WATCOMC__      // Watcom stuff
#   include <io.h>         // access()
#   include <direct.h>
#elif defined (__EMX__)  // EMX-stuff
#   include <unistd.h>   // F_OK
#   include <sys/types.h>
#   include <dirent.h>
#else                    // UNIX
#   include <sys/types.h>
#   include <sys/wait.h>    // wait()
#   include <sys/utsname.h> // uname()
#   include <unistd.h>   // F_OK
#   include <dirent.h>
#   include <fcntl.h>    // open, write, creat, read
#endif

#include "constants.h"
#include "jmr.hh"
#include "time.hh"
#include "terminal_io.hh"
#include "linereader.hh"

//-------------------------------
// for set current diskdrive and copying file
#ifdef OS2
//#   define INCL_DOSERRORS
#   define INCL_ERRORS
#   define INCL_DOSFILEMGR
#   include <os2.h>
#endif

#if defined (WIN32) || defined (DOS)
#   include <dos.h>
#endif

#ifdef __unix__
#   include <unistd.h>  // getcwd, chdir
#endif

//****************** GLOBAL VARIABLES *************************************/
extern settings_t Settings;
extern Terminal_screen Screen;
extern Window *Wscript;

static const char* help_text[] = {
        "@COMMON MOVING COMMANDS:",
        "",
        "  HOME, ESC <    Beginning of list/article",
        "  END, ESC >     End of list/article",
        "  PGUP, Ctrl-v   Page up",
        "  PGDN, ESC v    Page down",
        "  UP ARROW       Line up",
        "  DOWN ARROW     Line down",
        "  LEFT ARROW     Back to previous level",
        "  RIGHT ARROW    Enter to next level",
        "",
        "@COMMON EDITING COMMANDS:",
        "",
        "  Ctrl-a, Ctrl-e Move to beginning or end of the line",
        "  Ctrl-k         Delete all characters, from cursor to end of line",
        "  Ctrl-h         Delete the previous character",
        "  Ctrl-b, Ctrl-f Move backward of forward",
        "",
        "@MAIL PACKET AND DATABASE SELECTION:",
        "",
        "  r              Refresh file or database list",
        "  n              Next packet or database",
        "  p              Previous packet or database",
        "  ENTER          Open packet or database",
        "  l              Switch to list of available databases or list of",
        "                   available mail packets",
        "  q, Q           Quit jmr",
        "",
        "@GROUP SELECTION:",
        "",
        "  n              Next group",
        "  p              Previous group",
        "  ENTER, ->      Enter to group",
        "  TAB            Enter to next group with unread articles",
        "  w              Write an article to current group",
        "  y              Switch between all groups and groups with unread articles",
        "  c              Catchup. Mark all articles in current group as read",
        "  C              Catchup without questions",
        "  t              Tag/untag current group",
        "  T              Tag/untag all groups",
        "  /              Search from current, tagged or all groups",
        "  q              Return to packet selection level",
        "",
        "@THREAD SELECTION:",
        "",
        "  n              Next thread",
        "  p              Previous thread",
        "  TAB            View next unread article within all threads",
        "  ENTER, ->      View first article of current thread",
        "  w              Write an article to current group",
        "  f              Write followup to current article or first article",
        "                   of current thread, if reading mode is by threads",
        "  r              Write private reply to current article (or first",
        "                   article of current thread)",
        "  y              Show all threads or only threads with unread articles",
        "  t              Tag/untag current article (does not work in thread mode)",
        "  T              Tag/untag all articles (not in thread mode)",
        "  s              Sort articles",
        "  c              Catchup. Mark all articles within current group as",
        "                   a read",
        "  C              Forced catchup",
        "  e              Edit current reply. Works only in group 'New Replies'",
        "  E              Edit headers of a current reply.",
        "  k              Kill/unkill article. Works only in groups Replylog,",
        "                   New Replies and Tagged Articles",
        "  q, <-          Return to group selection level",
        "",
        "@MESSAGE VIEWER:",
        "",
        "  TAB, ENTER     View next unread article within current group",
        "  n              View next article",
        "  p              View previous article",
        "  <, Ctrl-a      View first article of a current thread",
        "  >, Ctrl-e      View last article of a current thread",
        "  N              Next article in history",
        "  P              Previous article in history",
        "  f              Write followup to current article",
        "  r              Write private reply to current article",
        "  e              Edit current reply. Works only in group 'New Replies'",
        "  E              Edit headers of a current reply.",
        "  t              Tag/untag current article",
        "  k              Kill/unkill current article. Only in groups:",
        "                   Replylog, New Replies and Tagged Articles",
        "  s              Save current article or thread to file",
        "  SPC            Page down, or if end of current article, then",
        "                   view next unread article",
        "  ESC-r          View article using Rot13",
        "  ESC-w          Toggle line wrapping mode on/off",
        "  q, LEFT ARROW  Return to thread selection level",
        "",
        "@MISC",
        "",
        "  Ctrl-l         Redraw screen",
        "  m              Show message buffer",
        "  Q              Quit jmr",
        "@END" // This must be last item of the array!
};



//*************************************************************************/
// FUNCTION: read_tagline
//*************************************************************************/
//
// Function reads random line from given file.
//
//
// RETURN: line as String object.
//*************************************************************************/
String read_tagline (String const &file)
{
        List<String> *taglines;
        Linereader l( file );

        // read lines from file of taglines to linked list
        taglines = l.read_all_lines();

        // get random line
        String tmp;
        DEBUG( "read_tagline: Lines = " << taglines->count_items());
        int index = rand() % taglines->count_items();
        DEBUG( "read_tagline: random is: " << index );
        if ( taglines->first() == true ) {
                while ( index ) {
                        taglines->next();
                        --index;
                }
                tmp = *taglines->get();
        }
        delete taglines;
        return tmp;
}


//*************************************************************************/
// FUNCTION: get_tagline
//*************************************************************************/
//
// Function gets tagline from file of taglines, or from resource file.
//
// EXTERNAL VARIABLE REFERENCES:
//   IN : Settings.jmrdir, Settings.tagline
//   OUT: 
//
// RETURN: tagline as String
//*************************************************************************/
String
get_tagline ()
{
        // default tagline
        String tag = Settings.tagline;
        tag.cut_tail();
        // read random tagline from file.
        if (Settings.tagline.nget (0) == '@') {
                String file;
                String tmp;
                tmp.copy (Settings.tagline, 1);
                correct_path (tmp);  // expand possible ~
                tmp.ncut_end (1);    // cut trailing '/' or '\'
                file = tmp;
                if (ACCESS (file.get(), F_OK) == 0) {
                        tag = read_tagline (file);
                } else {
                        file = "/usr/local/lib/jmr/" + tmp;
                        if (ACCESS (file.get(), F_OK) == 0) {
                                tag = read_tagline (file);
                        } else {
                                file = Settings.jmrdir + tmp;
                                if (ACCESS (file.get(), F_OK) == 0) {
                                        tag = read_tagline (file);
                                } else {
                                        handle_error ("Cannot access file of taglines.");
                                        tag = "";
                                }
                        }
                }
        }

           // Remove possible ^M from the tagline. Seems like that
           // usually tagline file is in MS-DOG format.... 
           // (where is good old dos2unix?)
        tag.strip_ch( '\r' );
        return tag;
}

/***************************************************************************
 * FUNCTION: clear_workdir
 ***************************************************************************
 *
 * DESCRIPTION: Removes all files from working directory
 *
 * EXTERNAL REFERENCES
 * IN : Settings.workdir
 * OUT:
 *
 ***************************************************************************/
void
clear_workdir()
{
        String path;
        String file;
        String tmp;
        
        path = Settings.workdir;
        correct_path (path);
        
        file = path + "*.[nN][dD][xX]";
        rm_files( file );

        file = path + "*.[dD][aA][tT]";
        rm_files( file );

        file = path + "*.[iI][dD]";
        rm_files( file );

        file = path + "*.[mM][sS][gG]";
        rm_files( file );
        
        // remove files with exact name.
        // Under Os/2, readdir() returns uppercase name, if file is
        // stored to FAT file system. That's why in Os/2 it is needed
        // also check for uppercase names...
        tmp = DEADJMR_FILENAME;
        file = path + tmp;
        rm_files( file );

#ifdef OS2
        file = path + tmp.upcase();
        rm_files( file );
#endif
        
        tmp = DEADJMR_ID_FILENAME;
        file = path + tmp;
        rm_files( file );
#ifdef OS2
        file = path + tmp.upcase();
        rm_files( file );
#endif

        tmp = REPLY_TEMP_FILENAME;
        file = path + tmp;
        rm_files( file );
#ifdef OS2
        file = path + tmp.upcase();
        rm_files( file );
#endif  
}

/***************************************************************************
 * FUNCTION: handle_error
 ***************************************************************************
 *
 * DESCRIPTION: Shows error message, and if flag is HALT_FL, then program 
 *              is halted. 
 *
 *              flag:
 *              DEFAULT_FL     Show error message and wait for key
 *              REPORT_FL      Print error message to stderr, and continue
 *              HALT_FL        Print error message to stderr and halt.
 *
 * EXTERNAL REFERENCES
 * IN : Settings.currentdir
 * OUT:
 *
 ***************************************************************************/
void
handle_error (const char *msg, int flag)
{
        Screen.enable();
        Wscript->reset_attr();
        Wscript->textcolor (BOLD | RED);
        Wscript->enable();
        Wscript->print("\n*** ERROR: ");
        Wscript->reset_attr();
        Wscript->print("%s", msg );
        if (flag != HALT_FL && flag != REPORT_FL) {
                Wscript->print( "\nPress any key to continue.." );
                Screen.get_ch();
                Wscript->disable();
                Wscript->print("\n -----------------------------");
        } else if ( flag == HALT_FL) {
                Wscript->print("\n*** Program halted.\n" );
                Screen.refresh();
                if (Settings.currentdir[0]) {
                        change_dir (Settings.currentdir);
                }
                exit (EXIT_FAILURE);
        }
        Screen.refresh();
}

void
system_error ( const char *msg, int flag )
{
        String str = msg;
        str += " -- ";
        str += strerror( errno );
        handle_error( str.c_str(), flag );
}

void
fatal_error( const char *msg )
{
        handle_error( msg, HALT_FL );
}

/***************************************************************************
 * FUNCTION: convert_to_qwk_date
 ***************************************************************************
 *
 * DESCRIPTION: Converts date from format mm-dd-yyyy to QWK style mm-dd-yy
 *              (and wait year 2000 happy!)
 *
 *
 * RETURN : Pointer to c-string that contains date. Copy it immediately to
 *          the final location
 ***************************************************************************/
char*
convert_to_qwk_date (char *s)
{
        static char buf[12];
        strncpy (buf, s, 6);
        buf[6] = s[8];
        buf[7] = s[9];
        buf[8] = '\0';
        return buf;
}

/***************************************************************************
 * FUNCTION: convert_to_jmr_date
 ***************************************************************************
 *
 * DESCRIPTION: Converts date from stubid QWK format to better mm-dd-yyyy
 *              format
 *
 *
 * RETURN : pointer to static c-string that contains new date.
 ***************************************************************************/
char *
convert_to_jmr_date (char *s)
{
        Time_handler Time;
        static char buf[12];
        char *tmp;
        tmp = Time.get_date();
        strcpy (buf, s);
        buf[6] = tmp[6];
        buf[7] = tmp[7];
        buf[8] = s[6];
        buf[9] = s[7];
        buf[10] = '\0';
        return buf;
}
//*************************************************************************/
// FUNCTION: get_month
//*************************************************************************/
//
// Returns number of month from date that is in jmr's format (mm-dd-yyyy)
//
//*************************************************************************/
int
get_month (char *s)
{
        return (int) (10 * ((*s) - 48) + *(s+1) - 48);
}
//*************************************************************************/
// FUNCTION: get_day
//*************************************************************************/
//
// Returns number of day from date string that is in jmr's date format.
//
//*************************************************************************/
int
get_day (char *s)
{
        return (int) (10 * (*(s+3) - 48) + *(s+4) -48);
}
//*************************************************************************/
// FUNCTION: get_year
//*************************************************************************/
//
// Returns number of year from date string 
//
//*************************************************************************/
int
get_year (char *s)
{
        return atoi (s+6);
}


/***************************************************************************
 * FUNCTION: strip_re_prefix
 ***************************************************************************
 *
 * DESCRIPTION: Checks if prefix 're:' exist. If so, then remove prefix.
 *
 *
 * RETURN : true, if prefix 're:' found.
 ***************************************************************************/
bool
strip_re_prefix (String& str)
{
        bool rc = false;
        String tmp = str;
        
        tmp.cut_first();
        if (tmp.ifind ("re:") == 0) {
                rc = true;
                str.copy (tmp, 3);
        }

        str.cut_first();
        str.cut_tail();
        return rc;
}


/***************************************************************************
 * FUNCTION: get_yesno
 ***************************************************************************
 *
 * DESCRIPTION: Reads answer to question y/n. If user just press enter, then
 *              default_value is token as answer.
 *
 *
 * RETURN : ascii code of answer.
 ***************************************************************************/
int
get_yesno (int default_value)
{
        int c;
        do {
                c = Screen.get_ch();
        } while (c != 'y' && c != SELECT_CMD && c != 'n');
        if (c == SELECT_CMD) {
                c = default_value;
        }
        return c;
}

//*************************************************************************/
// FUNCTION: show_help
//*************************************************************************/
//
// This function shows help.
//
// EXTERNAL VARIABLE REFERENCES:
//   IN : Screen
//   OUT: 
//
// RETURN: 
//*************************************************************************/
void show_help()
{
        int y;
        int ymax = Screen.get_ymax() - 3;
        int index;
  loop:
        index = 0;
        int c;
        y = 0;
        Screen.clear();
        do {
                if (*help_text[index] == '@') {
                        Screen.textcolor( BOLD );
                        Screen.print( "%s\n", help_text[index]+1 );
                        //cout << help_text[index]+1 << "\n";
                        Screen.reset_attr();
                } else {
                        Screen.print( "%s\n", help_text[index] );
                        //cout << help_text[index] << "\n";
                }
                ++index;
                ++y;
                if (y == ymax) {
                        Screen.gotoxy( 0, ymax + 3);
                        Screen.print( "q to quit, ? to start over or any other key to continue" );
                        c = Screen.get_ch();
                        if (c == QUIT_CMD) {
                                return;
                        }
                        if (c == HELP_CMD) {
                                goto loop;
                        }
                        Screen.clear();
                        y = 0;
                        
                }
        } while ( strcmp( help_text[index], "@END" ) );
        Screen.gotoxy(0, ymax + 3);
        Screen.print( "? to start over, any other to exit from help" );
        c = Screen.get_ch();
        if (c == HELP_CMD) {
                goto loop;
        }
}

//**************************************************************************/
// CLASS: Infoline
// MEMBER FUNCTION: reset
//**************************************************************************/ 
//
// 
// 
// EXTERNAL VARIABLE REFERENCES
//   IN :  
//   OUT: 
// 
// PARAMETERS:
//
// RETURN: 
//**************************************************************************/

void
Infoline::reset()
{
        if (true == active) {
                Screen.bottom();
                _msg = "";
                show_option_str( default_msg.get(), Settings.iline_color );
                Screen.clr_eol();
                active = false;
        }
}

//**************************************************************************/
// CLASS: Infoline
// MEMBER FUNCTION: show
//**************************************************************************/ 
//
// 
// 
// EXTERNAL VARIABLE REFERENCES
//   IN :  
//   OUT: 
// 
// PARAMETERS:
//
// RETURN: 
//**************************************************************************/

void
Infoline::show( int flag)
{
        if (true == active || flag & REFRESH_ALL_FL) {
                int color = is_error ? Settings.iline_err_color
                        : Settings.iline_color;
                Screen.bottom();

                if (_msg.is_empty() == false) {
                        show_option_str( _msg.c_str(), color );
                } else {
                        show_option_str( default_msg.c_str(), color );
                }
                Screen.clr_eol();
        }
}
//**************************************************************************/
// CLASS: Infoline
// MEMBER FUNCTION: show_default
//**************************************************************************/ 
//
// 
// 
// EXTERNAL VARIABLE REFERENCES
//   IN :  
//   OUT: 
// 
// PARAMETERS:
//
// RETURN: 
//**************************************************************************/
void
Infoline::show_default()
{
        Screen.bottom();
        show_option_str( default_msg.c_str(), Settings.iline_color | BOLD,
                         Settings.iline_color);
        Screen.clr_eol();
}


//**************************************************************************/
// CLASS: Infoline
// MEMBER FUNCTION: set
//**************************************************************************/ 
//
// 
// 
// EXTERNAL VARIABLE REFERENCES
//   IN :  
//   OUT: 
// 
// PARAMETERS:
//
// RETURN: 
//**************************************************************************/
void
Infoline::set( const char* msg, int fl )
{
        active = true;
        if (fl & ERROR_FL ) {
                _msg = "*** ";
                is_error = true;
        } else {
                _msg = "";
                is_error = false;
        }
        _msg += msg;

}

void
Sline::show()
{
        Screen.gotoxy( 0, Screen.get_ymax() - 1 );
        Screen.reset_attr();
        if( Screen.is_color_term() == true ) {
                Screen.textcolor( Settings.sline_color );
                Screen.back_color( Settings.slineback_color );
        } else {
                Screen.inverse();
        }
        Screen.addstr( get_sline() );
        Screen.reset_attr();
}



//*************************************************************************/
// FUNCTION: set_dashline_color
//*************************************************************************/
//
// Sets colors of dashed line on.
//
// EXTERNAL VARIABLE REFERENCES:
//   IN : Settings.dash_color, Settings_dashback_color
//   OUT: Screen
//
// RETURN: 
//*************************************************************************/
void
set_dashline_color()
{
        Screen.reset_attr();
        if (Settings.dash_color != DEFAULT_FCOLOR) {
                Screen.textcolor( Settings.dash_color );
        }
        if (Settings.dashback_color != DEFAULT_BCOLOR) {
                Screen.back_color( Settings.dashback_color );
        } 
}
//*************************************************************************/
// FUNCTION: show_option_str
//*************************************************************************/
//
// Displays given string using given 'bold_color' in all text that are
// between '@' marks. Color for other text is 'color'.
//
// e.g. If msg is "Press @Q@ for quit", is letter Q highlighted using
// color 'bold_color' and other text is drawed using color 'color'.
//
// EXTERNAL VARIA