Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

bbslist.c 112 KB
Newer Older
deuce's avatar
deuce committed
1 2
/* Copyright (C), 2007 by Stephen Hurd */

3
#include <stdbool.h>
4 5 6 7
#include <stdio.h>
#include <stdlib.h>

#include <dirwrap.h>
8
#include <ini_file.h>
9
#include <uifc.h>
Deucе's avatar
Deucе committed
10
#include <xpprintf.h>
11
#include "filepick.h"
12

13
#include "syncterm.h"
deuce's avatar
deuce committed
14
#include "fonts.h"
15 16
#include "bbslist.h"
#include "uifcinit.h"
17
#include "comio.h"
18
#include "conn.h"
19
#include "ciolib.h"
20
#include "cterm.h"
21 22
#include "window.h"
#include "term.h"
deuce's avatar
deuce committed
23
#include "menu.h"
24
#include "vidmodes.h"
25

26
struct sort_order_info {
27 28 29 30
    char        *name;
    int         flags;
    size_t      offset;
    int         length;
31 32
};

33 34
#define SORT_ORDER_REVERSED     (1<<0)
#define SORT_ORDER_STRING       (1<<1)
deuce's avatar
deuce committed
35

36
static struct sort_order_info sort_order[] = {
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
     {
         NULL
        ,0
        ,0
        ,0
    }
    ,{
         "Entry Name"
        ,SORT_ORDER_STRING
        ,offsetof(struct bbslist, name)
        ,sizeof(((struct bbslist *)NULL)->name)
    }
    ,{
         "Date Added"
        ,SORT_ORDER_REVERSED
        ,offsetof(struct bbslist, added)
        ,sizeof(((struct bbslist *)NULL)->added)
    }
    ,{
         "Date Last Connected"
        ,SORT_ORDER_REVERSED
        ,offsetof(struct bbslist, connected)
        ,sizeof(((struct bbslist *)NULL)->connected)
    }
    ,{
         "Total Calls"
        ,SORT_ORDER_REVERSED
        ,offsetof(struct bbslist, calls)
        ,sizeof(((struct bbslist *)NULL)->calls)
    }
    ,{
         "Dialing List"
        ,0
        ,offsetof(struct bbslist, type)
        ,sizeof(((struct bbslist *)NULL)->type)
    }
    ,{
         "Address"
        ,SORT_ORDER_STRING
        ,offsetof(struct bbslist, addr)
        ,sizeof(((struct bbslist *)NULL)->addr)
    }
    ,{
         "Port"
        ,0
        ,offsetof(struct bbslist, port)
        ,sizeof(((struct bbslist *)NULL)->port)
    }
    ,{
         "Username"
        ,SORT_ORDER_STRING
        ,offsetof(struct bbslist, user)
        ,sizeof(((struct bbslist *)NULL)->user)
    }
    ,{
         "Password"
        ,SORT_ORDER_STRING
        ,offsetof(struct bbslist, password)
        ,sizeof(((struct bbslist *)NULL)->password)
    }
    ,{
         "System Password"
        ,SORT_ORDER_STRING
        ,offsetof(struct bbslist, syspass)
        ,sizeof(((struct bbslist *)NULL)->syspass)
    }
    ,{
         "Connection Type"
        ,0
        ,offsetof(struct bbslist, conn_type)
        ,sizeof(((struct bbslist *)NULL)->conn_type)
    }
    ,{
         "Screen Mode"
        ,0
        ,offsetof(struct bbslist, screen_mode)
        ,sizeof(((struct bbslist *)NULL)->screen_mode)
    }
    ,{
         "Status Line Visibility"
        ,0
        ,offsetof(struct bbslist, nostatus)
        ,sizeof(((struct bbslist *)NULL)->nostatus)
    }
    ,{
         "Download Directory"
        ,SORT_ORDER_STRING
        ,offsetof(struct bbslist, dldir)
        ,sizeof(((struct bbslist *)NULL)->dldir)
    }
    ,{
         "Upload Directory"
        ,SORT_ORDER_STRING
        ,offsetof(struct bbslist, uldir)
        ,sizeof(((struct bbslist *)NULL)->uldir)
    }
    ,{
         "Log File"
        ,SORT_ORDER_STRING
        ,offsetof(struct bbslist, logfile)
        ,sizeof(((struct bbslist *)NULL)->logfile)
    }
    ,{
         "Transfer Log Level"
        ,0
        ,offsetof(struct bbslist, xfer_loglevel)
        ,sizeof(((struct bbslist *)NULL)->xfer_loglevel)
    }
    ,{
         "BPS Rate"
        ,0
        ,offsetof(struct bbslist, bpsrate)
        ,sizeof(((struct bbslist *)NULL)->bpsrate)
    }
    ,{
         "ANSI Music"
        ,0
        ,offsetof(struct bbslist, music)
        ,sizeof(((struct bbslist *)NULL)->music)
    }
    ,{
         "Address Family"
        ,0
        ,offsetof(struct bbslist, address_family)
        ,sizeof(((struct bbslist *)NULL)->address_family)
    }
    ,{
         "Font"
        ,SORT_ORDER_STRING
        ,offsetof(struct bbslist, font)
        ,sizeof(((struct bbslist *)NULL)->font)
    }
    ,{
         "Hide Popups"
        ,0
        ,offsetof(struct bbslist, hidepopups)
        ,sizeof(((struct bbslist *)NULL)->hidepopups)
    }
    ,{
         "RIP"
        ,0
        ,offsetof(struct bbslist, rip)
        ,sizeof(((struct bbslist *)NULL)->rip)
    }
    ,{
         NULL
        ,0
        ,0
        ,0
    }
187 188
};

189 190
int sortorder[sizeof(sort_order)/sizeof(struct sort_order_info)];

Deucе's avatar
Deucе committed
191 192
char *screen_modes[]={     "Current", "80x25", "80x28", "80x30", "80x43", "80x50", "80x60", "132x37 (16:9)", "132x52 (5:4)", "132x25", "132x28", "132x30", "132x34", "132x43", "132x50", "132x60", "C64", "C128 (40col)", "C128 (80col)", "Atari", "Atari XEP80", "Custom", "EGA 80x25", "VGA 80x25", NULL};
static char *screen_modes_enum[]={"Current", "80x25", "80x28", "80x30", "80x43", "80x50", "80x60", "132x37",        "132x52",       "132x25", "132x28", "132x30", "132x34", "132x43", "132x50", "132x60", "C64", "C128-40col",   "C128-80col",   "Atari", "Atari-XEP80", "Custom", "EGA80x25", "VGA80x25", NULL};
Deucе's avatar
Deucе committed
193

194
char *log_levels[]={"Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Info", "Debug", NULL};
195
static char *log_level_desc[]={"None", "Alerts", "Critical Errors", "Errors", "Warnings", "Notices", "Normal", "All (Debug)", NULL};
196

197
char *rate_names[]={"300", "600", "1200", "2400", "4800", "9600", "19200", "38400", "57600", "76800", "115200", "Current", NULL};
198
int rates[]={300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 0};
199

Deucе's avatar
Deucе committed
200 201
static char *rip_versions[] = {"Off", "RIPv1", "RIPv3"};

202 203
static char *fc_names[] = {"RTS/CTS", "XON/XOFF", "RTS/CTS and XON/XOFF", "None", NULL};
static char *fc_enum[] = {"RTSCTS", "XONXOFF", "RTSCTS_XONXOFF", "None", NULL};
204

deuce's avatar
deuce committed
205
char *music_names[]={"ESC [ | only", "BANSI Style", "All ANSI Music enabled", NULL};
206
char music_helpbuf[] = "`ANSI Music Setup`\n\n"
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
                        "~ ESC [ | only ~            Only CSI | (SyncTERM) ANSI music is supported.\n"
                        "                          Enables Delete Line\n"
                        "~ BANSI Style ~             Also enables BANSI-Style (CSI N)\n"
                        "                          Enables Delete Line\n"
                        "~ All ANSI Music Enabled ~  Enables both CSI M and CSI N ANSI music.\n"
                        "                          Delete Line is disabled.\n"
                        "\n"
                        "So-Called ANSI Music has a long and troubled history.  Although the\n"
                        "original ANSI standard has well defined ways to provide private\n"
                        "extensions to the spec, none of these methods were used.  Instead,\n"
                        "so-called ANSI music replaced the Delete Line ANSI sequence.  Many\n"
                        "full-screen editors use DL, and to this day, some programs (Such as\n"
                        "BitchX) require it to run.\n\n"
                        "To deal with this, BananaCom decided to use what *they* thought was an\n"
                        "unspecified escape code ESC[N for ANSI music.  Unfortunately, this is\n"
                        "broken also.  Although rarely implemented in BBS clients, ESC[N is\n"
                        "the erase field sequence.\n\n"
                        "SyncTERM has now defined a third ANSI music sequence which *IS* legal\n"
                        "according to the ANSI spec.  Specifically ESC[|.";
226

227 228
static char *address_families[]={"PerDNS", "IPv4", "IPv6", NULL};
static char *address_family_names[]={"As per DNS", "IPv4 only", "IPv6 only", NULL};
229

230
static char *address_family_help = "`Address Family`\n\n"
231 232 233 234
                            "Select the address family to resolve\n\n"
                            "`As per DNS`..: Uses what is in the DNS system\n"
                            "`IPv4 only`...: Only uses IPv4 addresses.\n"
                            "`IPv6 only`...: Only uses IPv6 addresses.\n";
235

236
static char *address_help=
237 238 239 240 241
                    "`Address`, `Phone Number`, `Serial Port`, or `Command`\n\n"
                    "Enter the hostname, IP address, phone number, or serial port device of\n"
                    "the system to connect to. Example: `nix.synchro.net`\n\n"
                    "In the case of the Shell type, enter the command to run.\n"
                    "Shell types are only functional under *nix\n";
242
static char *conn_type_help=           "`Connection Type`\n\n"
243 244 245 246 247 248 249 250 251 252 253
                                "Select the type of connection you wish to make:\n\n"
                                "`RLogin`...........: Auto-login with RLogin protocol\n"
                                "`RLogin Reversed`..: RLogin using reversed username/password parameters\n"
                                "`Telnet`...........: Use more common Telnet protocol\n"
                                "`Raw`..............: Make a raw TCP socket connection\n"
                                "`SSH`..............: Connect using the Secure Shell (SSH-2) protocol\n"
                                "`Modem`............: Connect using a dial-up modem\n"
                                "`Serial`...........: Connect directly to a serial communications port\n"
                                "`Shell`............: Connect to a local PTY (*nix only)\n"
                                "`MBBS GHost`.......: Communicate using the Major BBS 'GHost' protocol\n";
                                ;
254

255 256
static char *YesNo[3]={"Yes","No",""};

257
ini_style_t ini_style = {
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
    /* key_len */ 15,
    /* key_prefix */ "\t",
    /* section_separator */ "\n",
    /* value_separarator */NULL,
    /* bit_separator */ NULL };

static int
fc_to_enum(int fc)
{
    switch (fc & (COM_FLOW_CONTROL_RTS_CTS | COM_FLOW_CONTROL_XON_OFF)) {
        case COM_FLOW_CONTROL_RTS_CTS:
            return 0;
        case COM_FLOW_CONTROL_XON_OFF:
            return 1;
        case (COM_FLOW_CONTROL_RTS_CTS | COM_FLOW_CONTROL_XON_OFF):
            return 2;
        default:
            return 3;
    }
}

static int
fc_from_enum(int fc_enum)
{
    switch(fc_enum) {
        case 0:
            return COM_FLOW_CONTROL_RTS_CTS;
        case 1:
            return COM_FLOW_CONTROL_XON_OFF;
        case 2:
            return (COM_FLOW_CONTROL_RTS_CTS | COM_FLOW_CONTROL_XON_OFF);
        default:
            return 0;
    }
}
293

294 295
void viewofflinescroll(void)
{
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
    int top;
    int key;
    int i;
    struct  text_info txtinfo;
    struct  text_info sbtxtinfo;
    struct mouse_event mevent;

    if(scrollback_buf==NULL)
        return;
    uifcbail();
    gettextinfo(&txtinfo);

    textmode(scrollback_mode);
    switch(ciolib_to_screen(scrollback_mode)) {
        case SCREEN_MODE_C64:
            setfont(33,TRUE,1);
            break;
        case SCREEN_MODE_C128_40:
        case SCREEN_MODE_C128_80:
            setfont(35,TRUE,1);
            break;
        case SCREEN_MODE_ATARI:
        case SCREEN_MODE_ATARI_XEP80:
            setfont(36,TRUE,1);
            break;
    }
    /* Set up a shadow palette */
    if (cio_api.options & CONIO_OPT_EXTENDED_PALETTE) {
        for (i=0; i < sizeof(dac_default)/sizeof(struct dac_colors); i++)
            setpalette(i + 16, dac_default[i].red << 8 | dac_default[i].red, dac_default[i].green << 8 | dac_default[i].green, dac_default[i].blue << 8 | dac_default[i].blue);
    }
    setfont(0, FALSE, 1);
    setfont(0, FALSE, 2);
    setfont(0, FALSE, 3);
    setfont(0, FALSE, 4);
    drawwin();
    set_modepalette(palettes[COLOUR_PALETTE]);
    top=scrollback_lines;
    gotoxy(1,1);
    textattr(uifc.hclr|(uifc.bclr<<4)|BLINK);
    gettextinfo(&sbtxtinfo);
    ciomouse_addevent(CIOLIB_BUTTON_4_PRESS);
    ciomouse_addevent(CIOLIB_BUTTON_5_PRESS);
    showmouse();

    for(i=0;!i && !quitting;) {
        if(top<1)
            top=1;
        if(top>(int)scrollback_lines)
            top=scrollback_lines;
        vmem_puttext(((sbtxtinfo.screenwidth-scrollback_cols)/2)+1,1
                ,(sbtxtinfo.screenwidth-scrollback_cols)/2+scrollback_cols
                ,sbtxtinfo.screenheight
                ,scrollback_buf+(scrollback_cols*top));
        cputs("Scrollback");
        gotoxy(scrollback_cols-9,1);
        cputs("Scrollback");
        gotoxy(1,1);
        key=getch();
        switch(key) {
            case 0xe0:
            case 0:
                switch(key|getch()<<8) {
                    case CIO_KEY_QUIT:
                        check_exit(TRUE);
                        if (quitting)
                            i=1;
                        break;
                    case CIO_KEY_MOUSE:
                        getmouse(&mevent);
                        switch(mevent.event) {
                            case CIOLIB_BUTTON_1_DRAG_START:
                                mousedrag(scrollback_buf);
                                break;
                            case CIOLIB_BUTTON_4_PRESS:
                                top--;
                                break;
                            case CIOLIB_BUTTON_5_PRESS:
                                top++;
                                break;
                        }
                        break;
                    case CIO_KEY_UP:
                        top--;
                        break;
                    case CIO_KEY_DOWN:
                        top++;
                        break;
                    case CIO_KEY_PPAGE:
                        top-=sbtxtinfo.screenheight;
                        break;
                    case CIO_KEY_NPAGE:
                        top+=sbtxtinfo.screenheight;
                        break;
                    case CIO_KEY_F(1):
                        init_uifc(FALSE, FALSE);
                        uifc.helpbuf=   "`Scrollback Buffer`\n\n"
                                        "~ J ~ or ~ Up Arrow ~   Scrolls up one line\n"
                                        "~ K ~ or ~ Down Arrow ~ Scrolls down one line\n"
                                        "~ H ~ or ~ Page Up ~    Scrolls up one screen\n"
                                        "~ L ~ or ~ Page Down ~  Scrolls down one screen\n";
                        uifc.showhelp();
                        uifcbail();
                        drawwin();
                        break;
                }
                break;
            case 'j':
            case 'J':
                top--;
                break;
            case 'k':
            case 'K':
                top++;
                break;
            case 'h':
            case 'H':
                top-=term.height;
                break;
            case 'l':
            case 'L':
                top+=term.height;
                break;
            case ESC:
                i=1;
                break;
        }
    }

    textmode(txtinfo.currmode);
    init_uifc(TRUE,TRUE);
    return;
428 429
}

430 431
int get_rate_num(int rate)
{
432
    int i;
433

434 435
    for(i=0; rates[i] && (!rate || rate > rates[i]); i++);
    return(i);
436 437 438
}

int get_next_rate(int curr_rate) {
439
    int i;
440

441 442 443 444 445
    if(curr_rate == 0)
        i=0;
    else
        i=get_rate_num(curr_rate)+1;
    return(rates[i]);
446
}
447

448 449
int is_sorting(int chk)
{
450
    int i;
451

452 453 454 455
    for(i=0; i<sizeof(sort_order)/sizeof(struct sort_order_info); i++)
        if((abs(sortorder[i]))==chk)
            return(1);
    return(0);
456 457
}

458 459 460
int intbufcmp(const void *a, const void *b, size_t size)
{
#ifdef __BIG_ENDIAN__
461
    return(memcmp(a,b,size));
462
#else
463 464 465 466 467 468 469 470 471
    int i;
    const unsigned char *ac=(const unsigned char *)a;
    const unsigned char *bc=(const unsigned char *)b;

    for(i=size-1; i>=0; i--) {
        if(ac[i]!=bc[i])
            return(ac[i]-bc[i]);
    }
    return(0);
472 473 474
#endif
}

475 476
int listcmp(const void *aptr, const void *bptr)
{
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
    const char *a=*(void **)(aptr);
    const char *b=*(void **)(bptr);
    int i;
    int item;
    int reverse;
    int ret=0;

    for(i=0; i<sizeof(sort_order)/sizeof(struct sort_order_info); i++) {
        item=abs(sortorder[i]);
        reverse=(sortorder[i]<0?1:0)^((sort_order[item].flags&SORT_ORDER_REVERSED)?1:0);
        if(sort_order[item].name) {
            if(sort_order[item].flags & SORT_ORDER_STRING)
                ret=stricmp(a+sort_order[item].offset,b+sort_order[item].offset);
            else
                ret=intbufcmp(a+sort_order[item].offset,b+sort_order[item].offset,sort_order[item].length);
            if(ret) {
                if(reverse)
                    ret=0-ret;
                return(ret);
            }
        }
        else {
            return(ret);
        }
    }
    return(0);
503 504
}

505
void sort_list(struct bbslist **list, int *listcount, int *cur, int *bar, char *current)  {
506 507 508 509 510 511 512 513 514 515 516 517
    int i;
    qsort(list, *listcount, sizeof(struct bbslist *), listcmp);
    if(cur && current) {
        for(i=0; i<*listcount; i++) {
            if(strcmp(list[i]->name,current)==0) {
                *cur=i;
                if(bar)
                    *bar=i;
                break;
            }
        }
    }
518 519 520 521
}

void write_sortorder(void)
{
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
    char    inipath[MAX_PATH+1];
    FILE    *inifile;
    str_list_t  inicontents;
    str_list_t  sortorders;
    char    str[64];
    int     i;

    sortorders=strListInit();
    for(i=0;sort_order[abs(sortorder[i])].name!=NULL;i++) {
        sprintf(str,"%d",sortorder[i]);
        strListPush(&sortorders, str);
    }

    get_syncterm_filename(inipath, sizeof(inipath), SYNCTERM_PATH_INI, FALSE);
    if((inifile=fopen(inipath,"r"))!=NULL) {
        inicontents=iniReadFile(inifile);
        fclose(inifile);
    }
    else {
        inicontents=strListInit();
    }

    iniSetStringList(&inicontents, "SyncTERM", "SortOrder", ",", sortorders, &ini_style);
    if((inifile=fopen(inipath,"w"))!=NULL) {
        iniWriteFile(inifile,inicontents);
        fclose(inifile);
    }
    strListFree(&sortorders);
    strListFree(&inicontents);
551 552
}

553
void edit_sorting(struct bbslist **list, int *listcount, int *ocur, int *obar, char *current)
554
{
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
    char    opt[sizeof(sort_order)/sizeof(struct sort_order_info)][80];
    char    *opts[sizeof(sort_order)/sizeof(struct sort_order_info)+1];
    char    sopt[sizeof(sort_order)/sizeof(struct sort_order_info)][80];
    char    *sopts[sizeof(sort_order)/sizeof(struct sort_order_info)+1];
    int     curr=0,bar=0;
    int     scurr=0,sbar=0;
    int     ret,sret;
    int     i,j;

    for(i=0;i<sizeof(sort_order)/sizeof(struct sort_order_info);i++)
        opts[i]=opt[i];
    opts[i]=NULL;
    for(i=0;i<sizeof(sort_order)/sizeof(struct sort_order_info);i++)
        sopts[i]=sopt[i];
    sopts[i]=NULL;

    for(;!quitting;) {
        /* Build ordered list of sort order */
        for(i=0; i<sizeof(sort_order)/sizeof(struct sort_order_info); i++) {
            if(sort_order[abs(sortorder[i])].name) {
                SAFECOPY(opt[i], sort_order[abs(sortorder[i])].name);
                if((sortorder[i]<0?1:0) ^ ((sort_order[abs(sortorder[i])].flags&SORT_ORDER_REVERSED)?1:0))
                    strcat(opt[i]," (reversed)");
            }
            else
                opt[i][0]=0;
        }
        uifc.helpbuf=   "`Sort Order`\n\n"
                        "Move the highlight bar to the position you would like\n"
                        "to add a new ordering before and press ~INSERT~.  Choose\n"
                        "a field from the list and it will be inserted.\n\n"
                        "To remove a sort order, use ~DELETE~.\n\n"
                        "To reverse a sort order, highlight it and press enter";
        ret=uifc.list(WIN_XTR|WIN_DEL|WIN_INS|WIN_INSACT|WIN_ACT|WIN_SAV
                    ,0,0,0,&curr,&bar,"Sort Order",opts);
        if(ret==-1) {
            if (uifc.exit_flags & UIFC_XF_QUIT) {
                if (!check_exit(FALSE))
                    continue;
            }
            break;
        }
        if(ret & MSK_INS) {     /* Insert sorting */
            j=0;
            for(i=0; i<sizeof(sort_order)/sizeof(struct sort_order_info); i++) {
                if(!is_sorting(i) && sort_order[i].name) {
                    SAFECOPY(sopt[j], sort_order[i].name);
                    j++;
                }
            }
            if(j==0) {
                uifc.helpbuf=   "All sort orders are present in the list.";
                uifc.msg("No more sort orders.");
                if(check_exit(FALSE))
                    break;
            }
            else {
                sopt[j][0]=0;
                uifc.helpbuf=   "Select a sort order to add and press enter";
                sret=uifc.list(WIN_SAV|WIN_BOT|WIN_RHT
                            ,0,0,0,&scurr,&sbar,"Sort Field",sopts);
                if(sret>=0) {
                    /* Insert into array */
                    memmove(&(sortorder[ret&MSK_OFF])+1,&(sortorder[(ret&MSK_OFF)]),sizeof(sortorder)-sizeof(sortorder[0])*((ret&MSK_OFF)+1));
                    j=0;
                    for(i=0; i<sizeof(sort_order)/sizeof(struct sort_order_info); i++) {
                        if(!is_sorting(i) && sort_order[i].name) {
                            if(j==sret) {
                                sortorder[ret&MSK_OFF]=i;
                                break;
                            }
                            j++;
                        }
                    }
                }
                else {
                    if(check_exit(FALSE))
                        break;
                }
            }
        }
        else if(ret & MSK_DEL) {        /* Delete criteria */
            memmove(&(sortorder[ret&MSK_OFF]),&(sortorder[(ret&MSK_OFF)])+1,sizeof(sortorder)-sizeof(sortorder[0])*((ret&MSK_OFF)+1));
        }
        else {
            sortorder[ret&MSK_OFF]=0-sortorder[ret&MSK_OFF];
        }
    }

    /* Write back to the .ini file */
    write_sortorder();
    sort_list(list, listcount, ocur, obar, current);
647 648
}

649 650
void free_list(struct bbslist **list, int listcount)
{
651
    int i;
652

653 654 655
    for(i=0;i<listcount;i++) {
        FREE_AND_NULL(list[i]);
    }
656 657
}

658
void read_item(str_list_t listfile, struct bbslist *entry, char *bbsname, int id, int type)
659
{
660 661
    char        home[MAX_PATH+1];
    str_list_t  section;
662

663 664
    get_syncterm_filename(home, sizeof(home), SYNCTERM_DEFAULT_TRANSFER_PATH, FALSE);
    if(bbsname != NULL) {
665
#if 0
666 667 668 669 670 671 672 673
        switch(type) {
            case USER_BBSLIST:
                SAFECOPY(entry->name,bbsname);
                break;
            case SYSTEM_BBSLIST:
                sprintf(entry->name,"[%.*s]",sizeof(entry->name)-3,bbsname);
                break;
        }
674
#else
675
        SAFECOPY(entry->name,bbsname);
676
#endif
677 678 679
    }
    section=iniGetSection(listfile,bbsname);
    iniGetString(section,NULL,"Address","",entry->addr);
680
    entry->conn_type=iniGetEnum(section,NULL,"ConnectionType",conn_types_enum,CONN_TYPE_SSH);
681 682 683 684 685 686 687 688 689 690 691 692 693
    entry->flow_control = fc_from_enum(iniGetEnum(section, NULL, "FlowControl", fc_enum, 0));
    entry->port=iniGetShortInt(section,NULL,"Port",conn_ports[entry->conn_type]);
    entry->added=iniGetDateTime(section,NULL,"Added",0);
    entry->connected=iniGetDateTime(section,NULL,"LastConnected",0);
    entry->calls=iniGetInteger(section,NULL,"TotalCalls",0);
    iniGetString(section,NULL,"UserName","",entry->user);
    iniGetString(section,NULL,"Password","",entry->password);
    iniGetString(section,NULL,"SystemPassword","",entry->syspass);
    if(iniGetBool(section,NULL,"BeDumb",FALSE)) /* Legacy */
        entry->conn_type=CONN_TYPE_RAW;
    entry->screen_mode=iniGetEnum(section,NULL,"ScreenMode",screen_modes_enum,SCREEN_MODE_CURRENT);
    entry->nostatus=iniGetBool(section,NULL,"NoStatus",FALSE);
    entry->hidepopups=iniGetBool(section,NULL,"HidePopups",FALSE);
Deucе's avatar
Deucе committed
694
    entry->rip=iniGetEnum(section,NULL,"RIP",rip_versions,RIP_VERSION_NONE);
695 696 697 698 699 700 701 702 703 704 705 706 707
    iniGetString(section,NULL,"DownloadPath",home,entry->dldir);
    iniGetString(section,NULL,"UploadPath",home,entry->uldir);

    /* Log Stuff */
    iniGetString(section,NULL,"LogFile","",entry->logfile);
    entry->append_logfile=iniGetBool(section,NULL,"AppendLogFile",TRUE);
    entry->xfer_loglevel=iniGetEnum(section,NULL,"TransferLogLevel",log_levels,LOG_INFO);
    entry->telnet_loglevel=iniGetEnum(section,NULL,"TelnetLogLevel",log_levels,LOG_INFO);

    entry->bpsrate=iniGetInteger(section,NULL,"BPSRate",0);
    entry->music=iniGetInteger(section,NULL,"ANSIMusic",CTERM_MUSIC_BANSI);
    entry->address_family=iniGetEnum(section,NULL,"AddressFamily",address_families, ADDRESS_FAMILY_UNSPEC);
    iniGetString(section,NULL,"Font","Codepage 437 English",entry->font);
708
    iniGetString(section,NULL,"Comment","",entry->comment);
709 710 711 712
    entry->type=type;
    entry->id=id;

    strListFree(&section);
713 714
}

715 716 717 718 719 720 721 722
/*
 * Checks if bbsname already is listed in list
 * setting *pos to the position if not NULL.
 * optionally only if the entry is a user list
 * entry
 */
int list_name_check(struct bbslist **list, char *bbsname, int *pos, int useronly)
{
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
    int i;

    if(list==NULL) {
        FILE    *listfile;
        str_list_t  inifile;

        if((listfile=fopen(settings.list_path,"r"))!=NULL) {
            inifile=iniReadFile(listfile);
            i=iniSectionExists(inifile, bbsname);
            strListFree(&inifile);
            fclose(listfile);
            return(i);
        }
        return(0);
    }
    for(i=0; list[i]!=NULL; i++) {
        if(useronly && list[i]->type != USER_BBSLIST)
            continue;
        if(stricmp(list[i]->name,bbsname)==0) {
            if(pos)
                *pos=i;
            return(1);
        }
    }
    return(0);
748 749
}

750 751 752 753
/*
 * Reads in a BBS list from listpath using *i as the counter into bbslist
 * first BBS read goes into list[i]
 */
754
void read_list(char *listpath, struct bbslist **list, struct bbslist *defaults, int *i, int type)
755
{
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788
    FILE    *listfile;
    char    *bbsname;
    str_list_t  bbses;
    str_list_t  inilines;

    if((listfile=fopen(listpath,"r"))!=NULL) {
        inilines=iniReadFile(listfile);
        fclose(listfile);
        if(defaults != NULL && type==USER_BBSLIST)
            read_item(inilines,defaults,NULL,-1,type);
        bbses=iniGetSectionList(inilines,NULL);
        while((bbsname=strListRemove(&bbses,0))!=NULL) {
            if(!list_name_check(list, bbsname, NULL, FALSE)) {
                if((list[*i]=(struct bbslist *)malloc(sizeof(struct bbslist)))==NULL) {
                    free(bbsname);
                    break;
                }
                read_item(inilines,list[*i],bbsname,*i,type);
                (*i)++;
            }
            free(bbsname);
        }
        strListFree(&bbses);
        strListFree(&inilines);
    }
    else {
        if(defaults != NULL && type==USER_BBSLIST)
            read_item(NULL,defaults,NULL,-1,type);
    }

#if 0   /* This isn't necessary (NULL is a sufficient) */
    /* Add terminator */
    list[*i]=(struct bbslist *)"";
789
#endif
790 791
}

792 793 794 795 796 797
static void
fc_str(char *str, int fc)
{
    sprintf(str, "Flow Control      %s", fc_names[fc_to_enum(fc)]);
}

798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915
/*
 * Terminates a path with "..." if it's too long.
 * Format must contain only a single '%s'.
 */
void printf_trunc(char *dst, size_t dstsz, char *fmt, char *path)
{
	char *mangled;
	size_t fmt_len = strlen(fmt) - 2;
	size_t remain_len = dstsz - fmt_len;
	size_t full_len = fmt_len + strlen(path);

	if (full_len >= dstsz) {
		mangled = strdup(path);
		if (mangled) {
			mangled[remain_len - 1] = '\0';
			mangled[remain_len - 2] = '.';
			mangled[remain_len - 3] = '.';
			mangled[remain_len - 4] = '.';
			sprintf(dst, fmt, mangled);
		}
		else
			sprintf(dst, fmt, "<Long>");
	}
	else {
		sprintf(dst, fmt, path);
	}
}

void configure_log(struct bbslist *item, const char *itemname, str_list_t inifile, int *changed)
{
	char opt[4][69];
	char *opts[(sizeof(opt)/sizeof(opt[0]))+1];
	int o;
	int i;
	int copt = 0;

	for (o = 0; o < sizeof(opt) / sizeof(opt[0]); o++)
		opts[o] = opt[o];
	opts[o] = NULL;

	for (;;) {
		o = 0;
		printf_trunc(opt[o], sizeof(opt[o]), "Log Filename             %s", item->logfile);
		o++;
		sprintf(opt[o++], "File Transfer Log Level  %s", log_level_desc[item->xfer_loglevel]);
		sprintf(opt[o++], "Telnet Command Log Level %s", log_level_desc[item->telnet_loglevel]);
		sprintf(opt[o++], "Append Log File          %s", item->append_logfile ? "Yes" : "No");

		uifc.helpbuf =
				"`Log Configuration`\n\n"
				"~ Log File ~\n"
				"        Log file name when logging is enabled\n\n"
				"~ File Transfer Log Level ~\n"
				"        Selects the transfer log level.\n\n"
				"~ Telnet Command Log Level ~\n"
				"        Selects the telnet command log level.\n\n"
				"~ Append Log File ~\n"
				"        Append log file (instead of overwrite) on each connection\n\n";
		switch (uifc.list(WIN_SAV|WIN_ACT, 0, 0, 0, &copt, NULL, "Log Configuration", opts)) {
			case -1:
				return;
			case 0:
				uifc.helpbuf=
						"`Log Filename`\n\n"
						"Enter the path to the optional log file.";
				if(uifc.input(WIN_MID|WIN_SAV,0,0,"Log File",item->logfile,MAX_PATH,K_EDIT)>=0) {
					iniSetString(&inifile,itemname,"LogFile",item->logfile,&ini_style);
					*changed = 1;
				}
				else
					check_exit(FALSE);
				break;
			case 1:
				uifc.helpbuf=	"`File Transfer Log Level`\n\n"
						"Select the varbosity level for logging.\n"
						"The lower in the list the item, the more berbose the log.\n"
						"Each level includes all messages in levels above it.";
						i = item->xfer_loglevel;
				switch(uifc.list(WIN_SAV|WIN_BOT|WIN_RHT, 0, 0, 0, &(item->xfer_loglevel), NULL, "File Transfer Log Level", log_level_desc)) {
					case -1:
						item->xfer_loglevel = i;
						check_exit(FALSE);
						break;
					default:
						if (item->xfer_loglevel != i) {
							iniSetEnum(&inifile,itemname,"TransferLogLevel",log_levels,item->xfer_loglevel,&ini_style);
							*changed=1;
						}
				}
                		break;
			case 2:
				uifc.helpbuf=	"`Telnet Command Log Level`\n\n"
						"Select the varbosity level for logging.\n"
						"The lower in the list the item, the more berbose the log.\n"
						"Each level includes all messages in levels above it.";
				i = item->telnet_loglevel;
				switch(uifc.list(WIN_SAV|WIN_BOT|WIN_RHT, 0, 0, 0, &(item->telnet_loglevel), NULL, "Telnet Command Log Level", log_level_desc)) {
					case -1:
						item->telnet_loglevel = i;
						check_exit(FALSE);
						break;
					default:
						if (item->telnet_loglevel != i) {
							iniSetEnum(&inifile,itemname,"TransferLogLevel",log_levels,item->telnet_loglevel,&ini_style);
							*changed=1;
						}
						break;
				}
				break;
			case 3:
				item->append_logfile=!item->append_logfile;
				*changed=1;
				iniSetBool(&inifile,itemname,"AppendLogFile",item->append_logfile,&ini_style);
				break;
		}
	}
}

Deucе's avatar
Deucе committed
916 917 918 919 920 921 922 923 924
static int
get_rip_version(int oldver, int *changed)
{
	int cur = oldver;
	int bar = 0;

	uifc.helpbuf=   "`RIP Version`\n\n"
	    "RIP v1 requires EGA mode while RIP v3\n"
	    "works in any screen mode.";
Deucе's avatar
Deucе committed
925
	switch(uifc.list(WIN_SAV,0,0,0,&cur,NULL,"RIP Mode",rip_versions)) {
Deucе's avatar
Deucе committed
926 927 928 929 930 931 932 933 934 935 936 937
		case -1:
			check_exit(FALSE);
			break;
		case RIP_VERSION_NONE:
		case RIP_VERSION_1:
		case RIP_VERSION_3:
			if (cur != oldver)
				*changed = 1;
	}
	return cur;
}

938
int edit_list(struct bbslist **list, struct bbslist *item,char *listpath,int isdefault)
939
{
940
    char    opt[19][69];    /* 21=Holds number of menu items, 80=Number of columns */
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994
    char    *opts[(sizeof(opt)/sizeof(opt[0]))+1];
    int     changed=0;
    int     copt=0,i,j;
    int     bar=0;
    char    str[64];
    FILE *listfile;
    str_list_t  inifile;
    char    tmp[LIST_NAME_MAX+1];
    char    *itemname;

    for(i=0;i<sizeof(opt)/sizeof(opt[0]);i++)
        opts[i]=opt[i];
    if(item->type==SYSTEM_BBSLIST) {
        uifc.helpbuf=   "`Copy from system directory`\n\n"
                        "This entry was loaded from the system directory.  In order to edit it, it\n"
                        "must be copied into your personal directory.\n";
        i=0;
        if(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,NULL,"Copy from system directory?",YesNo)!=0) {
            check_exit(FALSE);
            return(0);
        }
        item->type=USER_BBSLIST;
        add_bbs(listpath, item);
    }
    if((listfile=fopen(listpath,"r"))!=NULL) {
        inifile=iniReadFile(listfile);
        fclose(listfile);
    }
    else {
        inifile=strListInit();
    }

    if(isdefault)
        itemname=NULL;
    else
        itemname=item->name;
    for(;!quitting;) {
        i=0;
        if(!isdefault) {
            sprintf(opt[i++], "Name              %s",itemname);
            if(item->conn_type==CONN_TYPE_MODEM)
                sprintf(opt[i++], "Phone Number      %s",item->addr);
            else if(item->conn_type==CONN_TYPE_SERIAL)
                sprintf(opt[i++], "Device Name       %s",item->addr);
            else if(item->conn_type==CONN_TYPE_SHELL)
                sprintf(opt[i++], "Command           %s",item->addr);
            else
                sprintf(opt[i++], "Address           %s",item->addr);
        }
        sprintf(opt[i++], "Connection Type   %s",conn_types[item->conn_type]);
        if (item->conn_type == CONN_TYPE_MODEM || item->conn_type ==CONN_TYPE_SERIAL)
            fc_str(opt[i++], item->flow_control);
        else if (item->conn_type != CONN_TYPE_SHELL)
            sprintf(opt[i++], "TCP Port          %hu",item->port);
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
        if (item->conn_type == CONN_TYPE_SSHNA) {
		printf_trunc(opt[i], sizeof(opt[i]), "SSH Username      %s",item->user);
		i++;
		sprintf(opt[i++], "BBS Username      %s",item->password);
		sprintf(opt[i++], "BBS Password      %s",item->syspass[0]?"********":"<none>");
	}
	else {
		printf_trunc(opt[i], sizeof(opt[i]), "Username          %s",item->user);
		i++;
		sprintf(opt[i++], "Password          %s",item->password[0]?"********":"<none>");
		sprintf(opt[i++], "System Password   %s",item->syspass[0]?"********":"<none>");
	}
1007 1008
        sprintf(opt[i++], "Screen Mode       %s",screen_modes[item->screen_mode]);
        sprintf(opt[i++], "Hide Status Line  %s",item->nostatus?"Yes":"No");
1009 1010 1011 1012 1013
        printf_trunc(opt[i], sizeof(opt[i]), "Download Path     %s", item->dldir);
	i++;
        printf_trunc(opt[i], sizeof(opt[i]), "Upload Path       %s", item->uldir);
	i++;
        strcpy(opt[i++], "Log Configuration");
1014 1015 1016 1017 1018 1019 1020 1021 1022
        if(item->bpsrate)
            sprintf(str,"%ubps", item->bpsrate);
        else
            strcpy(str,"Current");
        sprintf(opt[i++], "Comm Rate         %s",str);
        sprintf(opt[i++], "ANSI Music        %s",music_names[item->music]);
        sprintf(opt[i++], "Address Family    %s",address_family_names[item->address_family]);
        sprintf(opt[i++], "Font              %s",item->font);
        sprintf(opt[i++], "Hide Popups       %s",item->hidepopups?"Yes":"No");
Deucе's avatar
Deucе committed
1023
        sprintf(opt[i++], "RIP               %s",rip_versions[item->rip]);
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
        opt[i][0]=0;
        uifc.changes=0;

        if (isdefault) {
            uifc.helpbuf=   "`Edit Default Connection`\n\n"
                            "Select item to edit.\n\n"
                            "~ Conection Type ~\n"
                            "        Type of connection\n\n"
                            "~ TCP Port ~ (if applicable)\n"
                            "        TCP port to connect to (applicable types only)\n\n"
                            "~ Username ~\n"
                            "        Username sent by the auto-login command\n\n"
                            "~ Password ~\n"
                            "        Password sent by auto-login command (not securely stored)\n\n"
                            "~ System Password ~\n"
                            "        System Password sent by auto-login command (not securely stored)\n\n"
                            "~ Screen Mode ~\n"
                            "        Display mode to use\n\n"
                            "~ Hide Status Line ~\n"
                            "        Selects if the status line should be hidden, giving an extra\n"
                            "        display row\n\n"
                            "~ Download Path ~\n"
                            "        Default path to store downloaded files\n\n"
                            "~ Upload Path ~\n"
                            "        Default path for uploads\n\n"
1049 1050
                            "~ Log Configuration ~\n"
                            "        Configure logging settings\n\n"
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088
                            "~ Comm Rate ~\n"
                            "        Display speed\n\n"
                            "~ ANSI Music ~\n"
                            "        ANSI music type selection\n\n"
                            "~ Address Family ~\n"
                            "        IPv4 or IPv6\n\n"
                            "~ Font ~\n"
                            "        Select font to use for the entry\n\n"
                            "~ Hide Popups ~\n"
                            "        Hide all popup dialogs (i.e., Connecting, Disconnected, etc.)\n\n"
                            ;
        }
        else {
            uifc.helpbuf=   "`Edit Directory Entry`\n\n"
                            "Select item to edit.\n\n"
                            "~ Name ~\n"
                            "        The name of the BBS entry\n\n"
                            "~ Phone Number / Device Name / Command / Address ~\n"
                            "        Required information to establish the connection (type specific)\n\n"
                            "~ Conection Type ~\n"
                            "        Type of connection\n\n"
                            "~ TCP Port ~ (if applicable)\n"
                            "        TCP port to connect to (applicable types only)\n\n"
                            "~ Username ~\n"
                            "        Username sent by the auto-login command\n\n"
                            "~ Password ~\n"
                            "        Password sent by auto-login command (not securely stored)\n\n"
                            "~ System Password ~\n"
                            "        System Password sent by auto-login command (not securely stored)\n\n"
                            "~ Screen Mode ~\n"
                            "        Display mode to use\n\n"
                            "~ Hide Status Line ~\n"
                            "        Selects if the status line should be hidden, giving an extra\n"
                            "        display row\n\n"
                            "~ Download Path ~\n"
                            "        Default path to store downloaded files\n\n"
                            "~ Upload Path ~\n"
                            "        Default path for uploads\n\n"
1089 1090
                            "~ Log Configuration ~\n"
                            "        Configure logging settings\n\n"
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215
                            "~ Comm Rate ~\n"
                            "        Display speed\n\n"
                            "~ ANSI Music ~\n"
                            "        ANSI music type selection\n\n"
                            "~ Address Family ~\n"
                            "        IPv4 or IPv6\n\n"
                            "~ Font ~\n"
                            "        Select font to use for the entry\n\n"
                            "~ Hide Popups ~\n"
                            "        Hide all popup dialogs (i.e., Connecting, Disconnected, etc.)\n\n"
                            ;
        }
        i=uifc.list(WIN_MID|WIN_SAV|WIN_ACT,0,0,0,&copt,&bar
            ,isdefault ? "Edit Default Connection":"Edit Directory Entry"
            ,opts);
        if(i>=0 && isdefault)
            i+=2;
        if(i>=3 && item->conn_type==CONN_TYPE_SHELL)
            i++;    /* no port number */
        switch(i) {
            case -1:
                check_exit(FALSE);
                if((!isdefault) && (itemname!=NULL) && (itemname[0]==0)) {
                    uifc.helpbuf=   "`Cancel Save`\n\n"
                                    "This entry has no name and can therefore not be saved.\n"
                                    "Selecting `No` will return to editing mode.\n";
                    i=0;
                    if(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,NULL,"Cancel Save?",YesNo)!=0) {
                        quitting=FALSE;
                        check_exit(FALSE);
                        break;
                    }
                    strListFree(&inifile);
                    return(0);
                }
                if(!safe_mode) {
                    if((listfile=fopen(listpath,"w"))!=NULL) {
                        iniWriteFile(listfile,inifile);
                        fclose(listfile);
                    }
                }
                strListFree(&inifile);
                return(changed);
            case 0:
                do {
                    uifc.helpbuf=   "`Directory Entry Name`\n\n"
                                    "Enter the name of the entry as it is to appear in the directory.";
                    strcpy(tmp,itemname);
                    uifc.input(WIN_MID|WIN_SAV,0,0,"Name",tmp,LIST_NAME_MAX,K_EDIT);
                    check_exit(FALSE);
                    if(quitting)
                        break;
                    if(stricmp(tmp,itemname) && list_name_check(list, tmp, NULL, FALSE)) {
                        uifc.helpbuf=   "`Entry Name Already Exists`\n\n"
                                        "An entry with that name already exists in the directory.\n"
                                        "Please choose a unique name.\n";
                        uifc.msg("Entry Name Already Exists!");
                        check_exit(FALSE);
                    }
                    else {
                        if(tmp[0]==0) {
                            uifc.helpbuf=   "`Can Not Use and Empty Name`\n\n"
                                            "Entry names can not be empty.  Please enter an entry name.\n";
                            uifc.msg("Can not use an empty name");
                            check_exit(FALSE);
                        }
                        else {
                            iniRenameSection(&inifile,itemname,tmp);
                            strcpy(itemname, tmp);
                        }
                    }
                } while(tmp[0]==0 && !quitting);
                break;
            case 1:
                uifc.helpbuf=address_help;
                uifc.input(WIN_MID|WIN_SAV,0,0
                    ,item->conn_type==CONN_TYPE_MODEM ? "Phone Number"
                    :item->conn_type==CONN_TYPE_SERIAL ? "Device Name"
                    :item->conn_type==CONN_TYPE_SHELL ? "Command"
                    : "Address"
                    ,item->addr,LIST_ADDR_MAX,K_EDIT);
                check_exit(FALSE);
                iniSetString(&inifile,itemname,"Address",item->addr,&ini_style);
                break;
            case 3:
                if (item->conn_type == CONN_TYPE_MODEM || item->conn_type == CONN_TYPE_SERIAL) {
                    uifc.helpbuf = "`Flow Control`\n\n"
                                   "Select the desired flow control type.\n"
                                   "This should usually be left as \"RTS/CTS\".\n";
                    i = fc_to_enum(item->flow_control);
                    j = i;
                    switch (uifc.list(WIN_SAV, 0, 0, 0, &j, NULL, "Flow Control", fc_names)) {
                        case -1:
                            check_exit(FALSE);
                            break;
                        default:
                            item->flow_control = fc_from_enum(j);
                            if (j != i) {
                                iniSetEnum(&inifile, itemname, "FlowControl", fc_enum, j, &ini_style);
                                uifc.changes = 1;
                            }
                            break;
                    }
                }
                else {
                    i=item->port;
                    sprintf(str,"%hu",item->port);
                    uifc.helpbuf=   "`TCP Port`\n\n"
                                    "Enter the TCP port number that the server is listening to on the remote system.\n"
                                    "Telnet is generally port 23, RLogin is generally 513 and SSH is\n"
                                    "generally 22\n";
                    uifc.input(WIN_MID|WIN_SAV,0,0,"TCP Port",str,5,K_EDIT|K_NUMBER);
                    check_exit(FALSE);
                    j=atoi(str);
                    if(j<1 || j>65535)
                        j=conn_ports[item->conn_type];
                    item->port=j;
                    iniSetShortInt(&inifile,itemname,"Port",item->port,&ini_style);
                    if(i!=j)
                        uifc.changes=1;
                    else
                        uifc.changes=0;
                }
                break;
            case 4:
1216 1217 1218 1219 1220 1221 1222 1223 1224
		if (item->conn_type == CONN_TYPE_SSHNA) {
			uifc.helpbuf=   "`SSH Username`\n\n"
					"Enter the username for passwordless SSH authentication.";
		}
		else {
			uifc.helpbuf=   "`Username`\n\n"
					"Enter the username to attempt auto-login to the remote with.\n"
					"For SSH, this must be the SSH user name.";
		}
1225 1226 1227 1228 1229
                uifc.input(WIN_MID|WIN_SAV,0,0,"Username",item->user,MAX_USER_LEN,K_EDIT);
                check_exit(FALSE);
                iniSetString(&inifile,itemname,"UserName",item->user,&ini_style);
                break;
            case 5:
1230 1231 1232 1233 1234 1235 1236 1237 1238
		if (item->conn_type == CONN_TYPE_SSHNA) {
			uifc.helpbuf=   "`BBS Username`\n\n"
					"Enter the username to be sent for auto-login (ALT-L).";
		}
		else {
			uifc.helpbuf=   "`Password`\n\n"
					"Enter your password for auto-login.\n"
					"For SSH, this must be the SSH password if it exists.\n";
		}
1239 1240 1241 1242 1243
                uifc.input(WIN_MID|WIN_SAV,0,0,"Password",item->password,MAX_PASSWD_LEN,K_EDIT);
                check_exit(FALSE);
                iniSetString(&inifile,itemname,"Password",item->password,&ini_style);
                break;
            case 6:
1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254
		if (item->conn_type == CONN_TYPE_SSHNA) {
			uifc.helpbuf=   "`BBS Password`\n\n"
					"Enter your password for auto-login. (ALT-L)\n";
		}
		else {
			uifc.helpbuf=   "`System Password`\n\n"
					"Enter your System password for auto-login.\n"
					"This password is sent after the username and password, so for non-\n"
					"Synchronet, or non-sysop accounts, this can be used for simple\n"
					"scripting.";
		}
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271
                uifc.input(WIN_MID|WIN_SAV,0,0,"System Password",item->syspass,MAX_SYSPASS_LEN,K_EDIT);
                check_exit(FALSE);
                iniSetString(&inifile,itemname,"SystemPassword",item->syspass,&ini_style);
                break;
            case 2:
                i=item->conn_type;
                item->conn_type--;
                uifc.helpbuf=conn_type_help;
                switch(uifc.list(WIN_SAV,0,0,0,&(item->conn_type),NULL,"Connection Type",&(conn_types[1]))) {
                    case -1:
                        check_exit(FALSE);
                        item->conn_type=i;
                        break;
                    default:
                        item->conn_type++;
                        iniSetEnum(&inifile,itemname,"ConnectionType",conn_types_enum,item->conn_type,&ini_style);

1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283
			// TODO: NOTE: This is destructive!  Beware!  Ooooooo....
			if (i == CONN_TYPE_SSHNA && item->conn_type != CONN_TYPE_SSHNA) {
				SAFECOPY(item->user, item->password);
				SAFECOPY(item->password, item->syspass);
				item->syspass[0] = 0;
			}
			if (i != CONN_TYPE_SSHNA && item->conn_type == CONN_TYPE_SSHNA) {
				SAFECOPY(item->syspass, item->password);
				SAFECOPY(item->password, item->user);
				item->user[0] = 0;
			}

1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310
                        if(item->conn_type!=CONN_TYPE_MODEM && item->conn_type!=CONN_TYPE_SERIAL
                                && item->conn_type!=CONN_TYPE_SHELL
                                ) {
                            /* Set the port too */
                            j=conn_ports[item->conn_type];
                            if(j<1 || j>65535)
                                j=item->port;
                            item->port=j;
                            iniSetShortInt(&inifile,itemname,"Port",item->port,&ini_style);
                        }

                        changed=1;
                        break;
                }
                break;
            case 7:
                i=item->screen_mode;
                uifc.helpbuf=   "`Screen Mode`\n\n"
                                "Select the screen size for this connection\n";
                j = i;
                switch(uifc.list(WIN_SAV,0,0,0,&(item->screen_mode),&j,"Screen Mode",screen_modes)) {
                    case -1:
                        check_exit(FALSE);
                        item->screen_mode=i;
                        break;
                    default:
                        iniSetEnum(&inifile,itemname,"ScreenMode",screen_modes_enum,item->screen_mode,&ini_style);
Deucе's avatar
Deucе committed
1311 1312 1313
                        if (item->rip == RIP_VERSION_1 && item->screen_mode != SCREEN_MODE_EGA_80X25 && item->screen_mode != SCREEN_MODE_80X43) {
                            item->rip = RIP_VERSION_3;
                            iniSetEnum(&inifile,itemname,"RIP",rip_versions,item->rip,&ini_style);
1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373
                        }
                        if(item->screen_mode == SCREEN_MODE_C64) {
                            SAFECOPY(item->font,font_names[33]);
                            iniSetString(&inifile,itemname,"Font",item->font,&ini_style);
                            item->nostatus = 1;
                            iniSetBool(&inifile,itemname,"NoStatus",item->nostatus,&ini_style);
                        }
                        else if(item->screen_mode == SCREEN_MODE_C128_40
                                || item->screen_mode == SCREEN_MODE_C128_80) {
                            SAFECOPY(item->font,font_names[35]);
                            iniSetString(&inifile,itemname,"Font",item->font,&ini_style);
                            item->nostatus = 1;
                            iniSetBool(&inifile,itemname,"NoStatus",item->nostatus,&ini_style);
                        }
                        else if(item->screen_mode == SCREEN_MODE_ATARI) {
                            SAFECOPY(item->font,font_names[36]);
                            iniSetString(&inifile,itemname,"Font",item->font,&ini_style);
                            item->nostatus = 1;
                            iniSetBool(&inifile,itemname,"NoStatus",item->nostatus,&ini_style);
                        }
                        else if(item->screen_mode == SCREEN_MODE_ATARI_XEP80) {
                            SAFECOPY(item->font,font_names[36]);
                            iniSetString(&inifile,itemname,"Font",item->font,&ini_style);
                            item->nostatus = 1;
                            iniSetBool(&inifile,itemname,"NoStatus",item->nostatus,&ini_style);
                        }
                        else if (i == SCREEN_MODE_C64 || i == SCREEN_MODE_C128_40 ||
                            i == SCREEN_MODE_C128_80 || i == SCREEN_MODE_ATARI ||
                            i == SCREEN_MODE_ATARI_XEP80) {
                            SAFECOPY(item->font,font_names[0]);
                            iniSetString(&inifile,itemname,"Font",item->font,&ini_style);
                            item->nostatus = 0;
                            iniSetBool(&inifile,itemname,"NoStatus",item->nostatus,&ini_style);
                        }
                        changed=1;
                        break;
                }
                break;
            case 8:
                item->nostatus=!item->nostatus;
                changed=1;
                iniSetBool(&inifile,itemname,"NoStatus",item->nostatus,&ini_style);
                break;
            case 9:
                uifc.helpbuf=   "`Download Path`\n\n"
                                "Enter the path where downloads will be placed.";
                if(uifc.input(WIN_MID|WIN_SAV,0,0,"Download Path",item->dldir,MAX_PATH,K_EDIT)>=0)
                    iniSetString(&inifile,itemname,"DownloadPath",item->dldir,&ini_style);
                else
                    check_exit(FALSE);
                break;
            case 10:
                uifc.helpbuf=   "`Upload Path`\n\n"
                                "Enter the path where uploads will be browsed from.";
                if(uifc.input(WIN_MID|WIN_SAV,0,0,"Upload Path",item->uldir,MAX_PATH,K_EDIT)>=0)
                    iniSetString(&inifile,itemname,"UploadPath",item->uldir,&ini_style);
                else
                    check_exit(FALSE);
                break;
            case 11:
1374
		configure_log(item, itemname, inifile, &changed);
1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394
                break;
            case 12:
                uifc.helpbuf=   "`Comm Rate (in bits-per-second)`\n\n"
                                "`For TCP connections:`\n"
                                "Select the rate which received characters will be displayed.\n\n"
                                "This allows animated ANSI and some games to work as intended.\n\n"
                                "`For Modem/Direct COM port connections:`\n"
                                "Select the `DTE Rate` to use."
                                ;
                i=get_rate_num(item->bpsrate);
                switch(uifc.list(WIN_SAV,0,0,0,&i,NULL,"Comm Rate (BPS)",rate_names)) {
                    case -1:
                        check_exit(FALSE);
                        break;
                    default:
                        item->bpsrate=rates[i];
                        iniSetInteger(&inifile,itemname,"BPSRate",item->bpsrate,&ini_style);
                        changed=1;
                }
                break;
1395
            case 13:
1396 1397 1398 1399 1400 1401 1402 1403 1404
                uifc.helpbuf=music_helpbuf;             i=item->music;
                if(uifc.list(WIN_SAV,0,0,0,&i,NULL,"ANSI Music Setup",music_names)!=-1) {
                    item->music=i;
                    iniSetInteger(&inifile,itemname,"ANSIMusic",item->music,&ini_style);
                    changed=1;
                }
                else
                    check_exit(FALSE);
                break;
1405
            case 14:
1406 1407 1408 1409 1410 1411 1412 1413 1414 1415
                uifc.helpbuf=address_family_help;
                i=item->address_family;
                if(uifc.list(WIN_SAV, 0, 0, 0, &i, NULL, "Address Family", address_family_names)!=-1) {
                    item->address_family=i;
                    iniSetEnum(&inifile, itemname, "AddressFamily", address_families, item->address_family, &ini_style);
                    changed=1;
                }
                else
                    check_exit(FALSE);
                break;
1416
            case 15:
1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433
                uifc.helpbuf=   "`Font`\n\n"
                                "Select the desired font for this connection.\n\n"
                                "Some fonts do not allow some modes.  When this is the case, an\n"
                                "appropriate mode will be forced.\n";
                i=j=find_font_id(item->font);
                switch(uifc.list(WIN_SAV,0,0,0,&i,&j,"Font",font_names)) {
                    case -1:
                        check_exit(FALSE);
                        break;
                    default:
                    if(i!=find_font_id(item->font)) {
                        SAFECOPY(item->font,font_names[i]);
                        iniSetString(&inifile,itemname,"Font",item->font,&ini_style);
                        changed=1;
                    }
                }
                break;
1434
            case 16:
1435 1436 1437 1438
                item->hidepopups=!item->hidepopups;
                changed=1;
                iniSetBool(&inifile,itemname,"HidePopups",item->hidepopups,&ini_style);
                break;
1439
            case 17:
Deucе's avatar
Deucе committed
1440 1441
                item->rip = get_rip_version(item->rip, &changed);
                if (item->rip == RIP_VERSION_1) {
1442 1443 1444
                    item->screen_mode = 4;
                    iniSetEnum(&inifile,itemname,"ScreenMode",screen_modes_enum,item->screen_mode,&ini_style);
                }
Deucе's avatar
Deucе committed
1445
                iniSetEnum(&inifile,itemname,"RIP",rip_versions,item->rip,&ini_style);
1446 1447 1448 1449 1450 1451
        }
        if(uifc.changes)
            changed=1;
    }
    strListFree(&inifile);
    return (changed);
1452 1453
}

1454 1455
void add_bbs(char *listpath, struct bbslist *bbs