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