diff options
| author | erdgeist <> | 2003-02-12 17:48:37 +0000 |
|---|---|---|
| committer | erdgeist <> | 2003-02-12 17:48:37 +0000 |
| commit | dea6bf757aa9a875eab35b2b650412e7605f1308 (patch) | |
| tree | 14ed8374c3a3862529313088375693a7de70d3a7 /vchat-client.c | |
CVS moved to erdgeist.org
Diffstat (limited to 'vchat-client.c')
| -rwxr-xr-x | vchat-client.c | 536 |
1 files changed, 536 insertions, 0 deletions
diff --git a/vchat-client.c b/vchat-client.c new file mode 100755 index 0000000..ae369ab --- /dev/null +++ b/vchat-client.c | |||
| @@ -0,0 +1,536 @@ | |||
| 1 | /* | ||
| 2 | * vchat-client - alpha version | ||
| 3 | * vchat-client.c - main() and utility functions | ||
| 4 | * | ||
| 5 | * Copyright (C) 2001 Andreas Kotes <count@flatline.de> | ||
| 6 | * | ||
| 7 | * This program is free software. It can be redistributed and/or modified, | ||
| 8 | * provided that this copyright notice is kept intact. This program is | ||
| 9 | * distributed in the hope that it will be useful, but without any warranty; | ||
| 10 | * without even the implied warranty of merchantability or fitness for a | ||
| 11 | * particular purpose. In no event shall the copyright holder be liable for | ||
| 12 | * any direct, indirect, incidental or special damages arising in any way out | ||
| 13 | * of the use of this software. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* general includes */ | ||
| 18 | #include <sys/types.h> | ||
| 19 | #include <sys/time.h> | ||
| 20 | #include <string.h> | ||
| 21 | #include <unistd.h> | ||
| 22 | #include <stdio.h> | ||
| 23 | #include <stdlib.h> | ||
| 24 | #include <errno.h> | ||
| 25 | #include <fcntl.h> | ||
| 26 | #include <signal.h> | ||
| 27 | #include <readline/readline.h> | ||
| 28 | #include <openssl/ssl.h> | ||
| 29 | #include "vchat.h" | ||
| 30 | |||
| 31 | /* version of this module */ | ||
| 32 | unsigned char *vchat_cl_version = "$Id$"; | ||
| 33 | |||
| 34 | /* externally used variables */ | ||
| 35 | /* we're logged in */ | ||
| 36 | unsigned int loggedin = 0; | ||
| 37 | /* we run as long as this is true */ | ||
| 38 | unsigned int status = 1; | ||
| 39 | /* error string to show after exit */ | ||
| 40 | unsigned char errstr[ERRSTRSIZE] = "\0"; | ||
| 41 | |||
| 42 | /* locally global variables */ | ||
| 43 | /* our list of filedescriptors */ | ||
| 44 | static fd_set masterfds; | ||
| 45 | |||
| 46 | /* declaration of configuration array */ | ||
| 47 | #include "vchat-config.h" | ||
| 48 | |||
| 49 | /* servers filedescriptor from vchat-protocol.c */ | ||
| 50 | extern int serverfd; | ||
| 51 | |||
| 52 | void setnoption (unsigned char *, unsigned char *); | ||
| 53 | |||
| 54 | static void parsecfg(unsigned char *line) { | ||
| 55 | int bytes; | ||
| 56 | unsigned char *param=line; | ||
| 57 | unsigned char *value=NULL; | ||
| 58 | |||
| 59 | /* handle quotes value is empty, so wecan use it */ | ||
| 60 | value = strchr(line,'#'); | ||
| 61 | if (value) { /* the line contains a cute little quote */ | ||
| 62 | value[0]='\0'; /* ignore the rest of the line */ | ||
| 63 | } | ||
| 64 | |||
| 65 | /* now split the line into two parts */ | ||
| 66 | value = strchr(line,'='); | ||
| 67 | if (!value) return; /* exit if strchr fails */ | ||
| 68 | value[0]='\0'; | ||
| 69 | value++; | ||
| 70 | |||
| 71 | /* "trim" values */ | ||
| 72 | while ((value[0] == ' ')||(value[0] == '\t')) | ||
| 73 | value++; | ||
| 74 | bytes = strlen(value); | ||
| 75 | while ((value[bytes-1] == ' ')||(value[bytes-1] == '\t')) { | ||
| 76 | value[bytes-1] = '\0'; | ||
| 77 | bytes=strlen(value); | ||
| 78 | } | ||
| 79 | /* bytes should be strlen(value) */ | ||
| 80 | if ( value[bytes-1] == '"' ) value[bytes-1] = '\0'; | ||
| 81 | if ( value[0] == '"' ) value++; | ||
| 82 | |||
| 83 | /* "trim" param */ | ||
| 84 | while ((param[0] == ' ')||(param[0] == '\t')) | ||
| 85 | param++; | ||
| 86 | bytes = strlen(param); | ||
| 87 | while ((param[bytes-1] == ' ')||(param[bytes-1] == '\t')) { | ||
| 88 | param[bytes-1] = '\0'; | ||
| 89 | bytes=strlen(param); | ||
| 90 | } | ||
| 91 | /* bytes should be strlen(param) */ | ||
| 92 | if ( param[bytes-1] == '\"' ) param[bytes-1] = '\0'; | ||
| 93 | if ( param[0] == '\"' ) param++; | ||
| 94 | |||
| 95 | if ((!param)||(!value)) return; /* failsave */ | ||
| 96 | |||
| 97 | //fprintf(stderr,"\"%s\" -> \"%s\"\n",param,value); | ||
| 98 | setnoption(param,value); | ||
| 99 | } | ||
| 100 | |||
| 101 | static void parseformats(unsigned char *line) { | ||
| 102 | int i; | ||
| 103 | unsigned char *tmp = NULL; | ||
| 104 | |||
| 105 | /* read a format line from file, syntax is | ||
| 106 | FS_XXX = "formatstring" | ||
| 107 | */ | ||
| 108 | |||
| 109 | while( *line == ' ') line++; | ||
| 110 | |||
| 111 | if( *line != '#') /* allow to comment out the line */ | ||
| 112 | for (i = 0; formatstrings[i].formatstr; i++) | ||
| 113 | if (!strncasecmp(formatstrings[i].idstring, line, strlen( formatstrings[i].idstring) )) | ||
| 114 | { | ||
| 115 | unsigned char *tail = line + strlen( formatstrings[i].idstring); | ||
| 116 | while( *tail==' ' || *tail=='\t') tail++; /* and skip whitespaces */ | ||
| 117 | |||
| 118 | if( *tail++ == '=' ) | ||
| 119 | { | ||
| 120 | while( *tail==' ' || *tail=='\t') tail++; | ||
| 121 | if( *(tail++)=='\"' ) | ||
| 122 | { | ||
| 123 | int j, k = 0, stringends = 0, backslash=0; | ||
| 124 | for ( j = 0; tail[j] && !stringends; j++) | ||
| 125 | { | ||
| 126 | switch( tail[j] ) { | ||
| 127 | case '^': | ||
| 128 | if ( tail[j+1] != '^' ) | ||
| 129 | tmpstr[k++] = 1; | ||
| 130 | break; | ||
| 131 | case '\\': | ||
| 132 | backslash=1-backslash; | ||
| 133 | tmpstr[k++] = '\\'; | ||
| 134 | break; | ||
| 135 | case '\"': | ||
| 136 | if (backslash) k--; else stringends = 1; | ||
| 137 | default: | ||
| 138 | tmpstr[k++] = tail[j]; | ||
| 139 | backslash = 0; | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | if ( stringends && ( (tmp = (unsigned char *)malloc( 1 + j )) != NULL ) ) | ||
| 144 | { | ||
| 145 | memcpy( tmp, tmpstr, k); | ||
| 146 | tmp[k-1]=0; | ||
| 147 | formatstrings[i].formatstr = tmp; | ||
| 148 | } | ||
| 149 | } | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | } | ||
| 154 | |||
| 155 | /* UNUSED uncomment if needed | ||
| 156 | static void parseknownhosts(unsigned char *line) { | ||
| 157 | } | ||
| 158 | */ | ||
| 159 | |||
| 160 | /* load config file */ | ||
| 161 | static void | ||
| 162 | loadcfg (unsigned char *file,void (*lineparser) (unsigned char *)) | ||
| 163 | { | ||
| 164 | int fd; | ||
| 165 | int bytes,bufoff=0; | ||
| 166 | unsigned char *tmp = NULL; | ||
| 167 | #define BUFSIZE 4096 | ||
| 168 | unsigned char buf[BUFSIZE]; /* data buffer */ | ||
| 169 | unsigned char *ltmp = buf; | ||
| 170 | unsigned char *tildex = NULL; | ||
| 171 | buf[BUFSIZE-1] = '\0'; /* sanity stop */ | ||
| 172 | |||
| 173 | if (!file) return; | ||
| 174 | if (!file[0]) return; | ||
| 175 | if (file[0] == '~') | ||
| 176 | tildex = tilde_expand(file); | ||
| 177 | else | ||
| 178 | tildex = file; | ||
| 179 | fd = open(tildex,O_RDONLY); | ||
| 180 | if (fd == -1) { | ||
| 181 | snprintf (errstr, TMPSTRSIZE, "Can't open config-file \"%s\": %s.", tildex, sys_errlist[errno]); | ||
| 182 | } else { | ||
| 183 | while ((bytes = read(fd,&buf[bufoff],BUFSIZE-bufoff-1))) { | ||
| 184 | if (bytes < 0) { | ||
| 185 | close(fd); | ||
| 186 | return; | ||
| 187 | } else { | ||
| 188 | /* terminate string */ | ||
| 189 | buf[bytes + bufoff] = '\0'; | ||
| 190 | /* as long as there are lines .. */ | ||
| 191 | while ((tmp = strchr (ltmp, '\n')) != NULL) { | ||
| 192 | /* did the server send CR+LF instead of LF with the last line? */ | ||
| 193 | if (tmp[-1] == '\r') | ||
| 194 | tmp[-1] = '\0'; | ||
| 195 | |||
| 196 | /* remove newline from previous message, advance pointer of next | ||
| 197 | * message */ | ||
| 198 | tmp[0] = '\0'; | ||
| 199 | tmp++; | ||
| 200 | |||
| 201 | /* we have a last message? give away to line handler! */ | ||
| 202 | if (ltmp[0]) | ||
| 203 | { | ||
| 204 | lineparser(ltmp); | ||
| 205 | } | ||
| 206 | |||
| 207 | /* move line along .. */ | ||
| 208 | ltmp = tmp; | ||
| 209 | } | ||
| 210 | /* buffer exhausted, move partial line to start of buffer and go | ||
| 211 | * on .. */ | ||
| 212 | bufoff = (bytes+bufoff) - (ltmp-buf); | ||
| 213 | if (bufoff > 0) | ||
| 214 | memmove (buf, ltmp, bufoff); | ||
| 215 | else | ||
| 216 | bufoff = 0; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | close(fd); | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | void | ||
| 224 | loadconfig (unsigned char *file) | ||
| 225 | { | ||
| 226 | loadcfg(file,parsecfg); | ||
| 227 | } | ||
| 228 | |||
| 229 | void | ||
| 230 | loadformats (unsigned char *file) | ||
| 231 | { | ||
| 232 | loadcfg(file,parseformats); | ||
| 233 | } | ||
| 234 | |||
| 235 | /* get-format-string */ | ||
| 236 | unsigned char * | ||
| 237 | getformatstr (formtstr id) | ||
| 238 | { | ||
| 239 | int i; | ||
| 240 | for (i = 0; formatstrings[i].formatstr; i++) | ||
| 241 | if (formatstrings[i].id == id) return formatstrings[i].formatstr; | ||
| 242 | return NULL; | ||
| 243 | } | ||
| 244 | |||
| 245 | /* get-string-option, fetches *char-value of variable named by option */ | ||
| 246 | unsigned char * | ||
| 247 | getstroption (confopt option) | ||
| 248 | { | ||
| 249 | int i; | ||
| 250 | #ifdef DEBUG | ||
| 251 | fprintf(stderr,"getstroption: %d\n",option); | ||
| 252 | #endif | ||
| 253 | for (i = 0; configoptions[i].type != CO_NIL; i++) | ||
| 254 | if ((configoptions[i].id == option) && (configoptions[i].type == CO_STR)) { | ||
| 255 | if (!configoptions[i].value) | ||
| 256 | return configoptions[i].defaultvalue; | ||
| 257 | else | ||
| 258 | return configoptions[i].value; | ||
| 259 | } | ||
| 260 | return NULL; | ||
| 261 | } | ||
| 262 | |||
| 263 | /* set-string-option, puts *char-value to variable named by option */ | ||
| 264 | void | ||
| 265 | setstroption (confopt option, unsigned char *string) | ||
| 266 | { | ||
| 267 | int i; | ||
| 268 | #ifdef DEBUG | ||
| 269 | fprintf(stderr,"setstroption: %d to %s\n",option,string); | ||
| 270 | #endif | ||
| 271 | for (i = 0; configoptions[i].type != CO_NIL; i++) | ||
| 272 | if ((configoptions[i].id == option) && (configoptions[i].type == CO_STR)) { | ||
| 273 | if (configoptions[i].value) | ||
| 274 | free(configoptions[i].value); | ||
| 275 | if (string) | ||
| 276 | configoptions[i].value = strdup(string); | ||
| 277 | else | ||
| 278 | configoptions[i].value = NULL; | ||
| 279 | if (configoptions[i].localvar) | ||
| 280 | *configoptions[i].localvar = configoptions[i].value; | ||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | /* set-named-option, puts string to variable named by name */ | ||
| 285 | void | ||
| 286 | setnoption (unsigned char *name, unsigned char *string) | ||
| 287 | { | ||
| 288 | int i; | ||
| 289 | #ifdef DEBUG | ||
| 290 | fprintf(stderr,"setstrnoption: %s to %s\n",name,string); | ||
| 291 | #endif | ||
| 292 | for (i = 0; configoptions[i].type != CO_NIL; i++) | ||
| 293 | if (!strcmp(configoptions[i].varname,name)) { | ||
| 294 | if (configoptions[i].type == CO_STR) { | ||
| 295 | if (configoptions[i].value) | ||
| 296 | free(configoptions[i].value); | ||
| 297 | if (string) | ||
| 298 | configoptions[i].value = strdup(string); | ||
| 299 | else | ||
| 300 | configoptions[i].value = NULL; | ||
| 301 | } else if (configoptions[i].type == CO_INT) { | ||
| 302 | configoptions[i].value = (char *) atoi(string); | ||
| 303 | } | ||
| 304 | if (configoptions[i].localvar) | ||
| 305 | *configoptions[i].localvar = configoptions[i].value; | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | /* get-integer-option, fetches int-value of variable named by option */ | ||
| 310 | int | ||
| 311 | getintoption (confopt option) | ||
| 312 | { | ||
| 313 | int i; | ||
| 314 | #ifdef DEBUG | ||
| 315 | fprintf(stderr,"getintoption: %d\n",option); | ||
| 316 | #endif | ||
| 317 | for (i = 0; configoptions[i].type != CO_NIL; i++) | ||
| 318 | if ((configoptions[i].id == option) && (configoptions[i].type == CO_INT)) { | ||
| 319 | if ((int)configoptions[i].value == -1) | ||
| 320 | return (int) configoptions[i].defaultvalue; | ||
| 321 | else | ||
| 322 | return (int) configoptions[i].value; | ||
| 323 | } | ||
| 324 | return 0; | ||
| 325 | } | ||
| 326 | |||
| 327 | /* set-integer-option, puts int-value to variable named by option */ | ||
| 328 | void | ||
| 329 | setintoption (confopt option, int value) | ||
| 330 | { | ||
| 331 | int i; | ||
| 332 | #ifdef DEBUG | ||
| 333 | fprintf(stderr,"setintoption: %d to %d\n",option,value); | ||
| 334 | #endif | ||
| 335 | for (i = 0; configoptions[i].type != CO_NIL; i++) | ||
| 336 | if ((configoptions[i].id == option) && (configoptions[i].type == CO_INT)) { | ||
| 337 | configoptions[i].value = (char *) value; | ||
| 338 | if (configoptions[i].localvar) | ||
| 339 | *configoptions[i].localvar = configoptions[i].value; | ||
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | int quitrequest = 0; | ||
| 344 | |||
| 345 | /* cleanup-hook, for SIGINT */ | ||
| 346 | void | ||
| 347 | cleanup (int signal) | ||
| 348 | { | ||
| 349 | if( signal == SIGINT ) { | ||
| 350 | switch( quitrequest >> 2 ) { | ||
| 351 | case 0: | ||
| 352 | flushout( ); | ||
| 353 | writeout( " Press Ctrl+C twice now to confirm "); | ||
| 354 | showout( ); | ||
| 355 | quitrequest+=4; | ||
| 356 | return; | ||
| 357 | break; | ||
| 358 | case 1: | ||
| 359 | flushout( ); | ||
| 360 | writeout( " Press Ctrl+C twice now to confirm "); | ||
| 361 | writeout( " Press Ctrl+C once now to confirm "); | ||
| 362 | showout( ); | ||
| 363 | quitrequest+=4; | ||
| 364 | return; | ||
| 365 | break; | ||
| 366 | default: | ||
| 367 | break; | ||
| 368 | } | ||
| 369 | } | ||
| 370 | /* restore terminal state */ | ||
| 371 | exitui (); | ||
| 372 | /* clear userlist */ | ||
| 373 | ul_clear (); | ||
| 374 | /* close server connection */ | ||
| 375 | if (serverfd > 0) | ||
| 376 | close (serverfd); | ||
| 377 | /* inform user if we where killed by signal */ | ||
| 378 | if (signal > 1) | ||
| 379 | { | ||
| 380 | fprintf (stderr, "vchat-client: terminated with signal %d.\n", signal); | ||
| 381 | } else if (errstr[0]) | ||
| 382 | fprintf (stderr, errstr); | ||
| 383 | /* end of story */ | ||
| 384 | exit (0); | ||
| 385 | } | ||
| 386 | |||
| 387 | void calleverysecond( void ) { | ||
| 388 | /* timetriggered execution, don't rely on being called every 1000us */ | ||
| 389 | /* rather see it as a chance for being called 9 times in 10 seconds */ | ||
| 390 | /* so check time() */ | ||
| 391 | |||
| 392 | if(quitrequest) | ||
| 393 | quitrequest--; | ||
| 394 | if(outputcountdown && !--outputcountdown) | ||
| 395 | hideout( ); | ||
| 396 | } | ||
| 397 | |||
| 398 | /* this function is called in the master loop */ | ||
| 399 | void | ||
| 400 | eventloop (void) | ||
| 401 | { | ||
| 402 | /* get fresh copy of filedescriptor list */ | ||
| 403 | fd_set readfds = masterfds; | ||
| 404 | struct timeval tv = { 1, 0}; | ||
| 405 | |||
| 406 | switch (select (serverfd + 1, &readfds, NULL, NULL, &tv)) | ||
| 407 | { | ||
| 408 | case -1: | ||
| 409 | /* EINTR is most likely a SIGWINCH - ignore for now */ | ||
| 410 | if (errno != EINTR) | ||
| 411 | { | ||
| 412 | snprintf (tmpstr, TMPSTRSIZE, "Select fails, %s.", sys_errlist[errno]); | ||
| 413 | strncpy(errstr,tmpstr,TMPSTRSIZE-2); | ||
| 414 | errstr[TMPSTRSIZE-2] = '\0'; | ||
| 415 | strcat(errstr,"\n"); | ||
| 416 | writecf (FS_ERR,tmpstr); | ||
| 417 | /* see this as an error condition and bail out */ | ||
| 418 | status = 0; | ||
| 419 | } | ||
| 420 | break; | ||
| 421 | case 0: | ||
| 422 | /* time out reached */ | ||
| 423 | calleverysecond(); | ||
| 424 | break; | ||
| 425 | default: | ||
| 426 | /* something to read from user & we're logged in or have a cert? */ | ||
| 427 | if (FD_ISSET (0, &readfds) && loggedin) | ||
| 428 | userinput (); | ||
| 429 | |||
| 430 | /* something to read from server? */ | ||
| 431 | if (FD_ISSET (serverfd, &readfds)) | ||
| 432 | networkinput (); | ||
| 433 | break; | ||
| 434 | } | ||
| 435 | } | ||
| 436 | |||
| 437 | void usage(unsigned char *name) { | ||
| 438 | printf("usage: %s [-C config-file] [-l] [-z] [-s host] [-p port] [-c channel] [-n nickname]\n",name); | ||
| 439 | printf(" -C load a second config-file, overriding the first one\n"); | ||
| 440 | printf(" -l local connect (no SSL + connects localhost:2323)\n"); | ||
| 441 | printf(" -z don't use certificate files\n"); | ||
| 442 | printf(" -s set server (default \"%s\")\n",getstroption(CF_SERVERHOST)); | ||
| 443 | printf(" -p set port (default %d)\n",getintoption(CF_SERVERPORT)); | ||
| 444 | printf(" -c set channel (default %d)\n",getintoption(CF_CHANNEL)); | ||
| 445 | if (nick) | ||
| 446 | printf(" -n set nickname (default \"%s\")\n",nick); | ||
| 447 | else | ||
| 448 | printf(" -n set nickname\n"); | ||
| 449 | printf(" -f set from (default \"%s\")\n",getstroption(CF_FROM)); | ||
| 450 | printf(" -h gives this help\n"); | ||
| 451 | } | ||
| 452 | |||
| 453 | /* main - d'oh */ | ||
| 454 | int | ||
| 455 | main (int argc, char **argv) | ||
| 456 | { | ||
| 457 | int pchar; | ||
| 458 | int cmdsunparsed = 1; | ||
| 459 | |||
| 460 | loadconfig (GLOBAL_CONFIG_FILE); | ||
| 461 | loadconfig (getstroption (CF_CONFIGFILE)); | ||
| 462 | loadformats(GLOBAL_FORMAT_FILE); | ||
| 463 | loadformats(getstroption (CF_FORMFILE)); | ||
| 464 | |||
| 465 | /* parse commandline */ | ||
| 466 | while (cmdsunparsed) { | ||
| 467 | pchar = getopt(argc,argv,"C:lzs:p:c:n:f:h"); | ||
| 468 | #ifdef DEBUG | ||
| 469 | fprintf(stderr,"parse commandline: %d ('%c'): %s\n",pchar,pchar,optarg); | ||
| 470 | #endif | ||
| 471 | |||
| 472 | switch (pchar) { | ||
| 473 | case -1 : cmdsunparsed = 0; break; | ||
| 474 | case 'C': loadconfig(optarg); break; | ||
| 475 | case 'l': setintoption(CF_USESSL,0); break; | ||
| 476 | case 'z': setintoption(CF_USECERT,0); break; | ||
| 477 | case 's': setstroption(CF_SERVERHOST,optarg); break; | ||
| 478 | case 'p': setintoption(CF_SERVERPORT,strtol(optarg,NULL,10)); break; | ||
| 479 | case 'c': setintoption(CF_CHANNEL,strtol(optarg,NULL,10)); break; | ||
| 480 | case 'n': setstroption(CF_NICK,optarg); break; | ||
| 481 | case 'f': setstroption(CF_FROM,optarg); break; | ||
| 482 | case 'h': usage(argv[0]); exit(0); break; | ||
| 483 | default : usage(argv[0]); exit(1); | ||
| 484 | } | ||
| 485 | } | ||
| 486 | |||
| 487 | if (optind < argc) { usage(argv[0]); exit(1); } | ||
| 488 | |||
| 489 | if (!getintoption(CF_USESSL)) { | ||
| 490 | setstroption(CF_SERVERHOST,"localhost"); | ||
| 491 | setintoption(CF_SERVERPORT,2323); | ||
| 492 | } else { | ||
| 493 | SSL_library_init (); | ||
| 494 | SSL_load_error_strings (); | ||
| 495 | } | ||
| 496 | |||
| 497 | |||
| 498 | /* install signal handler */ | ||
| 499 | signal (SIGINT, cleanup); | ||
| 500 | signal (SIGHUP, cleanup); | ||
| 501 | signal (SIGTERM, cleanup); | ||
| 502 | signal (SIGQUIT, cleanup); | ||
| 503 | |||
| 504 | /* initialize userinterface */ | ||
| 505 | initui (); | ||
| 506 | |||
| 507 | /* attempt connection */ | ||
| 508 | if (!vcconnect (getstroption(CF_SERVERHOST), getintoption(CF_SERVERPORT))) | ||
| 509 | { | ||
| 510 | snprintf (tmpstr, TMPSTRSIZE, "Could not connect to server, %s.", | ||
| 511 | sys_errlist[errno]); | ||
| 512 | strncpy(errstr,tmpstr,TMPSTRSIZE-2); | ||
| 513 | errstr[TMPSTRSIZE-2] = '\0'; | ||
| 514 | strcat(errstr,"\n"); | ||
| 515 | writecf (FS_ERR,tmpstr); | ||
| 516 | /* exit condition */ | ||
| 517 | status = 0; | ||
| 518 | } | ||
| 519 | else | ||
| 520 | { | ||
| 521 | /* add stdin & server to masterdfs */ | ||
| 522 | FD_ZERO (&masterfds); | ||
| 523 | FD_SET (0, &masterfds); | ||
| 524 | FD_SET (serverfd, &masterfds); | ||
| 525 | } | ||
| 526 | |||
| 527 | while (status) | ||
| 528 | eventloop (); | ||
| 529 | |||
| 530 | /* sanely close connection to server */ | ||
| 531 | vcdisconnect (); | ||
| 532 | |||
| 533 | /* call cleanup-hook without signal */ | ||
| 534 | cleanup (0); | ||
| 535 | return 0; | ||
| 536 | } | ||
