summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xvchat-client.c586
-rwxr-xr-xvchat-commands.c519
-rw-r--r--vchat-connection.c133
-rw-r--r--vchat-connection.h10
-rwxr-xr-xvchat-protocol.c556
-rwxr-xr-xvchat-tls.c1036
-rwxr-xr-xvchat-tls.h16
-rwxr-xr-xvchat-ui.c1945
-rwxr-xr-xvchat-user.c399
-rwxr-xr-xvchat.h217
10 files changed, 2816 insertions, 2601 deletions
diff --git a/vchat-client.c b/vchat-client.c
index e1fb8fc..c094376 100755
--- a/vchat-client.c
+++ b/vchat-client.c
@@ -15,25 +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-connection.h"
33#include "vchat-user.h" 33#include "vchat-user.h"
34#include "vchat.h"
34 35
35/* version of this module */ 36/* version of this module */
36const char *vchat_cl_version = "vchat-client.c $Id$"; 37const char *vchat_cl_version =
38 "vchat-client.c $Id$";
37 39
38/* externally used variables */ 40/* externally used variables */
39/* we're logged in */ 41/* we're logged in */
@@ -54,139 +56,149 @@ char errstr[ERRSTRSIZE] = "\0";
54/* declaration of configuration array */ 56/* declaration of configuration array */
55#include "vchat-config.h" 57#include "vchat-config.h"
56 58
57void setnoption (const char *, char *); 59void setnoption(const char *, char *);
58 60
59static void parsecfg(char *line) { 61static void parsecfg(char *line) {
60 int bytes; 62 int bytes;
61 char *param=line; 63 char *param = line;
62 char *value=NULL; 64 char *value = NULL;
63 65
64 /* handle quotes value is empty, so we can use it */ 66 /* handle quotes value is empty, so we can use it */
65 value = strchr(line,'#'); 67 value = strchr(line, '#');
66 if (value) { /* the line contains a cute little quote */ 68 if (value) { /* the line contains a cute little quote */
67 value[0]='\0'; /* ignore the rest of the line */ 69 value[0] = '\0'; /* ignore the rest of the line */
68 } 70 }
69 71
70 /* now split the line into two parts */ 72 /* now split the line into two parts */
71 value = strchr(line,'='); 73 value = strchr(line, '=');
72 if (!value) return; /* exit if strchr fails */ 74 if (!value)
73 value[0]='\0'; 75 return; /* exit if strchr fails */
76 value[0] = '\0';
74 value++; 77 value++;
75 78
76 /* "trim" values */ 79 /* "trim" values */
77 while ((value[0] == ' ')||(value[0] == '\t')) 80 while ((value[0] == ' ') || (value[0] == '\t'))
78 value++; 81 value++;
79 bytes = strlen(value); 82 bytes = strlen(value);
80 while ((value[bytes-1] == ' ')||(value[bytes-1] == '\t')) { 83 while ((value[bytes - 1] == ' ') || (value[bytes - 1] == '\t')) {
81 value[bytes-1] = '\0'; 84 value[bytes - 1] = '\0';
82 bytes=strlen(value); 85 bytes = strlen(value);
83 } 86 }
84 /* bytes should be strlen(value) */ 87 /* bytes should be strlen(value) */
85 if ( value[bytes-1] == '"' ) value[bytes-1] = '\0'; 88 if (value[bytes - 1] == '"')
86 if ( value[0] == '"' ) value++; 89 value[bytes - 1] = '\0';
90 if (value[0] == '"')
91 value++;
87 92
88 /* "trim" param */ 93 /* "trim" param */
89 while ((param[0] == ' ')||(param[0] == '\t')) 94 while ((param[0] == ' ') || (param[0] == '\t'))
90 param++; 95 param++;
91 bytes = strlen(param); 96 bytes = strlen(param);
92 while ((param[bytes-1] == ' ')||(param[bytes-1] == '\t')) { 97 while ((param[bytes - 1] == ' ') || (param[bytes - 1] == '\t')) {
93 param[bytes-1] = '\0'; 98 param[bytes - 1] = '\0';
94 bytes=strlen(param); 99 bytes = strlen(param);
95 } 100 }
96 /* bytes should be strlen(param) */ 101 /* bytes should be strlen(param) */
97 if ( param[bytes-1] == '\"' ) param[bytes-1] = '\0'; 102 if (param[bytes - 1] == '\"')
98 if ( param[0] == '\"' ) param++; 103 param[bytes - 1] = '\0';
104 if (param[0] == '\"')
105 param++;
99 106
100 if ((!param)||(!value)) return; /* failsave */ 107 if ((!param) || (!value))
108 return; /* failsave */
101 109
102 //fprintf(stderr,"\"%s\" -> \"%s\"\n",param,value); 110 // fprintf(stderr,"\"%s\" -> \"%s\"\n",param,value);
103 setnoption(param,value); 111 setnoption(param, value);
104} 112}
105 113
106static void parseformats(char *line) { 114static void parseformats(char *line) {
107 int i; 115 int i;
108 char *tmp = NULL; 116 char *tmp = NULL;
109 117
110 /* read a format line from file, syntax is 118 /* read a format line from file, syntax is
111 FS_XXX = "formatstring" 119 FS_XXX = "formatstring"
112 */ 120 */
113 121
114 while( *line == ' ') line++; 122 while (*line == ' ')
115 123 line++;
116 if( strlen( line ) > TMPSTRSIZE ) return; 124
117 125 if (strlen(line) > TMPSTRSIZE)
118 if( *line != '#') /* allow to comment out the line */ 126 return;
119 for (i = 0; formatstrings[i].formatstr; i++) 127
120 if (!strncasecmp(formatstrings[i].idstring, line, strlen( formatstrings[i].idstring) )) 128 if (*line != '#') /* allow to comment out the line */
121 { 129 for (i = 0; formatstrings[i].formatstr; i++)
122 char *tail = line + strlen( formatstrings[i].idstring); 130 if (!strncasecmp(formatstrings[i].idstring, line,
123 while( *tail==' ' || *tail=='\t') tail++; /* and skip whitespaces */ 131 strlen(formatstrings[i].idstring))) {
124 132 char *tail = line + strlen(formatstrings[i].idstring);
125 if( *tail++ == '=' ) 133 while (*tail == ' ' || *tail == '\t')
126 { 134 tail++; /* and skip whitespaces */
127 while( *tail==' ' || *tail=='\t') tail++; 135
128 if( *(tail++)=='\"' ) 136 if (*tail++ == '=') {
129 { 137 while (*tail == ' ' || *tail == '\t')
130 int j, k = 0, stringends = 0, backslash=0; 138 tail++;
131 for ( j = 0; tail[j] && !stringends; j++) 139 if (*(tail++) == '\"') {
132 { 140 int j, k = 0, stringends = 0, backslash = 0;
133 switch( tail[j] ) { 141 for (j = 0; tail[j] && !stringends; j++) {
134 case '^': 142 switch (tail[j]) {
135 if ( tail[j+1] != '^' ) 143 case '^':
136 tmpstr[k++] = 1; 144 if (tail[j + 1] != '^')
137 break; 145 tmpstr[k++] = 1;
138 case '\\': 146 break;
139 backslash=1-backslash; 147 case '\\':
140 tmpstr[k++] = '\\'; 148 backslash = 1 - backslash;
141 break; 149 tmpstr[k++] = '\\';
142 case '\"': 150 break;
143 if (backslash) k--; else stringends = 1; 151 case '\"':
144 default: 152 if (backslash)
145 tmpstr[k++] = tail[j]; 153 k--;
146 backslash = 0; 154 else
147 } 155 stringends = 1;
148 } 156 default:
149 157 tmpstr[k++] = tail[j];
150 if ( stringends && ( (tmp = (char *)malloc( 1 + j )) != NULL ) ) 158 backslash = 0;
151 {
152 memcpy( tmp, tmpstr, k);
153 tmp[k-1]=0;
154 formatstrings[i].formatstr = tmp;
155 }
156 }
157 } 159 }
158 } 160 }
159 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 }
160} 170}
161 171
162/* UNUSED uncomment if needed 172/* UNUSED uncomment if needed
163static void parseknownhosts(char *line) { 173static void parseknownhosts(char *line) {
164} 174}
165*/ 175*/
166 176
167/* load config file */ 177/* load config file */
168void 178void loadcfg(char *file, int complain, void (*lineparser)(char *)) {
169loadcfg (char *file,int complain, void (*lineparser) (char *))
170{
171 FILE *fh; 179 FILE *fh;
172#define BUFSIZE 4096 180#define BUFSIZE 4096
173 char buf[BUFSIZE]; /* data buffer */ 181 char buf[BUFSIZE]; /* data buffer */
174 char *tildex = NULL, *t; 182 char *tildex = NULL, *t;
175 183
176 /* Check and expand filename then open file */ 184 /* Check and expand filename then open file */
177 if (!file) return; 185 if (!file)
178 tildex = tilde_expand( file ); 186 return;
179 if (!tildex) return; 187 tildex = tilde_expand(file);
180 fh = fopen( tildex, "r" ); 188 if (!tildex)
181 free( tildex ); 189 return;
190 fh = fopen(tildex, "r");
191 free(tildex);
182 192
183 if (!fh) { 193 if (!fh) {
184 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));
185 return; 197 return;
186 } 198 }
187 199
188 while ( fgets( buf, sizeof(buf), fh ) ) { 200 while (fgets(buf, sizeof(buf), fh)) {
189 if( ( t = strchr( buf, '\n' ) ) ) 201 if ((t = strchr(buf, '\n')))
190 *t = 0; 202 *t = 0;
191 lineparser(buf); 203 lineparser(buf);
192 } 204 }
@@ -194,77 +206,62 @@ loadcfg (char *file,int complain, void (*lineparser) (char *))
194 fclose(fh); 206 fclose(fh);
195} 207}
196 208
197void 209void loadconfig(char *file) { loadcfg(file, 1, parsecfg); }
198loadconfig (char *file)
199{
200 loadcfg(file,1,parsecfg);
201}
202 210
203void 211void loadformats(char *file) { loadcfg(file, 0, parseformats); }
204loadformats (char *file)
205{
206 loadcfg(file,0,parseformats);
207}
208 212
209/* get-format-string */ 213/* get-format-string */
210char * 214char *getformatstr(formtstr id) {
211getformatstr (formtstr id)
212{
213 int i; 215 int i;
214 for (i = 0; formatstrings[i].formatstr; i++) 216 for (i = 0; formatstrings[i].formatstr; i++)
215 if (formatstrings[i].id == id) return formatstrings[i].formatstr; 217 if (formatstrings[i].id == id)
218 return formatstrings[i].formatstr;
216 return NULL; 219 return NULL;
217} 220}
218 221
219/* get-string-option, fetches *char-value of variable named by option */ 222/* get-string-option, fetches *char-value of variable named by option */
220char * 223char *getstroption(confopt option) {
221getstroption (confopt option)
222{
223 int i; 224 int i;
224#ifdef DEBUG 225#ifdef DEBUG
225 fprintf(stderr,"getstroption: %d\n",option); 226 fprintf(stderr, "getstroption: %d\n", option);
226#endif 227#endif
227 for (i = 0; configoptions[i].type != CO_NIL; i++) 228 for (i = 0; configoptions[i].type != CO_NIL; i++)
228 if ((configoptions[i].id == option) && (configoptions[i].type == CO_STR)) { 229 if ((configoptions[i].id == option) && (configoptions[i].type == CO_STR)) {
229 if (!configoptions[i].value) 230 if (!configoptions[i].value)
230 return configoptions[i].defaultvalue; 231 return configoptions[i].defaultvalue;
231 else 232 else
232 return configoptions[i].value; 233 return configoptions[i].value;
233 } 234 }
234 return NULL; 235 return NULL;
235} 236}
236 237
237/* set-string-option, puts *char-value to variable named by option */ 238/* set-string-option, puts *char-value to variable named by option */
238void 239void setstroption(confopt option, char *string) {
239setstroption (confopt option, char *string)
240{
241 int i; 240 int i;
242#ifdef DEBUG 241#ifdef DEBUG
243 fprintf(stderr,"setstroption: %d to %s\n",option,string); 242 fprintf(stderr, "setstroption: %d to %s\n", option, string);
244#endif 243#endif
245 for (i = 0; configoptions[i].type != CO_NIL; i++) 244 for (i = 0; configoptions[i].type != CO_NIL; i++)
246 if ((configoptions[i].id == option) && (configoptions[i].type == CO_STR)) { 245 if ((configoptions[i].id == option) && (configoptions[i].type == CO_STR)) {
247 if (configoptions[i].value) 246 if (configoptions[i].value)
248 free(configoptions[i].value); 247 free(configoptions[i].value);
249 if (string) 248 if (string)
250 configoptions[i].value = strdup(string); 249 configoptions[i].value = strdup(string);
251 else 250 else
252 configoptions[i].value = NULL; 251 configoptions[i].value = NULL;
253 if (configoptions[i].localvar.pstr) 252 if (configoptions[i].localvar.pstr)
254 *configoptions[i].localvar.pstr = configoptions[i].value; 253 *configoptions[i].localvar.pstr = configoptions[i].value;
255 } 254 }
256} 255}
257 256
258/* set-named-option, puts string to variable named by name */ 257/* set-named-option, puts string to variable named by name */
259void 258void setnoption(const char *name, char *string) {
260setnoption (const char *name, char *string)
261{
262 int i; 259 int i;
263#ifdef DEBUG 260#ifdef DEBUG
264 fprintf(stderr,"setstrnoption: %s to %s\n",name,string); 261 fprintf(stderr, "setstrnoption: %s to %s\n", name, string);
265#endif 262#endif
266 for (i = 0; configoptions[i].type != CO_NIL; i++) 263 for (i = 0; configoptions[i].type != CO_NIL; i++)
267 if (!strcmp(configoptions[i].varname,name)) { 264 if (!strcmp(configoptions[i].varname, name)) {
268 if (configoptions[i].type == CO_STR) { 265 if (configoptions[i].type == CO_STR) {
269 if (configoptions[i].value) 266 if (configoptions[i].value)
270 free(configoptions[i].value); 267 free(configoptions[i].value);
@@ -273,265 +270,288 @@ setnoption (const char *name, char *string)
273 else 270 else
274 configoptions[i].value = NULL; 271 configoptions[i].value = NULL;
275 if (configoptions[i].localvar.pstr) 272 if (configoptions[i].localvar.pstr)
276 *configoptions[i].localvar.pstr = configoptions[i].value; 273 *configoptions[i].localvar.pstr = configoptions[i].value;
277 } else if (configoptions[i].type == CO_INT) { 274 } else if (configoptions[i].type == CO_INT) {
278 configoptions[i].value = (char *)(uintptr_t)atoi(string); 275 configoptions[i].value = (char *)(uintptr_t)atoi(string);
279 if (configoptions[i].localvar.pint) 276 if (configoptions[i].localvar.pint)
280 *configoptions[i].localvar.pint = (uintptr_t)configoptions[i].value; 277 *configoptions[i].localvar.pint = (uintptr_t)configoptions[i].value;
281 } 278 }
282 } 279 }
283} 280}
284 281
285/* get-integer-option, fetches int-value of variable named by option */ 282/* get-integer-option, fetches int-value of variable named by option */
286int 283int getintoption(confopt option) {
287getintoption (confopt option)
288{
289 int i; 284 int i;
290#ifdef DEBUG 285#ifdef DEBUG
291 fprintf(stderr,"getintoption: %d\n",option); 286 fprintf(stderr, "getintoption: %d\n", option);
292#endif 287#endif
293 for (i = 0; configoptions[i].type != CO_NIL; i++) 288 for (i = 0; configoptions[i].type != CO_NIL; i++)
294 if ((configoptions[i].id == option) && (configoptions[i].type == CO_INT)) { 289 if ((configoptions[i].id == option) && (configoptions[i].type == CO_INT)) {
295 if ((intptr_t)configoptions[i].value == -1) 290 if ((intptr_t)configoptions[i].value == -1)
296 return (intptr_t) configoptions[i].defaultvalue; 291 return (intptr_t)configoptions[i].defaultvalue;
297 else 292 else
298 return (intptr_t) configoptions[i].value; 293 return (intptr_t)configoptions[i].value;
299 } 294 }
300 return 0; 295 return 0;
301} 296}
302 297
303/* set-integer-option, puts int-value to variable named by option */ 298/* set-integer-option, puts int-value to variable named by option */
304void 299void setintoption(confopt option, int value) {
305setintoption (confopt option, int value)
306{
307 int i; 300 int i;
308#ifdef DEBUG 301#ifdef DEBUG
309 fprintf(stderr,"setintoption: %d to %d\n",option,value); 302 fprintf(stderr, "setintoption: %d to %d\n", option, value);
310#endif 303#endif
311 for (i = 0; configoptions[i].type != CO_NIL; i++) 304 for (i = 0; configoptions[i].type != CO_NIL; i++)
312 if ((configoptions[i].id == option) && (configoptions[i].type == CO_INT)) { 305 if ((configoptions[i].id == option) && (configoptions[i].type == CO_INT)) {
313 configoptions[i].value = (char *)(uintptr_t)value; 306 configoptions[i].value = (char *)(uintptr_t)value;
314 if (configoptions[i].localvar.pint) 307 if (configoptions[i].localvar.pint)
315 *configoptions[i].localvar.pint = (uintptr_t)configoptions[i].value; 308 *configoptions[i].localvar.pint = (uintptr_t)configoptions[i].value;
316 } 309 }
317} 310}
318 311
319int quitrequest = 0; 312int quitrequest = 0;
320 313
321/* cleanup-hook, for SIGINT */ 314/* cleanup-hook, for SIGINT */
322void 315void cleanup(int signal) {
323cleanup (int signal) 316 if (signal == SIGINT) {
324{ 317 switch (quitrequest >> 2) {
325 if( signal == SIGINT ) { 318 case 0:
326 switch( quitrequest >> 2 ) { 319 flushout();
327 case 0: 320 writeout(" Press Ctrl+C twice now to confirm ");
328 flushout( ); 321 showout();
329 writeout( " Press Ctrl+C twice now to confirm "); 322 quitrequest += 4;
330 showout( ); 323 return;
331 quitrequest+=4; 324 break;
332 return; 325 case 1:
333 break; 326 flushout();
334 case 1: 327 writeout(" Press Ctrl+C twice now to confirm ");
335 flushout( ); 328 writeout(" Press Ctrl+C once now to confirm ");
336 writeout( " Press Ctrl+C twice now to confirm "); 329 showout();
337 writeout( " Press Ctrl+C once now to confirm "); 330 quitrequest += 4;
338 showout( ); 331 return;
339 quitrequest+=4; 332 break;
340 return; 333 default:
341 break; 334 break;
342 default: 335 }
343 break;
344 }
345 } 336 }
346 /* restore terminal state */ 337 /* restore terminal state */
347 exitui (); 338 exitui();
348 /* clear userlist */ 339 /* clear userlist */
349 ul_clear (); 340 ul_clear();
350 vc_disconnect(); 341 vc_disconnect();
351 342
352 /* inform user if we where killed by signal */ 343 /* inform user if we where killed by signal */
353 if (signal > 1) 344 if (signal > 1) {
354 { 345 fprintf(stderr, "vchat-client: terminated with signal %d.\n", signal);
355 fprintf (stderr, "vchat-client: terminated with signal %d.\n", signal); 346 } else if (errstr[0])
356 } else if (errstr[0]) 347 fputs(errstr, stderr);
357 fputs (errstr, stderr);
358 /* end of story */ 348 /* end of story */
359 exit (0); 349 exit(0);
360} 350}
361 351
362static int oldseconds = 0; 352static int oldseconds = 0;
363 353
364void calleverysecond( void ) { 354void calleverysecond(void) {
365 /* timetriggered execution, don't rely on being called every 1000us */ 355 /* timetriggered execution, don't rely on being called every 1000us */
366 /* rather see it as a chance for being called 9 times in 10 seconds */ 356 /* rather see it as a chance for being called 9 times in 10 seconds */
367 /* so check time() */ 357 /* so check time() */
368 time_t now = time( NULL ); 358 time_t now = time(NULL);
369 struct tm *mytime = localtime( &now ); 359 struct tm *mytime = localtime(&now);
370 if( mytime->tm_sec < oldseconds ) { 360 if (mytime->tm_sec < oldseconds) {
371 consoleline( NULL ); 361 consoleline(NULL);
372 } 362 }
373 oldseconds = mytime->tm_sec; 363 oldseconds = mytime->tm_sec;
374 364
375 if(quitrequest) 365 if (quitrequest)
376 quitrequest--; 366 quitrequest--;
377 if(outputcountdown && !--outputcountdown) 367 if (outputcountdown && !--outputcountdown)
378 hideout( ); 368 hideout();
379 if( reconnect_time && ( time( NULL ) > reconnect_time ) ) 369 if (reconnect_time && (time(NULL) > reconnect_time))
380 status = 0; 370 status = 0;
381} 371}
382 372
383/* this function is called in the master loop */ 373/* this function is called in the master loop */
384void 374void eventloop(void) {
385eventloop (void) 375 int poll_result = vc_poll(1 /* second timeout */);
386{
387 int poll_result = vc_poll( 1 /* second timeout */ );
388 376
389 switch (poll_result) { 377 switch (poll_result) {
390 case -1: 378 case -1:
391 /* EINTR is most likely a SIGWINCH - ignore for now */ 379 /* EINTR is most likely a SIGWINCH - ignore for now */
392 if (errno != EINTR) 380 if (errno != EINTR) {
393 { 381 snprintf(tmpstr, TMPSTRSIZE, "Select fails, %s.", strerror(errno));
394 snprintf (tmpstr, TMPSTRSIZE, "Select fails, %s.", strerror(errno)); 382 strncpy(errstr, tmpstr, TMPSTRSIZE - 2);
395 strncpy(errstr,tmpstr,TMPSTRSIZE-2); 383 errstr[TMPSTRSIZE - 2] = '\0';
396 errstr[TMPSTRSIZE-2] = '\0'; 384 strcat(errstr, "\n");
397 strcat(errstr,"\n"); 385 writecf(FS_ERR, tmpstr);
398 writecf (FS_ERR,tmpstr); 386 /* see this as an error condition and bail out */
399 /* see this as an error condition and bail out */ 387 status = 0;
400 status = 0; 388 }
401 } 389 break;
402 break;
403 case 0: 390 case 0:
404 /* time out reached */ 391 /* time out reached */
405 calleverysecond(); 392 calleverysecond();
406 break; 393 break;
407 default: 394 default:
408 /* something to read from user & we're logged in or have a cert? */ 395 /* something to read from user & we're logged in or have a cert? */
409 if (poll_result & 1) 396 if (poll_result & 1)
410 userinput (); 397 userinput();
411 398
412 /* something to read from server? */ 399 /* something to read from server? */
413 if (poll_result & 2) 400 if (poll_result & 2)
414 vc_receive (); 401 vc_receive();
415 break; 402 break;
416 } 403 }
417} 404}
418 405
419void usage( char *name) { 406void usage(char *name) {
420 printf ("usage: %s [-C config-file] [-F formats] [-l] [-z] [-s host] [-p port] [-c channel] [-n nickname]\n",name); 407 printf("usage: %s [-C config-file] [-F formats] [-l] [-z] [-s host] [-p "
421 puts (" -C load a second config-file, overriding the first one"); 408 "port] [-c channel] [-n nickname]\n",
422 puts (" -F load format strings (skins) from this file"); 409 name);
423 puts (" -l local connect (no SSL)"); 410 puts(" -C load a second config-file, overriding the first one");
424 puts (" -z don't use certificate files"); 411 puts(" -F load format strings (skins) from this file");
425 printf (" -s set server (default \"%s\")\n",getstroption(CF_SERVERHOST)); 412 puts(" -l local connect (no SSL)");
426 printf (" -p set port (default %s)\n",getstroption(CF_SERVERPORT)); 413 puts(" -z don't use certificate files");
427 printf (" -c set channel (default %d)\n",getintoption(CF_CHANNEL)); 414 printf(" -s set server (default \"%s\")\n", getstroption(CF_SERVERHOST));
428 if (own_nick_get()) 415 printf(" -p set port (default %s)\n", getstroption(CF_SERVERPORT));
429 printf(" -n set nickname (default \"%s\")\n",own_nick_get()); 416 printf(" -c set channel (default %d)\n", getintoption(CF_CHANNEL));
430 else 417 if (own_nick_get())
431 puts (" -n set nickname"); 418 printf(" -n set nickname (default \"%s\")\n", own_nick_get());
432 printf (" -f set from (default \"%s\")\n",getstroption(CF_FROM)); 419 else
433 puts (" -h gives this help"); 420 puts(" -n set nickname");
434 puts (" -v show module versions"); 421 printf(" -f set from (default \"%s\")\n", getstroption(CF_FROM));
422 puts(" -h gives this help");
423 puts(" -v show module versions");
435} 424}
436 425
437void versions() { 426void versions() {
438 puts (vchat_cl_version); 427 puts(vchat_cl_version);
439 puts (vchat_ui_version); 428 puts(vchat_ui_version);
440 puts (vchat_io_version); 429 puts(vchat_io_version);
441 puts (vchat_us_version); 430 puts(vchat_us_version);
442 puts (vchat_cm_version); 431 puts(vchat_cm_version);
443 puts (vchat_tls_version); 432 puts(vchat_tls_version);
444 puts (vchat_tls_version_external); 433 puts(vchat_tls_version_external);
445} 434}
446 435
447/* main - d'oh */ 436/* main - d'oh */
448int 437int main(int argc, char **argv) {
449main (int argc, char **argv)
450{
451 int pchar; 438 int pchar;
452 int cmdsunparsed = 1; 439 int cmdsunparsed = 1;
453 440
454 setlocale(LC_ALL,""); 441 setlocale(LC_ALL, "");
455 442
456 loadconfig (GLOBAL_CONFIG_FILE); 443 loadconfig(GLOBAL_CONFIG_FILE);
457 loadconfig (getstroption (CF_CONFIGFILE)); 444 loadconfig(getstroption(CF_CONFIGFILE));
458 445
459 /* make SSL version used visible */ 446 /* make SSL version used visible */
460 vchat_tls_get_version_external(); 447 vchat_tls_get_version_external();
461 448
462 /* parse commandline */ 449 /* parse commandline */
463 while (cmdsunparsed) { 450 while (cmdsunparsed) {
464 pchar = getopt(argc,argv,"C:F:lzs:p:c:n:f:kKL:hv"); 451 pchar = getopt(argc, argv, "C:F:lzs:p:c:n:f:kKL:hv");
465#ifdef DEBUG 452#ifdef DEBUG
466 fprintf(stderr,"parse commandline: %d ('%c'): %s\n",pchar,pchar,optarg); 453 fprintf(stderr, "parse commandline: %d ('%c'): %s\n", pchar, pchar, optarg);
467#endif 454#endif
468 455
469 switch (pchar) { 456 switch (pchar) {
470 case -1 : cmdsunparsed = 0; break; 457 case -1:
471 case 'C': loadconfig(optarg); break; 458 cmdsunparsed = 0;
472 case 'F': setstroption(CF_FORMFILE,optarg); break; 459 break;
473 case 'l': setintoption(CF_USESSL,0); break; 460 case 'C':
474 case 'z': setintoption(CF_USECERT,0); break; 461 loadconfig(optarg);
475 case 's': setstroption(CF_SERVERHOST,optarg); break; 462 break;
476 case 'p': setstroption(CF_SERVERPORT,optarg); break; 463 case 'F':
477 case 'c': setintoption(CF_CHANNEL,strtol(optarg,NULL,10)); break; 464 setstroption(CF_FORMFILE, optarg);
478 case 'n': own_nick_set(optarg); break; 465 break;
479 case 'f': setstroption(CF_FROM,optarg); break; 466 case 'l':
480 case 'h': usage(argv[0]); exit(0); break; 467 setintoption(CF_USESSL, 0);
481 case 'v': versions(); exit(0); break; 468 break;
482 default : usage(argv[0]); exit(1); 469 case 'z':
483 } 470 setintoption(CF_USECERT, 0);
471 break;
472 case 's':
473 setstroption(CF_SERVERHOST, optarg);
474 break;
475 case 'p':
476 setstroption(CF_SERVERPORT, optarg);
477 break;
478 case 'c':
479 setintoption(CF_CHANNEL, strtol(optarg, NULL, 10));
480 break;
481 case 'n':
482 own_nick_set(optarg);
483 break;
484 case 'f':
485 setstroption(CF_FROM, optarg);
486 break;
487 case 'h':
488 usage(argv[0]);
489 exit(0);
490 break;
491 case 'v':
492 versions();
493 exit(0);
494 break;
495 default:
496 usage(argv[0]);
497 exit(1);
498 }
484 } 499 }
485 500
486 if (optind < argc) { usage(argv[0]); exit(1); } 501 if (optind < argc) {
502 usage(argv[0]);
503 exit(1);
504 }
487 505
488 loadformats(GLOBAL_FORMAT_FILE); 506 loadformats(GLOBAL_FORMAT_FILE);
489 loadformats(getstroption (CF_FORMFILE)); 507 loadformats(getstroption(CF_FORMFILE));
490 508
491 /* install signal handler */ 509 /* install signal handler */
492 signal (SIGINT, cleanup); 510 signal(SIGINT, cleanup);
493 signal (SIGHUP, cleanup); 511 signal(SIGHUP, cleanup);
494 signal (SIGTERM, cleanup); 512 signal(SIGTERM, cleanup);
495 signal (SIGQUIT, SIG_IGN); 513 signal(SIGQUIT, SIG_IGN);
496 514
497 /* initialize userinterface */ 515 /* initialize userinterface */
498 initui (); 516 initui();
499 517
500 while( status ) { 518 while (status) {
501 /* attempt connection */ 519 /* attempt connection */
502 if (vc_connect (getstroption(CF_SERVERHOST), getstroption(CF_SERVERPORT))) { 520 if (vc_connect(getstroption(CF_SERVERHOST), getstroption(CF_SERVERPORT))) {
503 snprintf (tmpstr, TMPSTRSIZE, "Could not connect to server, %s.", strerror(errno)); 521 snprintf(tmpstr, TMPSTRSIZE, "Could not connect to server, %s.",
504 strncpy(errstr,tmpstr,TMPSTRSIZE-2); 522 strerror(errno));
505 errstr[TMPSTRSIZE-2] = '\0'; 523 strncpy(errstr, tmpstr, TMPSTRSIZE - 2);
506 strcat(errstr,"\n"); 524 errstr[TMPSTRSIZE - 2] = '\0';
507 writecf (FS_ERR,tmpstr); 525 strcat(errstr, "\n");
508 526 writecf(FS_ERR, tmpstr);
509 if( getintoption( CF_AUTORECONN ) ) { 527
510 snprintf (tmpstr, TMPSTRSIZE, "reconnecting in %d seconds", reconnect_delay ); 528 if (getintoption(CF_AUTORECONN)) {
511 writecf (FS_ERR, tmpstr); 529 snprintf(tmpstr, TMPSTRSIZE, "reconnecting in %d seconds",
512 reconnect_delay = ( reconnect_delay * 15 ) / 10; 530 reconnect_delay);
513 reconnect_time = time( NULL ) + reconnect_delay; 531 writecf(FS_ERR, tmpstr);
532 reconnect_delay = (reconnect_delay * 15) / 10;
533 reconnect_time = time(NULL) + reconnect_delay;
514 } else 534 } else
515 status = 0; 535 status = 0;
516 } else { 536 } else {
517 /* reset reconnect delay */ 537 /* reset reconnect delay */
518 reconnect_delay = 6; 538 reconnect_delay = 6;
519 reconnect_time = 0; 539 reconnect_time = 0;
520 } 540 }
521 541
522 while (status) 542 while (status)
523 eventloop (); 543 eventloop();
524 544
525 /* sanely close connection to server */ 545 /* sanely close connection to server */
526 vc_disconnect (); 546 vc_disconnect();
527 547
528 if( !ownquit && ( getintoption( CF_AUTORECONN ) || wantreconnect ) ) 548 if (!ownquit && (getintoption(CF_AUTORECONN) || wantreconnect))
529 status = 1; 549 status = 1;
530 550
531 wantreconnect = 0; 551 wantreconnect = 0;
532 } 552 }
533 553
534 /* call cleanup-hook without signal */ 554 /* call cleanup-hook without signal */
535 cleanup (0); 555 cleanup(0);
536 return 0; 556 return 0;
537} 557}
diff --git a/vchat-commands.c b/vchat-commands.c
index 8094a7c..9aa3abd 100755
--- a/vchat-commands.c
+++ b/vchat-commands.c
@@ -10,27 +10,29 @@
10 * without even the implied warranty of merchantability or fitness for a 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 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 12 * any direct, indirect, incidental or special damages arising in any way out
13 * of the use of this software. 13 * of the use of this software.
14 * 14 *
15 */ 15 */
16 16
17/* general includes */ 17/* general includes */
18#include <stdlib.h>
19#include <unistd.h>
20#include <errno.h> 18#include <errno.h>
21#include <stdio.h> 19#include <stdio.h>
20#include <stdlib.h>
22#include <string.h> 21#include <string.h>
23#include <sys/stat.h> 22#include <sys/stat.h>
23#include <unistd.h>
24
24#include <readline/readline.h> 25#include <readline/readline.h>
25 26
26/* local includes */ 27/* local includes */
27#include "vchat.h"
28#include "vchat-connection.h" 28#include "vchat-connection.h"
29#include "vchat-help.h" 29#include "vchat-help.h"
30#include "vchat-user.h" 30#include "vchat-user.h"
31#include "vchat.h"
31 32
32/* version of this module */ 33/* version of this module */
33const char *vchat_cm_version = "vchat-commands.c $Id$"; 34const char *vchat_cm_version =
35 "vchat-commands.c $Id$";
34 36
35/* from vchat-client.c */ 37/* from vchat-client.c */
36extern int ownquit; 38extern int ownquit;
@@ -39,45 +41,45 @@ extern int status;
39 41
40/* our "/command " table */ 42/* our "/command " table */
41enum { 43enum {
42COMMAND_VERSION, 44 COMMAND_VERSION,
43COMMAND_FILTERS, 45 COMMAND_FILTERS,
44COMMAND_LSFLT, 46 COMMAND_LSFLT,
45COMMAND_RMFLT, 47 COMMAND_RMFLT,
46COMMAND_CLFLT, 48 COMMAND_CLFLT,
47COMMAND_HELP, 49 COMMAND_HELP,
48COMMAND_FORMAT, 50 COMMAND_FORMAT,
49COMMAND_KEYS, 51 COMMAND_KEYS,
50COMMAND_QUIT, 52 COMMAND_QUIT,
51COMMAND_USER, 53 COMMAND_USER,
52COMMAND_DICT, 54 COMMAND_DICT,
53COMMAND_FLT, 55 COMMAND_FLT,
54COMMAND_PM, 56 COMMAND_PM,
55COMMAND_ACTION, 57 COMMAND_ACTION,
56COMMAND_PMSHORT, 58 COMMAND_PMSHORT,
57COMMAND_QUERY, 59 COMMAND_QUERY,
58COMMAND_QUITSHORT, 60 COMMAND_QUITSHORT,
59COMMAND_PLAIN, 61 COMMAND_PLAIN,
60COMMAND_RECONNECT, 62 COMMAND_RECONNECT,
61COMMAND_NONE 63 COMMAND_NONE
62}; 64};
63 65
64static void command_quit ( char *tail); 66static void command_quit(char *tail);
65static void command_user ( char *tail); 67static void command_user(char *tail);
66static void command_pm ( char *tail); 68static void command_pm(char *tail);
67static void command_action ( char *tail); 69static void command_action(char *tail);
68static void command_help ( char *tail); 70static void command_help(char *tail);
69static void command_format ( char *tail); 71static void command_format(char *tail);
70static void command_flt ( char *tail); 72static void command_flt(char *tail);
71static void command_lsflt ( char *tail); 73static void command_lsflt(char *tail);
72static void command_clflt ( char *tail); 74static void command_clflt(char *tail);
73static void command_rmflt ( char *tail); 75static void command_rmflt(char *tail);
74 void command_version ( char *tail); 76void command_version(char *tail);
75static void command_none ( char *line); 77static void command_none(char *line);
76static void command_query ( char *tail); 78static void command_query(char *tail);
77static void command_reconnect ( char *tail); 79static void command_reconnect(char *tail);
78static void command_dict ( char *tail); 80static void command_dict(char *tail);
79 81
80static void output_default ( char *tail); 82static void output_default(char *tail);
81 83
82/* commandentry defined in vchat.h */ 84/* commandentry defined in vchat.h */
83 85
@@ -106,9 +108,7 @@ commandtable[] = {
106}; 108};
107 109
108/* parse "/command" */ 110/* parse "/command" */
109static int 111static int translatecommand(char **cmd) {
110translatecommand( char **cmd)
111{
112 int result; 112 int result;
113 int cut = 0; 113 int cut = 0;
114 int maxcut = 0; 114 int maxcut = 0;
@@ -116,214 +116,215 @@ translatecommand( char **cmd)
116 /* We do only want to allow Command abbrevation to 116 /* We do only want to allow Command abbrevation to
117 the next newline, so that /VRES won't expand to /V RES */ 117 the next newline, so that /VRES won't expand to /V RES */
118 118
119 while( (*cmd)[maxcut] && ((*cmd)[maxcut] != 0x20) && ((*cmd)[maxcut] != '\n')) maxcut++; 119 while ((*cmd)[maxcut] && ((*cmd)[maxcut] != 0x20) && ((*cmd)[maxcut] != '\n'))
120 if( maxcut ) maxcut--; 120 maxcut++;
121 if (maxcut)
122 maxcut--;
121 123
122 /* Repeatedly scan command table for command, with growing abbrevation cut off */ 124 /* Repeatedly scan command table for command, with growing abbrevation cut off
125 */
123 do { 126 do {
124 /* Looks ugly, needs rewrite for better understanding */ 127 /* Looks ugly, needs rewrite for better understanding */
125 for( result = 0; 128 for (result = 0;
126 (result != COMMAND_NONE) && 129 (result != COMMAND_NONE) &&
127 (strncasecmp(*cmd, commandtable[result].name, commandtable[result].len - 130 (strncasecmp(
128 ((commandtable[result].len - maxcut - cut > 0) ? cut : 0))); 131 *cmd, commandtable[result].name,
129 result++); 132 commandtable[result].len -
130 } while ((cut < commandtable[0].len) && (commandtable[result].number == COMMAND_NONE) && (++cut)); 133 ((commandtable[result].len - maxcut - cut > 0) ? cut : 0)));
134 result++)
135 ;
136 } while ((cut < commandtable[0].len) &&
137 (commandtable[result].number == COMMAND_NONE) && (++cut));
131 138
132 /* Just leave the tail... */ 139 /* Just leave the tail... */
133 (*cmd) += commandtable[result].len; 140 (*cmd) += commandtable[result].len;
134 141
135 /* ... whose start may be affected by abbrevation */ 142 /* ... whose start may be affected by abbrevation */
136 if( commandtable[result].number != COMMAND_NONE ) 143 if (commandtable[result].number != COMMAND_NONE)
137 (*cmd) -= cut; 144 (*cmd) -= cut;
138 145
139 return result; 146 return result;
140} 147}
141 148
142/* handle thought */ 149/* handle thought */
143static void 150static void dothink(const char *tail, const char nice) {
144dothink(const char *tail, const char nice ) 151 while (*tail == ' ')
145{ 152 tail++;
146 while( *tail == ' ' ) tail++;
147 153
148 /* send users message to server */ 154 /* send users message to server */
149 snprintf (tmpstr, TMPSTRSIZE, ".%c %s", nice, tail); 155 snprintf(tmpstr, TMPSTRSIZE, ".%c %s", nice, tail);
150 vc_sendmessage (tmpstr); 156 vc_sendmessage(tmpstr);
151 157
152 /* show action in channel window */ 158 /* show action in channel window */
153 snprintf (tmpstr, TMPSTRSIZE, nice == 'O' ? getformatstr(FS_TXPUBNTHOUGHT) : getformatstr(FS_TXPUBTHOUGHT), tail); 159 snprintf(tmpstr, TMPSTRSIZE,
154 writechan (tmpstr); 160 nice == 'O' ? getformatstr(FS_TXPUBNTHOUGHT)
161 : getformatstr(FS_TXPUBTHOUGHT),
162 tail);
163 writechan(tmpstr);
155} 164}
156 165
157
158/* handle action */ 166/* handle action */
159static void 167static void doaction(const char *tail) {
160doaction(const char *tail ) 168 while (*tail == ' ')
161{ 169 tail++;
162 while( *tail == ' ' ) tail++; 170
163 171 if (*tail) {
164 if( *tail ) { 172 /* send users message to server */
165 /* send users message to server */ 173 snprintf(tmpstr, TMPSTRSIZE, ".a %s", tail);
166 snprintf (tmpstr, TMPSTRSIZE, ".a %s", tail); 174 vc_sendmessage(tmpstr);
167 vc_sendmessage (tmpstr); 175
168 176 /* show action in channel window */
169 /* show action in channel window */ 177 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_TXPUBACTION), own_nick_get(),
170 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_TXPUBACTION), own_nick_get(), tail); 178 tail);
171 writechan (tmpstr); 179 writechan(tmpstr);
172 } else { 180 } else {
173 /* missing action */ 181 /* missing action */
174 msgout( " You do nothing. " ); 182 msgout(" You do nothing. ");
175 } 183 }
176} 184}
177 185
178/* handle private message outgoing */ 186/* handle private message outgoing */
179static void 187static void privatemessagetx(char *tail) {
180privatemessagetx (char *tail ) {
181 char *mesg; 188 char *mesg;
182 189
183 /* find nick */ 190 /* find nick */
184 while( *tail==' ') tail++; 191 while (*tail == ' ')
192 tail++;
185 193
186 /* find message */ 194 /* find message */
187 mesg = tail; 195 mesg = tail;
188 while ( *mesg && *mesg!=' ') mesg++; 196 while (*mesg && *mesg != ' ')
197 mesg++;
189 198
190 /* check for nick && message */ 199 /* check for nick && message */
191 if(*tail && *mesg) { 200 if (*tail && *mesg) {
192 201
193 /* terminate nick, move to rel start */ 202 /* terminate nick, move to rel start */
194 *mesg++ = '\0'; 203 *mesg++ = '\0';
195 204
196 /* form message and send to server */ 205 /* form message and send to server */
197 snprintf (tmpstr, TMPSTRSIZE, ".m %s %s", tail, mesg); 206 snprintf(tmpstr, TMPSTRSIZE, ".m %s %s", tail, mesg);
198 vc_sendmessage (tmpstr); 207 vc_sendmessage(tmpstr);
199 208
200 /* show message in private window */ 209 /* show message in private window */
201 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_TXPRIVMSG), tail, mesg); 210 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_TXPRIVMSG), tail, mesg);
202 writepriv (tmpstr, 0); 211 writepriv(tmpstr, 0);
203 212
204 /* note we messaged someone */ 213 /* note we messaged someone */
205 ul_private_action(tail); 214 ul_private_action(tail);
206 215
207 } else { 216 } else {
208 /* Bump user to fill in missing parts */ 217 /* Bump user to fill in missing parts */
209 msgout( *tail ? " Won't send empty message. ":" Recipient missing. " ); 218 msgout(*tail ? " Won't send empty message. " : " Recipient missing. ");
210 } 219 }
211} 220}
212 221
213/* handle line entered by user */ 222/* handle line entered by user */
214void 223void handleline(char *line) {
215handleline (char *line)
216{
217#ifdef DEBUG 224#ifdef DEBUG
218 /* debugging? log users input! */ 225 /* debugging? log users input! */
219 fprintf (stderr, "=| %s\n", line); 226 fprintf(stderr, "=| %s\n", line);
220#endif 227#endif
221 228
222 switch ( line[0] ) 229 switch (line[0]) {
223 {
224 case '.': 230 case '.':
225 switch ( line[1] ) { 231 switch (line[1]) {
226 case 'm': /* sending a private message? */ 232 case 'm': /* sending a private message? */
227 privatemessagetx( line+2 ); 233 privatemessagetx(line + 2);
228 break; 234 break;
229 case 'a': /* Do an action */ 235 case 'a': /* Do an action */
230 doaction( line+2 ); 236 doaction(line + 2);
231 break; 237 break;
232 case '.': 238 case '.':
233 /* .. on start of line is public */ 239 /* .. on start of line is public */
234 if( line[2] != 'm' ) { 240 if (line[2] != 'm') {
235 output_default( line ); 241 output_default(line);
236 } else { 242 } else {
237 /* oopsi, "..m " detected */ 243 /* oopsi, "..m " detected */
238 /* dunno what to do */ 244 /* dunno what to do */
239 flushout( ); 245 flushout();
240 writeout("? You probably misstyped ?"); 246 writeout("? You probably misstyped ?");
241 writeout(" "); 247 writeout(" ");
242 writeout(line ); 248 writeout(line);
243 showout( ); 249 showout();
244 }
245 break;
246 case 'o':
247 case 'O':
248 dothink( line + 2, line[1] );
249 break;
250 case 'x':
251 /* inform vchat-client, that the following connection
252 drop was intentional */
253 ownquit = 1; /* fallthrough intended */
254 default:
255 /* generic server command, send to server, show to user */
256 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_COMMAND), line);
257 writechan (tmpstr);
258 vc_sendmessage (line);
259 break;
260 } 250 }
261 break; 251 break;
262 case '/': 252 case 'o':
263 line++; 253 case 'O':
264 commandtable[translatecommand(&line)].handler(line); 254 dothink(line + 2, line[1]);
265 break; 255 break;
266 default: 256 case 'x':
267 output_default( line ); 257 /* inform vchat-client, that the following connection
258 drop was intentional */
259 ownquit = 1; /* fallthrough intended */
260 default:
261 /* generic server command, send to server, show to user */
262 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_COMMAND), line);
263 writechan(tmpstr);
264 vc_sendmessage(line);
268 break; 265 break;
266 }
267 break;
268 case '/':
269 line++;
270 commandtable[translatecommand(&line)].handler(line);
271 break;
272 default:
273 output_default(line);
274 break;
269 } 275 }
270} 276}
271 277
272static void 278static void output_default(char *line) {
273output_default(char *line ) { 279 /* prepare for output on display */
274 /* prepare for output on display */ 280 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_TXPUBMSG), own_nick_get(), line);
275 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_TXPUBMSG), own_nick_get(), line);
276 281
277 /* send original line to server */ 282 /* send original line to server */
278 vc_sendmessage (line); 283 vc_sendmessage(line);
279 284
280 /* output message to channel window */ 285 /* output message to channel window */
281 writechan (tmpstr); 286 writechan(tmpstr);
282} 287}
283 288
284/* handle a "/user " request */ 289/* handle a "/user " request */
285static void 290static void command_user(char *tail) {
286command_user(char *tail) 291 while (*tail == ' ')
287{ 292 tail++;
288 while( *tail == ' ') tail++; 293 if (*tail) {
289 if( *tail ) { 294 char *out = ul_match_user(tail);
290 char * out = ul_match_user( tail); 295 if (*out) {
291 if( *out ) { 296 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_USMATCH), tail, out);
292 snprintf( tmpstr, TMPSTRSIZE, getformatstr(FS_USMATCH), tail, out); 297 } else {
293 } else { 298 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_ERR),
294 snprintf( tmpstr, TMPSTRSIZE, getformatstr(FS_ERR), " No user matched that regex. "); 299 " No user matched that regex. ");
295 } 300 }
296 } else { 301 } else {
297 snprintf( tmpstr, TMPSTRSIZE, getformatstr(FS_ERR), " Which user? "); 302 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_ERR), " Which user? ");
298 } 303 }
299 msgout( tmpstr ); 304 msgout(tmpstr);
300} 305}
301 306
302/* handle a "/msg " request */ 307/* handle a "/msg " request */
303static void 308static void command_pm(char *tail) { privatemessagetx(tail); }
304command_pm (char *tail)
305{
306 privatemessagetx( tail );
307}
308 309
309static void 310static void command_format(char *line) {
310command_format(char *line) {
311 struct stat testexist; 311 struct stat testexist;
312 char * tildex = NULL; 312 char *tildex = NULL;
313 313
314 flushout(); 314 flushout();
315 while( *line==' ') line++; 315 while (*line == ' ')
316 if(line) { 316 line++;
317 tildex = tilde_expand( line ); 317 if (line) {
318 if(tildex && !stat(tildex, &testexist )) 318 tildex = tilde_expand(line);
319 if (tildex && !stat(tildex, &testexist))
319 loadformats(tildex); 320 loadformats(tildex);
320 else { 321 else {
321#define BUFSIZE 4096 322#define BUFSIZE 4096
322 char buf[BUFSIZE]; 323 char buf[BUFSIZE];
323 snprintf( buf, BUFSIZE, "~/.vchat/sample-%s.fmt", line ); 324 snprintf(buf, BUFSIZE, "~/.vchat/sample-%s.fmt", line);
324 free(tildex); 325 free(tildex);
325 tildex = tilde_expand( line ); 326 tildex = tilde_expand(line);
326 if(tildex && !stat(tildex, &testexist )) 327 if (tildex && !stat(tildex, &testexist))
327 loadformats(tildex); 328 loadformats(tildex);
328 } 329 }
329 writeout(" Sort of done. "); 330 writeout(" Sort of done. ");
@@ -335,92 +336,87 @@ command_format(char *line) {
335} 336}
336 337
337/* handle a help request */ 338/* handle a help request */
338static void 339static void command_help(char *line) {
339command_help (char *line) { 340 flushout();
340 flushout( ); 341 while (*line == ' ')
341 while( *line==' ') line++; 342 line++;
342 if( *line ) { /* Get help on command */ 343 if (*line) { /* Get help on command */
343 int i; 344 int i;
344 if( ( i = translatecommand( &line ) ) != COMMAND_NONE ) { 345 if ((i = translatecommand(&line)) != COMMAND_NONE) {
345 snprintf( tmpstr, TMPSTRSIZE, "Help on command: %s", commandtable[i].name); 346 snprintf(tmpstr, TMPSTRSIZE, "Help on command: %s", commandtable[i].name);
346 writeout( tmpstr ); 347 writeout(tmpstr);
347 writeout(" "); 348 writeout(" ");
348 if( commandtable[i].short_help && !commandtable[i].help ) 349 if (commandtable[i].short_help && !commandtable[i].help)
349 writeout(commandtable[i].short_help ); 350 writeout(commandtable[i].short_help);
350 line = commandtable[i].help; 351 line = commandtable[i].help;
351 if( line ) { 352 if (line) {
352 while( *line ) { 353 while (*line) {
353 char *tmp = tmpstr; 354 char *tmp = tmpstr;
354 while( *line && (*line != '\n') ) 355 while (*line && (*line != '\n'))
355 *tmp++ = *line++; 356 *tmp++ = *line++;
356 *tmp = '\0'; if( *line == '\n') line++; 357 *tmp = '\0';
357 writeout ( tmpstr ); 358 if (*line == '\n')
358 } 359 line++;
359 } 360 writeout(tmpstr);
360 } else { 361 }
361 command_help( " " );
362 }
363 } else { /* Get overall help */
364 int i;
365 for( i = 0; commandtable[i].number != COMMAND_NONE; i++ ) {
366 if( commandtable[i].short_help )
367 writeout( commandtable[i].short_help );
368 } 362 }
363 } else {
364 command_help(" ");
365 }
366 } else { /* Get overall help */
367 int i;
368 for (i = 0; commandtable[i].number != COMMAND_NONE; i++) {
369 if (commandtable[i].short_help)
370 writeout(commandtable[i].short_help);
371 }
369 } 372 }
370 showout(); 373 showout();
371} 374}
372 375
373/* handle an unknown command */ 376/* handle an unknown command */
374static void 377static void command_none(char *line) {
375command_none(char *line) { 378 snprintf(tmpstr, TMPSTRSIZE, " Unknown client command: %s ", line);
376 snprintf(tmpstr, TMPSTRSIZE, " Unknown client command: %s ", line); 379 msgout(tmpstr);
377 msgout(tmpstr);
378} 380}
379 381
380/* handle a "/flt " request */ 382/* handle a "/flt " request */
381static void 383static void command_flt(char *tail) {
382command_flt(char *tail){
383 char colour; 384 char colour;
384 while(*tail==' ') tail++; 385 while (*tail == ' ')
386 tail++;
385 colour = *tail++; 387 colour = *tail++;
386 while( colour && *tail == ' ') tail++; 388 while (colour && *tail == ' ')
387 if( colour && *tail) { 389 tail++;
388 addfilter( colour, tail); 390 if (colour && *tail) {
391 addfilter(colour, tail);
389 } 392 }
390} 393}
391 394
392/* handle a "/clflt " request */ 395/* handle a "/clflt " request */
393static void 396static void command_clflt(char *tail) {
394command_clflt (char *tail) { 397 while (*tail == ' ')
395 while( *tail == ' ') tail++; 398 tail++;
396 clearfilters( *tail ); 399 clearfilters(*tail);
397} 400}
398 401
399/* handle a "/rmflt " request */ 402/* handle a "/rmflt " request */
400static void 403static void command_rmflt(char *tail) {
401command_rmflt (char *tail) { 404 while (*tail == ' ')
402 while( *tail == ' ') tail++; 405 tail++;
403 removefilter( tail ); 406 removefilter(tail);
404} 407}
405 408
406/* list filters */ 409/* list filters */
407static void 410static void command_lsflt(char *tail) {
408command_lsflt (char *tail) {
409 (void)tail; 411 (void)tail;
410 listfilters(); 412 listfilters();
411} 413}
412 414
413/* handle a "/me " action */ 415/* handle a "/me " action */
414static void 416static void command_action(char *tail) { doaction(tail); }
415command_action(char *tail)
416{
417 doaction(tail);
418}
419 417
420/* handle a "/reconnect" request */ 418/* handle a "/reconnect" request */
421static void 419static void command_reconnect(char *tail) {
422command_reconnect(char *tail)
423{
424 (void)tail; 420 (void)tail;
425 status = 0; 421 status = 0;
426 wantreconnect = 1; 422 wantreconnect = 1;
@@ -428,15 +424,13 @@ command_reconnect(char *tail)
428} 424}
429 425
430/* handle a "/quit " exit */ 426/* handle a "/quit " exit */
431static void 427static void command_quit(char *tail) {
432command_quit(char *tail)
433{
434 /* send users message to server */ 428 /* send users message to server */
435 snprintf (tmpstr, TMPSTRSIZE, ".x %s", tail); 429 snprintf(tmpstr, TMPSTRSIZE, ".x %s", tail);
436 vc_sendmessage (tmpstr); 430 vc_sendmessage(tmpstr);
437 431
438 /* show action in channel window */ 432 /* show action in channel window */
439 writechan (tmpstr); 433 writechan(tmpstr);
440 434
441 /* Inform vchat-client, that the closing connection 435 /* Inform vchat-client, that the closing connection
442 following is intended */ 436 following is intended */
@@ -445,42 +439,35 @@ command_quit(char *tail)
445} 439}
446 440
447/* print out version */ 441/* print out version */
448void 442void command_version(char *tail) {
449command_version(char *tail)
450{
451 (void)tail; 443 (void)tail;
452 /* output internal versions of all modules */ 444 /* output internal versions of all modules */
453 flushout(); 445 flushout();
454 writeout (vchat_cl_version); 446 writeout(vchat_cl_version);
455 writeout (vchat_ui_version); 447 writeout(vchat_ui_version);
456 writeout (vchat_io_version); 448 writeout(vchat_io_version);
457 writeout (vchat_us_version); 449 writeout(vchat_us_version);
458 writeout (vchat_cm_version); 450 writeout(vchat_cm_version);
459 writeout (vchat_tls_version); 451 writeout(vchat_tls_version);
460 writeout (vchat_tls_version_external); 452 writeout(vchat_tls_version_external);
461 showout(); 453 showout();
462} 454}
463 455
464/* start or end a query */ 456/* start or end a query */
465void 457void command_query(char *tail) {
466command_query(char *tail)
467{
468 char *msg; 458 char *msg;
469 while( *tail == ' ') tail++; 459 while (*tail == ' ')
460 tail++;
470 461
471 // Check, if a message is to be sent in first query 462 // Check, if a message is to be sent in first query
472 // Note: this is safe, since readline chops trailing spaces 463 // Note: this is safe, since readline chops trailing spaces
473 if((msg = strchr(tail, ' '))) { 464 if ((msg = strchr(tail, ' '))) {
474 privatemessagetx( tail ); 465 privatemessagetx(tail);
475 *msg = 0; 466 *msg = 0;
476 } 467 }
477 468
478 // Do the ui stuff for query 469 // Do the ui stuff for query
479 handlequery( tail ); 470 handlequery(tail);
480} 471}
481 472
482void 473void command_dict(char *tail) { ul_add_to_dict(tail); }
483command_dict(char *tail)
484{
485 ul_add_to_dict(tail);
486}
diff --git a/vchat-connection.c b/vchat-connection.c
index 5ab4dd4..01cf2c2 100644
--- a/vchat-connection.c
+++ b/vchat-connection.c
@@ -10,27 +10,27 @@
10 * without even the implied warranty of merchantability or fitness for a 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 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 12 * any direct, indirect, incidental or special damages arising in any way out
13 * of the use of this software. 13 * of the use of this software.
14 * 14 *
15 */ 15 */
16 16
17#include <stdlib.h> 17#include <errno.h>
18#include <netdb.h>
19#include <netinet/in.h>
18#include <stddef.h> 20#include <stddef.h>
19#include <string.h>
20#include <stdio.h> 21#include <stdio.h>
21#include <unistd.h> 22#include <stdlib.h>
22#include <netdb.h> 23#include <string.h>
23#include <errno.h>
24#include <sys/types.h>
25#include <sys/socket.h> 24#include <sys/socket.h>
26#include <netinet/in.h> 25#include <sys/types.h>
26#include <unistd.h>
27 27
28/* For tilde_expand */ 28/* For tilde_expand */
29#include <readline/readline.h> 29#include <readline/readline.h>
30 30
31#include "vchat.h"
32#include "vchat-connection.h" 31#include "vchat-connection.h"
33#include "vchat-tls.h" 32#include "vchat-tls.h"
33#include "vchat.h"
34 34
35static int serverfd = -1; 35static int serverfd = -1;
36unsigned int want_tcp_keepalive = 0; 36unsigned int want_tcp_keepalive = 0;
@@ -40,49 +40,49 @@ unsigned int want_tcp_keepalive = 0;
40extern int status; 40extern int status;
41 41
42/* Generic tcp connector, blocking */ 42/* Generic tcp connector, blocking */
43static int connect_tcp_socket( const char *server, const char *port ) { 43static int connect_tcp_socket(const char *server, const char *port) {
44 struct addrinfo hints, *res, *res0; 44 struct addrinfo hints, *res, *res0;
45 int s, error; 45 int s, error;
46 46
47 memset(&hints, 0, sizeof(hints)); 47 memset(&hints, 0, sizeof(hints));
48 hints.ai_family = PF_UNSPEC; 48 hints.ai_family = PF_UNSPEC;
49 hints.ai_socktype = SOCK_STREAM; 49 hints.ai_socktype = SOCK_STREAM;
50 error = getaddrinfo( server, port, &hints, &res0 ); 50 error = getaddrinfo(server, port, &hints, &res0);
51 if (error) return -1; 51 if (error)
52 return -1;
52 s = -1; 53 s = -1;
53 for (res = res0; res; res = res->ai_next) { 54 for (res = res0; res; res = res->ai_next) {
54 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 55 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
55 if (s < 0) continue; 56 if (s < 0)
57 continue;
56 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { 58 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
57 close(s); 59 close(s);
58 s = -1; 60 s = -1;
59 continue; 61 continue;
60 } 62 }
61 break; /* okay we got one */ 63 break; /* okay we got one */
62 } 64 }
63 freeaddrinfo(res0); 65 freeaddrinfo(res0);
64 66
65 if (want_tcp_keepalive) { 67 if (want_tcp_keepalive) {
66 int one=1; 68 int one = 1;
67 setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,&one,sizeof(one)); 69 setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one));
68 } 70 }
69 return s; 71 return s;
70} 72}
71 73
72/* Return a tilde expanded path in a malloced buffer or NULL */ 74/* Return a tilde expanded path in a malloced buffer or NULL */
73static char *get_tilde_expanded(confopt opt) { 75static char *get_tilde_expanded(confopt opt) {
74 char *str = getstroption (opt); 76 char *str = getstroption(opt);
75 if (!str) 77 if (!str)
76 return str; 78 return str;
77 if (str[0] == '~') 79 if (str[0] == '~')
78 return tilde_expand (str); 80 return tilde_expand(str);
79 return strdup(str); 81 return strdup(str);
80} 82}
81 83
82/* connects to server */ 84/* connects to server */
83int 85int vc_connect(const char *server, const char *port) {
84vc_connect (const char *server, const char *port)
85{
86 /* vchat connection x509 store */ 86 /* vchat connection x509 store */
87 vc_x509store_t vc_store; 87 vc_x509store_t vc_store;
88 88
@@ -90,11 +90,11 @@ vc_connect (const char *server, const char *port)
90 char *certfile, *cafile; 90 char *certfile, *cafile;
91 91
92 /* Connect to the server */ 92 /* Connect to the server */
93 serverfd = connect_tcp_socket( server, port ); 93 serverfd = connect_tcp_socket(server, port);
94 if( serverfd < 0 ) { 94 if (serverfd < 0) {
95 /* inform user */ 95 /* inform user */
96 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_CANTCONNECT), server, port ); 96 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_CANTCONNECT), server, port);
97 writechan (tmpstr); 97 writechan(tmpstr);
98 return -1; 98 return -1;
99 } 99 }
100 100
@@ -105,11 +105,11 @@ vc_connect (const char *server, const char *port)
105 vc_init_x509store(&vc_store); 105 vc_init_x509store(&vc_store);
106 106
107 /* get name of certificate file */ 107 /* get name of certificate file */
108 certfile = get_tilde_expanded (CF_CERTFILE); 108 certfile = get_tilde_expanded(CF_CERTFILE);
109 /* do we have a certificate file? */ 109 /* do we have a certificate file? */
110 if (certfile) { 110 if (certfile) {
111 /* get name of key file */ 111 /* get name of key file */
112 char *keyfile = get_tilde_expanded (CF_KEYFILE); 112 char *keyfile = get_tilde_expanded(CF_KEYFILE);
113 113
114 vc_x509store_setcertfile(&vc_store, certfile); 114 vc_x509store_setcertfile(&vc_store, certfile);
115 vc_x509store_set_pkeycb(&vc_store, (vc_askpass_cb_t)passprompt); 115 vc_x509store_set_pkeycb(&vc_store, (vc_askpass_cb_t)passprompt);
@@ -122,13 +122,13 @@ vc_connect (const char *server, const char *port)
122 } 122 }
123 123
124 /* get name of ca file */ 124 /* get name of ca file */
125 cafile = get_tilde_expanded (CF_CAFILE); 125 cafile = get_tilde_expanded(CF_CAFILE);
126 if (cafile && !access(cafile, F_OK)) 126 if (cafile && !access(cafile, F_OK))
127 vc_x509store_setcafile(&vc_store, cafile); 127 vc_x509store_setcafile(&vc_store, cafile);
128 free(cafile); 128 free(cafile);
129 129
130 /* upgrade our plain BIO to ssl */ 130 /* upgrade our plain BIO to ssl */
131 int result = vc_tls_connect( serverfd, &vc_store ); 131 int result = vc_tls_connect(serverfd, &vc_store);
132 vc_cleanup_x509store(&vc_store); 132 vc_cleanup_x509store(&vc_store);
133 133
134 if (result) { 134 if (result) {
@@ -136,17 +136,17 @@ vc_connect (const char *server, const char *port)
136 serverfd = -1; 136 serverfd = -1;
137 errno = EIO; 137 errno = EIO;
138 vc_tls_cleanup(); 138 vc_tls_cleanup();
139 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_CANTCONNECT), server, port ); 139 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_CANTCONNECT), server, port);
140 writechan (tmpstr); 140 writechan(tmpstr);
141 return -1; 141 return -1;
142 } 142 }
143 143
144 /* inform user */ 144 /* inform user */
145 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_CONNECTED), server, port); 145 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_CONNECTED), server, port);
146 writechan (tmpstr); 146 writechan(tmpstr);
147 147
148#ifdef DEBUG 148#ifdef DEBUG
149 dumpfile = fopen( "dumpfile", "a"); 149 dumpfile = fopen("dumpfile", "a");
150#endif 150#endif
151 151
152 /* if we didn't fail until now, we've got a connection. */ 152 /* if we didn't fail until now, we've got a connection. */
@@ -154,25 +154,24 @@ vc_connect (const char *server, const char *port)
154} 154}
155 155
156/* Poll for activity on the socket or stdin */ 156/* Poll for activity on the socket or stdin */
157int vc_poll (int timeout_seconds) { 157int vc_poll(int timeout_seconds) {
158 fd_set readfds; 158 fd_set readfds;
159 FD_ZERO (&readfds); 159 FD_ZERO(&readfds);
160 FD_SET (0, &readfds); 160 FD_SET(0, &readfds);
161 if (serverfd != -1) 161 if (serverfd != -1)
162 FD_SET (serverfd, &readfds); 162 FD_SET(serverfd, &readfds);
163 struct timeval tv = { timeout_seconds, 0}; 163 struct timeval tv = {timeout_seconds, 0};
164 int result = select (serverfd + 2, &readfds, NULL, NULL, &tv); 164 int result = select(serverfd + 2, &readfds, NULL, NULL, &tv);
165 if (result <= 0) 165 if (result <= 0)
166 return result; 166 return result;
167 result = FD_ISSET (0, &readfds) ? 1 : 0; 167 result = FD_ISSET(0, &readfds) ? 1 : 0;
168 if (serverfd != -1) 168 if (serverfd != -1)
169 result += FD_ISSET (serverfd, &readfds) ? 2 : 0; 169 result += FD_ISSET(serverfd, &readfds) ? 2 : 0;
170 return result; 170 return result;
171} 171}
172 172
173/* disconnect from server */ 173/* disconnect from server */
174void 174void vc_disconnect() {
175vc_disconnect () {
176 if (serverfd > 0) { 175 if (serverfd > 0) {
177 close(serverfd); 176 close(serverfd);
178 serverfd = -1; 177 serverfd = -1;
@@ -183,21 +182,19 @@ vc_disconnect () {
183 182
184#define STAGINGSIZE 16384 183#define STAGINGSIZE 16384
185static char _staging[STAGINGSIZE]; 184static char _staging[STAGINGSIZE];
186void 185void vc_sendmessage(const char *msg) {
187vc_sendmessage (const char *msg)
188{
189 size_t sent, len = snprintf(_staging, sizeof(_staging), "%s\r\n", msg); 186 size_t sent, len = snprintf(_staging, sizeof(_staging), "%s\r\n", msg);
190#ifdef DEBUG 187#ifdef DEBUG
191 /* debugging? log network output! */ 188 /* debugging? log network output! */
192 fprintf (dumpfile, ">| (%zd) %s\n", len - 2, msg); 189 fprintf(dumpfile, ">| (%zd) %s\n", len - 2, msg);
193#endif 190#endif
194 191
195 if (getintoption(CF_USESSL)) 192 if (getintoption(CF_USESSL))
196 sent = vc_tls_sendmessage (_staging, len); 193 sent = vc_tls_sendmessage(_staging, len);
197 else 194 else
198 sent = write (serverfd, _staging, len); 195 sent = write(serverfd, _staging, len);
199 if (sent != len) 196 if (sent != len)
200 writecf (FS_ERR,"Message sending fuzzy."); 197 writecf(FS_ERR, "Message sending fuzzy.");
201} 198}
202 199
203/* offset in buffer (for linebreaks at packet borders) */ 200/* offset in buffer (for linebreaks at packet borders) */
@@ -206,9 +203,7 @@ static char _buf[BUFSIZE];
206static size_t _buf_fill; 203static size_t _buf_fill;
207 204
208/* get data from servers connection */ 205/* get data from servers connection */
209void 206void vc_receive(void) {
210vc_receive (void)
211{
212 char *endmsg; 207 char *endmsg;
213 size_t freebytes = BUFSIZE - _buf_fill; 208 size_t freebytes = BUFSIZE - _buf_fill;
214 ssize_t bytes; 209 ssize_t bytes;
@@ -218,26 +213,27 @@ vc_receive (void)
218 else 213 else
219 bytes = vc_tls_receivemessage(_buf + _buf_fill, freebytes); 214 bytes = vc_tls_receivemessage(_buf + _buf_fill, freebytes);
220 215
221 /* Our tls functions may require retries with handshakes etc, this is signalled by -2 */ 216 /* Our tls functions may require retries with handshakes etc, this is
217 * signalled by -2 */
222 if (bytes == -2) 218 if (bytes == -2)
223 return; 219 return;
224 220
225 /* Error on the socket read? raise error message, bail out */ 221 /* Error on the socket read? raise error message, bail out */
226 if (bytes == -1) { 222 if (bytes == -1) {
227 snprintf (tmpstr, TMPSTRSIZE, "Receive fails, %s.", strerror(errno)); 223 snprintf(tmpstr, TMPSTRSIZE, "Receive fails, %s.", strerror(errno));
228 snprintf (errstr, ERRSTRSIZE, "Receive fails, %s.\n", strerror(errno)); 224 snprintf(errstr, ERRSTRSIZE, "Receive fails, %s.\n", strerror(errno));
229 writecf (FS_ERR,tmpstr); 225 writecf(FS_ERR, tmpstr);
230 status = 0; 226 status = 0;
231 return; 227 return;
232 } 228 }
233 229
234 /* end of file from server? */ 230 /* end of file from server? */
235 if (bytes == 0) { 231 if (bytes == 0) {
236 /* inform user, bail out */ 232 /* inform user, bail out */
237 writecf (FS_SERV, "* EOF from server."); 233 writecf(FS_SERV, "* EOF from server.");
238 snprintf (errstr, ERRSTRSIZE, "* EOF from server.\n"); 234 snprintf(errstr, ERRSTRSIZE, "* EOF from server.\n");
239 status = 0; 235 status = 0;
240 return; 236 return;
241 } 237 }
242 238
243 _buf_fill += bytes; 239 _buf_fill += bytes;
@@ -249,13 +245,14 @@ vc_receive (void)
249 endmsg[0] = 0; 245 endmsg[0] = 0;
250 if (endmsg[-1] == '\r') 246 if (endmsg[-1] == '\r')
251 endmsg[-1] = 0; 247 endmsg[-1] = 0;
252 /* If terminating and chomping left us with a message, give it to line handler */ 248 /* If terminating and chomping left us with a message, give it to line
249 * handler */
253 if (_buf[0]) { 250 if (_buf[0]) {
254#ifdef DEBUG 251#ifdef DEBUG
255 /* debugging? log network input! */ 252 /* debugging? log network input! */
256 fprintf (stderr, "<| %s\n", _buf); 253 fprintf(stderr, "<| %s\n", _buf);
257#endif 254#endif
258 protocol_parsemsg (_buf); 255 protocol_parsemsg(_buf);
259 } 256 }
260 } 257 }
261 _buf_fill -= 1 + endmsg - _buf; 258 _buf_fill -= 1 + endmsg - _buf;
diff --git a/vchat-connection.h b/vchat-connection.h
index a56dc29..9b3ccaa 100644
--- a/vchat-connection.h
+++ b/vchat-connection.h
@@ -2,8 +2,8 @@
2 2
3#include <stdint.h> 3#include <stdint.h>
4 4
5int vc_connect(const char *host, const char *port); 5int vc_connect(const char *host, const char *port);
6void vc_sendmessage(const char *message); 6void vc_sendmessage(const char *message);
7void vc_receive(); 7void vc_receive();
8int vc_poll(); 8int vc_poll();
9void vc_disconnect(); 9void vc_disconnect();
diff --git a/vchat-protocol.c b/vchat-protocol.c
index 2b98779..ac65639 100755
--- a/vchat-protocol.c
+++ b/vchat-protocol.c
@@ -10,49 +10,51 @@
10 * without even the implied warranty of merchantability or fitness for a 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 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 12 * any direct, indirect, incidental or special damages arising in any way out
13 * of the use of this software. 13 * of the use of this software.
14 * 14 *
15 */ 15 */
16 16
17/* general includes */ 17/* general includes */
18#include <stdlib.h> 18#include <errno.h>
19#include <langinfo.h>
20#include <locale.h>
19#include <stdio.h> 21#include <stdio.h>
22#include <stdlib.h>
20#include <string.h> 23#include <string.h>
21#include <errno.h> 24
22#include <readline/readline.h> 25#include <readline/readline.h>
23#include <locale.h>
24#include <langinfo.h>
25 26
26#ifdef DEBUG 27#ifdef DEBUG
27FILE * dumpfile; 28FILE *dumpfile;
28#endif 29#endif
29 30
30/* local includes */ 31/* local includes */
31#include "vchat.h"
32#include "vchat-user.h"
33#include "vchat-connection.h" 32#include "vchat-connection.h"
33#include "vchat-user.h"
34#include "vchat.h"
34 35
35/* version of this module */ 36/* version of this module */
36const char *vchat_io_version = "vchat-protocol.c $Id$"; 37const char *vchat_io_version =
38 "vchat-protocol.c $Id$";
37 39
38/* declaration of local helper functions */ 40/* declaration of local helper functions */
39static void usersignon (char *); 41static void usersignon(char *);
40static void usersignoff (char *); 42static void usersignoff(char *);
41static void usernickchange (char *); 43static void usernickchange(char *);
42static void userjoin (char *); 44static void userjoin(char *);
43static void userleave (char *); 45static void userleave(char *);
44static void receivenicks (char *message); 46static void receivenicks(char *message);
45static void justloggedin (char *message); 47static void justloggedin(char *message);
46static void nickerr (char *message); 48static void nickerr(char *message);
47static void login (char *message); 49static void login(char *message);
48static void anonlogin (char *message); 50static void anonlogin(char *message);
49static void topicinfo (char *message); 51static void topicinfo(char *message);
50static void pubaction (char *message); 52static void pubaction(char *message);
51static void pubthoughts (char *message); 53static void pubthoughts(char *message);
52static void serverlogin (char *message); 54static void serverlogin(char *message);
53static void idleprompt (char *message); 55static void idleprompt(char *message);
54static void topicchange (char *message); 56static void topicchange(char *message);
55static void pmnotsent (char *message); 57static void pmnotsent(char *message);
56 58
57/* declaration of server message array */ 59/* declaration of server message array */
58#include "vchat-messages.h" 60#include "vchat-messages.h"
@@ -61,61 +63,53 @@ char *encoding;
61 63
62/* handle a pm not sent error 64/* handle a pm not sent error
63 * format: 412 %s */ 65 * format: 412 %s */
64static void 66static void pmnotsent(char *message) {
65pmnotsent (char *message) 67 while (*message && *message != ' ')
66{ 68 message++;
67 while(*message && *message!=' ') message++; 69 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_ERR), message + 1);
68 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_ERR),message+1); 70 writepriv(tmpstr, 0);
69 writepriv( tmpstr, 0);
70
71} 71}
72 72
73/* parse and handle an action string 73/* parse and handle an action string
74 * format: 118 %s %s 74 * format: 118 %s %s
75 * vars: %s nick 75 * vars: %s nick
76 * %s action */ 76 * %s action */
77static void 77static void pubaction(char *message) {
78pubaction (char *message)
79{
80 char *nick = NULL, *action = NULL; 78 char *nick = NULL, *action = NULL;
81 nick = strchr (message, ' '); 79 nick = strchr(message, ' ');
82 nick[0] = '\0'; 80 nick[0] = '\0';
83 nick++; 81 nick++;
84 82
85 action = strchr (nick, ' '); 83 action = strchr(nick, ' ');
86 action[0] = '\0'; 84 action[0] = '\0';
87 action++; 85 action++;
88 86
89 ul_public_action(nick); 87 ul_public_action(nick);
90 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_PUBACTION),nick,action); 88 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_PUBACTION), nick, action);
91 writechan (tmpstr); 89 writechan(tmpstr);
92} 90}
93 91
94/* parse and handle an thought string 92/* parse and handle an thought string
95 * format: 124 %s %s 93 * format: 124 %s %s
96 * vars: %s nick 94 * vars: %s nick
97 * %s thought */ 95 * %s thought */
98static void 96static void pubthoughts(char *message) {
99pubthoughts (char *message)
100{
101 char *nick = NULL, *thoughts = NULL; 97 char *nick = NULL, *thoughts = NULL;
102 nick = strchr (message, ' '); 98 nick = strchr(message, ' ');
103 nick[0] = '\0'; 99 nick[0] = '\0';
104 nick++; 100 nick++;
105 101
106 thoughts = strchr (nick, ' '); 102 thoughts = strchr(nick, ' ');
107 thoughts[0] = '\0'; 103 thoughts[0] = '\0';
108 thoughts++; 104 thoughts++;
109 105
110 ul_public_action(nick); 106 ul_public_action(nick);
111 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_PUBTHOUGHT),nick,thoughts); 107 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_PUBTHOUGHT), nick, thoughts);
112 writechan (tmpstr); 108 writechan(tmpstr);
113} 109}
114 110
115/* parse and handle server logon */ 111/* parse and handle server logon */
116static void 112static void serverlogin(char *message) {
117serverlogin (char *message)
118{
119 (void)message; 113 (void)message;
120 int utf8 = !strcmp(nl_langinfo(CODESET), "UTF-8"); 114 int utf8 = !strcmp(nl_langinfo(CODESET), "UTF-8");
121 if (utf8) 115 if (utf8)
@@ -125,274 +119,257 @@ serverlogin (char *message)
125/* parse and handle an idle message 119/* parse and handle an idle message
126 * format: 305 120 * format: 305
127 * vars: %s message */ 121 * vars: %s message */
128static void 122static void idleprompt(char *message) {
129idleprompt (char *message)
130{
131 char *msg = NULL; 123 char *msg = NULL;
132 msg = strchr (message, ' '); 124 msg = strchr(message, ' ');
133 msg[0] = '\0'; 125 msg[0] = '\0';
134 msg++; 126 msg++;
135 127
136 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_IDLE),msg); 128 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_IDLE), msg);
137 writechan (tmpstr); 129 writechan(tmpstr);
138} 130}
139 131
140/* parse and handle a topic information string 132/* parse and handle a topic information string
141 * format: 115 %d %s 133 * format: 115 %d %s
142 * vars: %d chan - channel number 134 * vars: %d chan - channel number
143 * %s topic - topic */ 135 * %s topic - topic */
144static void 136static void topicinfo(char *message) {
145topicinfo (char *message)
146{
147 char *channel = NULL, *topic = NULL; 137 char *channel = NULL, *topic = NULL;
148 int tmpchan = 0, ownchan = own_channel_get(); 138 int tmpchan = 0, ownchan = own_channel_get();
149 139
150 /* search start of channel number */ 140 /* search start of channel number */
151 channel = strchr (message, ' '); 141 channel = strchr(message, ' ');
152 channel++; 142 channel++;
153 143
154 /* search start of topic and terminate channel number */ 144 /* search start of topic and terminate channel number */
155 topic = strchr (channel, ' '); 145 topic = strchr(channel, ' ');
156 topic[0] = '\0'; 146 topic[0] = '\0';
157 topic++; 147 topic++;
158 148
159 /* convert channel number to integer */ 149 /* convert channel number to integer */
160 tmpchan = atoi (channel); 150 tmpchan = atoi(channel);
161 151
162 if (tmpchan == ownchan ) { 152 if (tmpchan == ownchan) {
163 /* show change in topic window */ 153 /* show change in topic window */
164 if (strlen(topic)) 154 if (strlen(topic))
165 snprintf (topicstr, TOPICSTRSIZE, getformatstr(FS_TOPICW), ownchan, topic); 155 snprintf(topicstr, TOPICSTRSIZE, getformatstr(FS_TOPICW), ownchan, topic);
166 else 156 else
167 snprintf (topicstr, TOPICSTRSIZE, getformatstr(FS_NOTOPICW), ownchan ); 157 snprintf(topicstr, TOPICSTRSIZE, getformatstr(FS_NOTOPICW), ownchan);
168 topicline(NULL); 158 topicline(NULL);
169 } 159 }
170 160
171 /* announce change in channel window */ 161 /* announce change in channel window */
172 if (strlen(topic)) 162 if (strlen(topic))
173 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_TOPIC), tmpchan, topic); 163 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_TOPIC), tmpchan, topic);
174 else 164 else
175 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_NOTOPIC), tmpchan); 165 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_NOTOPIC), tmpchan);
176 writechan (tmpstr); 166 writechan(tmpstr);
177} 167}
178 168
179/* parse and handle a topic change string 169/* parse and handle a topic change string
180 * format: 114 %s changes topic to '%s' 170 * format: 114 %s changes topic to '%s'
181 * vars: %s nick 171 * vars: %s nick
182 * %s topic */ 172 * %s topic */
183static void 173static void topicchange(char *message) {
184topicchange (char *message)
185{
186 char *nick = NULL, *topic = NULL; 174 char *nick = NULL, *topic = NULL;
187 int len, ownchan = own_channel_get(); 175 int len, ownchan = own_channel_get();
188 176
189 /* search start of nickname */ 177 /* search start of nickname */
190 nick = strchr (message, ' '); 178 nick = strchr(message, ' ');
191 nick++; 179 nick++;
192 180
193 /* search start of message before topic, terminate nick */ 181 /* search start of message before topic, terminate nick */
194 topic = strchr (nick, ' '); 182 topic = strchr(nick, ' ');
195 topic[0] = '\0'; 183 topic[0] = '\0';
196 topic++; 184 topic++;
197 185
198 /* search start of real topic and terminate channel number */ 186 /* search start of real topic and terminate channel number */
199 topic = strchr (topic, '\''); 187 topic = strchr(topic, '\'');
200 topic[0] = '\0'; 188 topic[0] = '\0';
201 topic++; 189 topic++;
202 190
203 /* remove ending '\'', if there */ 191 /* remove ending '\'', if there */
204 len = strlen (topic); 192 len = strlen(topic);
205 if (topic[len-1] == '\'') 193 if (topic[len - 1] == '\'')
206 topic[len-1] = '\0'; 194 topic[len - 1] = '\0';
207 195
208 ul_public_action(nick); 196 ul_public_action(nick);
209 /* show change in topic window */ 197 /* show change in topic window */
210 snprintf (topicstr, TOPICSTRSIZE, getformatstr(FS_TOPICW), ownchan, topic); 198 snprintf(topicstr, TOPICSTRSIZE, getformatstr(FS_TOPICW), ownchan, topic);
211 topicline(NULL); 199 topicline(NULL);
212 200
213 /* announce change in channel window */ 201 /* announce change in channel window */
214 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_CHGTOPIC), nick, topic); 202 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_CHGTOPIC), nick, topic);
215 writechan (tmpstr); 203 writechan(tmpstr);
216} 204}
217 205
218/* parse and handle a login message 206/* parse and handle a login message
219 * format: 212 %s %s 207 * format: 212 %s %s
220 * vars: %s str1 - nick used to login 208 * vars: %s str1 - nick used to login
221 * %s str2 - servers message */ 209 * %s str2 - servers message */
222static void 210static void justloggedin(char *message) {
223justloggedin (char *message)
224{
225 char *str1 = NULL, *str2 = NULL; 211 char *str1 = NULL, *str2 = NULL;
226 /* search start of nickname */ 212 /* search start of nickname */
227 str1 = strchr (message, ' '); 213 str1 = strchr(message, ' ');
228 str1++; 214 str1++;
229 215
230 /* search start of message, terminate nick */ 216 /* search start of message, terminate nick */
231 str2 = strchr (str1, ' '); 217 str2 = strchr(str1, ' ');
232 str2[0] = '\0'; 218 str2[0] = '\0';
233 str2++; 219 str2++;
234 220
235 /* if we have a new nick, store it */ 221 /* if we have a new nick, store it */
236 own_nick_set( str1 ); 222 own_nick_set(str1);
237 223
238 /* show change in console window */ 224 /* show change in console window */
239 snprintf (consolestr, CONSOLESTRSIZE, getformatstr(FS_CONSOLE), str1, getstroption (CF_SERVERHOST), getstroption (CF_SERVERPORT)); 225 snprintf(consolestr, CONSOLESTRSIZE, getformatstr(FS_CONSOLE), str1,
240 consoleline (NULL); 226 getstroption(CF_SERVERHOST), getstroption(CF_SERVERPORT));
227 consoleline(NULL);
241 228
242 /* announce login as servermessage */ 229 /* announce login as servermessage */
243 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_SIGNON), str1, str2); 230 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_SIGNON), str1, str2);
244 writechan (tmpstr); 231 writechan(tmpstr);
245 232
246 /* we're not logged in, change status and request nicks */ 233 /* we're not logged in, change status and request nicks */
247 if (!loggedin) 234 if (!loggedin) {
248 { 235 loadcfg(getstroption(CF_LOGINSCRIPT), 0, handleline);
249 loadcfg(getstroption(CF_LOGINSCRIPT),0,handleline); 236 handleline(".S");
250 handleline(".S"); 237 loggedin = 1;
251 loggedin = 1; 238 }
252 }
253} 239}
254 240
255/* this user joins a different channel */ 241/* this user joins a different channel */
256void 242void ownjoin(int channel) {
257ownjoin (int channel)
258{
259 vc_sendmessage(".t"); 243 vc_sendmessage(".t");
260 snprintf(tmpstr, TMPSTRSIZE, ".S %d",channel); 244 snprintf(tmpstr, TMPSTRSIZE, ".S %d", channel);
261 vc_sendmessage(tmpstr); 245 vc_sendmessage(tmpstr);
262} 246}
263 247
264/* this user changes his nick */ 248/* this user changes his nick */
265void 249void ownnickchange(const char *newnick) { (void)newnick; }
266ownnickchange (const char *newnick)
267{
268 (void)newnick;
269}
270 250
271/* parse and handle a nick error message 251/* parse and handle a nick error message
272 * format: 401 %s 252 * format: 401 %s
273 * 403 %s 253 * 403 %s
274 * 415 %s 254 * 415 %s
275 * vars: %s - server message */ 255 * vars: %s - server message */
276static void 256static void nickerr(char *message) {
277nickerr (char *message)
278{
279 char *helpkiller = NULL; 257 char *helpkiller = NULL;
280 /* mutate message for output */ 258 /* mutate message for output */
281 message[2] = '!'; 259 message[2] = '!';
282 /* help information found? remove it. */ 260 /* help information found? remove it. */
283 if ((helpkiller = strstr (message, " Type .h for help"))) 261 if ((helpkiller = strstr(message, " Type .h for help")))
284 helpkiller[0] = '\0'; 262 helpkiller[0] = '\0';
285 /* nickchange not done? eliminate message */ 263 /* nickchange not done? eliminate message */
286 if (loggedin && (helpkiller = strstr (message, " - Nick not changed"))) 264 if (loggedin && (helpkiller = strstr(message, " - Nick not changed")))
287 helpkiller[0] = '\0'; 265 helpkiller[0] = '\0';
288 /* show errormessage */ 266 /* show errormessage */
289 writecf (FS_ERR,&message[2]); 267 writecf(FS_ERR, &message[2]);
290 268
291 /* not logged in? insist on getting a new nick */ 269 /* not logged in? insist on getting a new nick */
292 if (!loggedin) 270 if (!loggedin) {
293 { 271 /* free bogus nick */
294 /* free bogus nick */ 272 own_nick_set(NULL);
295 own_nick_set(NULL);
296 273
297 /* get new nick via vchat-ui.c */ 274 /* get new nick via vchat-ui.c */
298 nickprompt (); 275 nickprompt();
299 276
300 /* form login message and send it to server */ 277 /* form login message and send it to server */
301 snprintf (tmpstr, TMPSTRSIZE, ".l %s %s %d", own_nick_get(), getstroption (CF_FROM), getintoption (CF_CHANNEL)); 278 snprintf(tmpstr, TMPSTRSIZE, ".l %s %s %d", own_nick_get(),
302 vc_sendmessage (tmpstr); 279 getstroption(CF_FROM), getintoption(CF_CHANNEL));
303 } 280 vc_sendmessage(tmpstr);
281 }
304} 282}
305 283
306/* parse and handle a registered nick information 284/* parse and handle a registered nick information
307 * format: 120 %s %s 285 * format: 120 %s %s
308 * vars: %s - this users registered nick 286 * vars: %s - this users registered nick
309 * %s msg - server message */ 287 * %s msg - server message */
310static void 288static void login(char *message) {
311login (char *message) {
312 char *msg = NULL; 289 char *msg = NULL;
313 290
314 /* mutate message for output */ 291 /* mutate message for output */
315 message[2] = '*'; 292 message[2] = '*';
316 /* show message to user */ 293 /* show message to user */
317 writecf (FS_SERV,&message[2]); 294 writecf(FS_SERV, &message[2]);
318 295
319 /* we don't know our nick? */ 296 /* we don't know our nick? */
320 if (!own_nick_get() ) { 297 if (!own_nick_get()) {
321 /* find message after nick */ 298 /* find message after nick */
322 msg = strchr (&message[4], ' '); 299 msg = strchr(&message[4], ' ');
323 if (msg) { 300 if (msg) {
324 /* terminate string before message and copy nick */ 301 /* terminate string before message and copy nick */
325 msg[0] = '\0'; 302 msg[0] = '\0';
326 own_nick_set(&message[4]); 303 own_nick_set(&message[4]);
327 } else { 304 } else {
328 /* no string in servers message (huh?), ask user for nick */ 305 /* no string in servers message (huh?), ask user for nick */
329 nickprompt (); 306 nickprompt();
330 } 307 }
331 } 308 }
332 309
333 /* form login message and send it to server */ 310 /* form login message and send it to server */
334 snprintf (tmpstr, TMPSTRSIZE, ".l %s %s %d", own_nick_get(), getstroption (CF_FROM), getintoption (CF_CHANNEL)); 311 snprintf(tmpstr, TMPSTRSIZE, ".l %s %s %d", own_nick_get(),
335 vc_sendmessage (tmpstr); 312 getstroption(CF_FROM), getintoption(CF_CHANNEL));
313 vc_sendmessage(tmpstr);
336} 314}
337 315
338/* parse and handle anon login request 316/* parse and handle anon login request
339 * format: 121 %s 317 * format: 121 %s
340 * vars: %s - server message */ 318 * vars: %s - server message */
341static void 319static void anonlogin(char *message) {
342anonlogin (char *message)
343{
344 /* mutate message for output */ 320 /* mutate message for output */
345 message[2] = '*'; 321 message[2] = '*';
346 /* show message to user */ 322 /* show message to user */
347 writecf (FS_SERV,&message[2]); 323 writecf(FS_SERV, &message[2]);
348 324
349 /* we don't know our nick? ask for it! */ 325 /* we don't know our nick? ask for it! */
350 if (!own_nick_get()) 326 if (!own_nick_get())
351 nickprompt (); 327 nickprompt();
352 328
353 /* form login message and send it to server */ 329 /* form login message and send it to server */
354 snprintf (tmpstr, TMPSTRSIZE, ".l %s %s %d", own_nick_get(), getstroption (CF_FROM), getintoption (CF_CHANNEL)); 330 snprintf(tmpstr, TMPSTRSIZE, ".l %s %s %d", own_nick_get(),
355 vc_sendmessage (tmpstr); 331 getstroption(CF_FROM), getintoption(CF_CHANNEL));
332 vc_sendmessage(tmpstr);
356} 333}
357 334
358/* parse and handle list of nicks (from '.S') 335/* parse and handle list of nicks (from '.S')
359 * format: 119 %s .. 336 * format: 119 %s ..
360 * vars: %s nick - a users nick */ 337 * vars: %s nick - a users nick */
361static void 338static void receivenicks(char *message) {
362receivenicks (char *message) {
363 char *str1 = NULL, *str2 = NULL; 339 char *str1 = NULL, *str2 = NULL;
364 int chanflag = -1; 340 int chanflag = -1;
365 341
366 /* show message to user */ 342 /* show message to user */
367 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_USONLINE), &message[4]); 343 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_USONLINE), &message[4]);
368 writechan (tmpstr); 344 writechan(tmpstr);
369 345
370 /* search for channelnumber */ 346 /* search for channelnumber */
371 if( !(str1 = strchr (message, ' ') ) ) return; 347 if (!(str1 = strchr(message, ' ')))
348 return;
372 str1++; 349 str1++;
373 350
374 if (str1[0] == '*') { 351 if (str1[0] == '*') {
375 ul_rebuild_list(); 352 ul_rebuild_list();
376 str1++; 353 str1++;
377 } else { 354 } else {
378 int mychan; 355 int mychan;
379 str2 = str1; 356 str2 = str1;
380 str1 = strchr(str2,' '); 357 str1 = strchr(str2, ' ');
381 str1[0] = '\0'; 358 str1[0] = '\0';
382 mychan = atoi(str2); 359 mychan = atoi(str2);
383 if( mychan != own_channel_get() ) 360 if (mychan != own_channel_get())
384 return; 361 return;
385 362
386 /* Kick all users from the IN_MY_CHANNEL list */ 363 /* Kick all users from the IN_MY_CHANNEL list */
387 own_channel_set( own_channel_get() ); 364 own_channel_set(own_channel_get());
388 chanflag = 1; 365 chanflag = 1;
389 } 366 }
390 str1++; 367 str1++;
391 368
392 /* while user .. */ 369 /* while user .. */
393 while (str1) { 370 while (str1) {
394 /* search next user */ 371 /* search next user */
395 str2 = strchr (str1, ' '); 372 str2 = strchr(str1, ' ');
396 /* there is another user? terminate this one */ 373 /* there is another user? terminate this one */
397 if (str2) { 374 if (str2) {
398 str2[0] = '\0'; 375 str2[0] = '\0';
@@ -412,52 +389,48 @@ receivenicks (char *message) {
412 * format: 211 %s %s 389 * format: 211 %s %s
413 * vars: %s nick - who logged on 390 * vars: %s nick - who logged on
414 * %s msg - servers message */ 391 * %s msg - servers message */
415static void 392static void usersignon(char *message) {
416usersignon (char *message)
417{
418 char *nick = NULL, *msg = NULL; 393 char *nick = NULL, *msg = NULL;
419 /* search start of nickname */ 394 /* search start of nickname */
420 nick = strchr (message, ' '); 395 nick = strchr(message, ' ');
421 nick++; 396 nick++;
422 397
423 /* search start of message, terminate nick */ 398 /* search start of message, terminate nick */
424 msg = strchr (nick, ' '); 399 msg = strchr(nick, ' ');
425 msg[0] = '\0'; 400 msg[0] = '\0';
426 msg++; 401 msg++;
427 402
428 /* add this user via vchat-user.c */ 403 /* add this user via vchat-user.c */
429 ul_add (nick, 0); 404 ul_add(nick, 0);
430 405
431 /* show message to user */ 406 /* show message to user */
432 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_SIGNON), nick, msg); 407 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_SIGNON), nick, msg);
433 writechan (tmpstr); 408 writechan(tmpstr);
434} 409}
435 410
436/* parse and handle a logoff message 411/* parse and handle a logoff message
437 * format: 221 %s %s 412 * format: 221 %s %s
438 * vars: %s nick - who logged off 413 * vars: %s nick - who logged off
439 * %s msg - servers message */ 414 * %s msg - servers message */
440static void 415static void usersignoff(char *message) {
441usersignoff (char *message)
442{
443 char *nick = NULL, *msg = NULL; 416 char *nick = NULL, *msg = NULL;
444 /* search start of nickname */ 417 /* search start of nickname */
445 nick = strchr (message, ' '); 418 nick = strchr(message, ' ');
446 nick++; 419 nick++;
447 420
448 /* search start of message, terminate nick */ 421 /* search start of message, terminate nick */
449 msg = strchr (nick, ' '); 422 msg = strchr(nick, ' ');
450 if( msg ) { 423 if (msg) {
451 msg[0] = '\0'; 424 msg[0] = '\0';
452 msg++; 425 msg++;
453 } 426 }
454 427
455 /* delete this user via vchat-user.c */ 428 /* delete this user via vchat-user.c */
456 ul_del (nick); 429 ul_del(nick);
457 430
458 /* show message to user */ 431 /* show message to user */
459 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_SIGNOFF), nick, msg); 432 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_SIGNOFF), nick, msg);
460 writechan (tmpstr); 433 writechan(tmpstr);
461} 434}
462 435
463/* parse and handle a join message 436/* parse and handle a join message
@@ -465,40 +438,38 @@ usersignoff (char *message)
465 * vars: %s nick - who joined 438 * vars: %s nick - who joined
466 * %s msg - servers message 439 * %s msg - servers message
467 * %d chan - channel joined */ 440 * %d chan - channel joined */
468static void 441static void userjoin(char *message) {
469userjoin (char *message)
470{
471 char *nick = NULL, *msg = NULL, *channel = NULL; 442 char *nick = NULL, *msg = NULL, *channel = NULL;
472 int chan = 0; 443 int chan = 0;
473 444
474 /* search start of nickname */ 445 /* search start of nickname */
475 nick = strchr (message, ' '); 446 nick = strchr(message, ' ');
476 nick++; 447 nick++;
477 448
478 /* search start of message, terminate nick */ 449 /* search start of message, terminate nick */
479 msg = strchr (nick, ' '); 450 msg = strchr(nick, ' ');
480 msg[0] = '\0'; 451 msg[0] = '\0';
481 msg++; 452 msg++;
482 453
483 /* search start of channel, terminate message */ 454 /* search start of channel, terminate message */
484 channel = strrchr (msg, ' '); 455 channel = strrchr(msg, ' ');
485 channel[0] = '\0'; 456 channel[0] = '\0';
486 channel++; 457 channel++;
487 458
488 /* convert channel to integer */ 459 /* convert channel to integer */
489 chan = atoi (channel); 460 chan = atoi(channel);
490 461
491 /* is it myself joining */ 462 /* is it myself joining */
492 if( own_nick_check(nick) ) 463 if (own_nick_check(nick))
493 own_channel_set(chan); 464 own_channel_set(chan);
494 465
495 /* notice channel join via vchat-user.c */ 466 /* notice channel join via vchat-user.c */
496 if( own_channel_get() == chan ) 467 if (own_channel_get() == chan)
497 ul_enter_chan(nick); 468 ul_enter_chan(nick);
498 469
499 /* show message to user */ 470 /* show message to user */
500 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_JOIN), nick, msg, chan); 471 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_JOIN), nick, msg, chan);
501 writechan (tmpstr); 472 writechan(tmpstr);
502} 473}
503 474
504/* parse and handle a leave message 475/* parse and handle a leave message
@@ -506,35 +477,33 @@ userjoin (char *message)
506 * vars: %s nick - who left 477 * vars: %s nick - who left
507 * %s msg - servers message 478 * %s msg - servers message
508 * %d chan - channel joined */ 479 * %d chan - channel joined */
509static void 480static void userleave(char *message) {
510userleave (char *message)
511{
512 char *nick = NULL, *msg = NULL, *channel = NULL; 481 char *nick = NULL, *msg = NULL, *channel = NULL;
513 int chan = 0; 482 int chan = 0;
514 483
515 /* search start of nickname */ 484 /* search start of nickname */
516 nick = strchr (message, ' '); 485 nick = strchr(message, ' ');
517 nick++; 486 nick++;
518 487
519 /* search start of message, terminate nick */ 488 /* search start of message, terminate nick */
520 msg = strchr (nick, ' '); 489 msg = strchr(nick, ' ');
521 msg[0] = '\0'; 490 msg[0] = '\0';
522 msg++; 491 msg++;
523 492
524 /* convert channel to integer */ 493 /* convert channel to integer */
525 channel = strrchr (msg, ' '); 494 channel = strrchr(msg, ' ');
526 channel[0] = '\0'; 495 channel[0] = '\0';
527 channel++; 496 channel++;
528 497
529 /* convert channel to integer */ 498 /* convert channel to integer */
530 chan = atoi (channel); 499 chan = atoi(channel);
531 500
532 /* notice channel leave via vchat-user.c */ 501 /* notice channel leave via vchat-user.c */
533 ul_leave_chan(nick); 502 ul_leave_chan(nick);
534 503
535 /* show message to user */ 504 /* show message to user */
536 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_LEAVE), nick, msg, chan); 505 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_LEAVE), nick, msg, chan);
537 writechan (tmpstr); 506 writechan(tmpstr);
538} 507}
539 508
540/* parse and handle a nickchange message 509/* parse and handle a nickchange message
@@ -542,151 +511,140 @@ userleave (char *message)
542 * vars: %s oldnick - users old nick 511 * vars: %s oldnick - users old nick
543 * %s newnick - users new nick 512 * %s newnick - users new nick
544 * %s msg - server message */ 513 * %s msg - server message */
545static void 514static void usernickchange(char *message) {
546usernickchange (char *message)
547{
548 char *oldnick = NULL, *newnick = NULL, *msg = NULL; 515 char *oldnick = NULL, *newnick = NULL, *msg = NULL;
549 516
550 /* search start of old nickname */ 517 /* search start of old nickname */
551 oldnick = strchr (message, ' '); 518 oldnick = strchr(message, ' ');
552 oldnick++; 519 oldnick++;
553 520
554 /* search start of new nickname, terminate old nick */ 521 /* search start of new nickname, terminate old nick */
555 newnick = strchr (oldnick, ' '); 522 newnick = strchr(oldnick, ' ');
556 newnick[0] = '\0'; 523 newnick[0] = '\0';
557 newnick++; 524 newnick++;
558 525
559 /* search start of message, terminate new nick */ 526 /* search start of message, terminate new nick */
560 msg = strchr (newnick, ' '); 527 msg = strchr(newnick, ' ');
561 msg[0] = '\0'; 528 msg[0] = '\0';
562 msg++; 529 msg++;
563 530
564 /* notice nickchange via vchat-user.c */ 531 /* notice nickchange via vchat-user.c */
565 ul_rename (oldnick, newnick); 532 ul_rename(oldnick, newnick);
566 533
567 if( own_nick_check(newnick) ) { 534 if (own_nick_check(newnick)) {
568 /* show change in console window */ 535 /* show change in console window */
569 snprintf (consolestr, CONSOLESTRSIZE, getformatstr(FS_CONSOLE), newnick, getstroption (CF_SERVERHOST), getstroption (CF_SERVERPORT)); 536 snprintf(consolestr, CONSOLESTRSIZE, getformatstr(FS_CONSOLE), newnick,
570 consoleline (NULL); 537 getstroption(CF_SERVERHOST), getstroption(CF_SERVERPORT));
538 consoleline(NULL);
571 } 539 }
572 540
573 /* show message to user */ 541 /* show message to user */
574 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_NICKCHANGE), oldnick, newnick, msg); 542 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_NICKCHANGE), oldnick, newnick,
575 writechan (tmpstr); 543 msg);
544 writechan(tmpstr);
576} 545}
577 546
578/* handle received message from server */ 547/* handle received message from server */
579void 548void protocol_parsemsg(char *message) {
580protocol_parsemsg (char *message)
581{
582 char *str1, *str2; 549 char *str1, *str2;
583 int i; 550 int i;
584 /* message to short or starts with '<'? must be channel */ 551 /* message to short or starts with '<'? must be channel */
585 if (message[0] == '<') 552 if (message[0] == '<') {
586 {
587 str1 = &message[1]; 553 str1 = &message[1];
588 str2 = strchr(str1,'>'); 554 str2 = strchr(str1, '>');
589 str2[0] = '\0'; 555 str2[0] = '\0';
590 str2++; 556 str2++;
591 if (str2[0] == ' ') str2++; 557 if (str2[0] == ' ')
558 str2++;
592 if (own_nick_check(str1)) 559 if (own_nick_check(str1))
593 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_MYPUBMSG),str1,str2); 560 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_MYPUBMSG), str1, str2);
594 else 561 else
595 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_RXPUBMSG),str1,str2); 562 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_RXPUBMSG), str1, str2);
596 writechan (tmpstr); 563 writechan(tmpstr);
597 564
598 ul_public_action(str1); 565 ul_public_action(str1);
599 } 566 } else if (message[0] == '[') {
600 else if (message[0] == '[')
601 {
602 str1 = &message[1]; 567 str1 = &message[1];
603 str2 = strchr(str1,']'); 568 str2 = strchr(str1, ']');
604 str2[0] = '\0'; 569 str2[0] = '\0';
605 str2++; 570 str2++;
606 if (str2[0] == ' ') str2++; 571 if (str2[0] == ' ')
607 if (own_nick_check( str1 )) 572 str2++;
608 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_MYPUBURL),str1,str2); 573 if (own_nick_check(str1))
574 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_MYPUBURL), str1, str2);
609 else 575 else
610 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_RXPUBURL),str1,str2); 576 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_RXPUBURL), str1, str2);
611 ul_public_action(str1); 577 ul_public_action(str1);
612 writechan (tmpstr); 578 writechan(tmpstr);
613 } 579 }
614 /* message starts with '*'? must be private */ 580 /* message starts with '*'? must be private */
615 else if (message[0] == '*') 581 else if (message[0] == '*') {
616 {
617 str1 = &message[1]; 582 str1 = &message[1];
618 str2 = strchr(str1,'*'); 583 str2 = strchr(str1, '*');
619 str2[0] = '\0'; 584 str2[0] = '\0';
620 str2++; 585 str2++;
621 if (str2[0] == ' ') str2++; 586 if (str2[0] == ' ')
622 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_RXPRIVMSG),str1,str2); 587 str2++;
623 writepriv (tmpstr, 1); 588 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_RXPRIVMSG), str1, str2);
589 writepriv(tmpstr, 1);
624 ul_private_action(str1); 590 ul_private_action(str1);
625 } 591 }
626 /* message starts with a number? must be a servermessage */ 592 /* message starts with a number? must be a servermessage */
627 else if ((message[0] >= '0') && (message[0] <= '9')) 593 else if ((message[0] >= '0') && (message[0] <= '9')) {
628 { 594 /* walk server message array */
629 /* walk server message array */ 595 for (i = 0; servermessages[i].id[0]; i++) {
630 for (i = 0; servermessages[i].id[0]; i++) 596 /* is this the message? */
631 { 597 if (!(strncmp(servermessages[i].id, message, 3))) {
632 /* is this the message? */ 598 /* scripting hook available - call it */
633 if (!(strncmp (servermessages[i].id, message, 3))) 599 if (servermessages[i].hook)
634 { 600 servermessages[i].hook(message);
635 /* scripting hook available - call it */ 601 /* function available - call it */
636 if (servermessages[i].hook) 602 else if (servermessages[i].funct)
637 servermessages[i].hook (message); 603 servermessages[i].funct(message);
638 /* function available - call it */ 604 /* no function available, but known - give output */
639 else if (servermessages[i].funct) 605 else {
640 servermessages[i].funct (message); 606 /* remove continutation mark */
641 /* no function available, but known - give output */ 607 if (message[3] == '-')
642 else 608 message[3] = ' ';
643 { 609
644 /* remove continutation mark */ 610 /* mutate message for display */
645 if (message[3] == '-') 611 message[2] = '*';
646 message[3] = ' '; 612 /* giveout message by type */
647 613 switch (servermessages[i].type) {
648 /* mutate message for display */ 614 case SM_IGNORE:
649 message[2] = '*'; 615 break;
650 /* giveout message by type */ 616 case SM_INFO:
651 switch (servermessages[i].type) 617 /* change marker and send as servermessage */
652 { 618 message[2] = '#';
653 case SM_IGNORE: 619 writecf(FS_SERV, &message[2]);
654 break; 620 break;
655 case SM_INFO: 621 case SM_USERINFO:
656 /* change marker and send as servermessage */ 622 /* keep marker and send as servermessage */
657 message[2] = '#'; 623 writecf(FS_SERV, &message[2]);
658 writecf (FS_SERV,&message[2]); 624 break;
659 break; 625 case SM_CHANNEL:
660 case SM_USERINFO: 626 /* keep marker and send as channelmessage */
661 /* keep marker and send as servermessage */ 627 writechan(&message[2]);
662 writecf (FS_SERV,&message[2]); 628 break;
663 break; 629 case SM_ERROR:
664 case SM_CHANNEL: 630 /* change marker and send as errormessage */
665 /* keep marker and send as channelmessage */ 631 message[2] = '!';
666 writechan (&message[2]); 632 writecf(FS_ERR, &message[2]);
667 break; 633 break;
668 case SM_ERROR: 634 default:
669 /* change marker and send as errormessage */ 635 /* fallback: keep marker and send as servermessage */
670 message[2] = '!'; 636 writecf(FS_SERV, &message[2]);
671 writecf (FS_ERR,&message[2]); 637 }
672 break; 638 }
673 default: 639 return;
674 /* fallback: keep marker and send as servermessage */ 640 }
675 writecf (FS_SERV,&message[2]);
676 }
677 }
678 return;
679 }
680 }
681 /* message not in list, raise errormessage */
682 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_UNKNOWNMSG), message);
683 writecf (FS_ERR,tmpstr);
684 }
685 else
686 {
687 /* message neither public, private or server, raise errormessage */
688 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_BOGUSMSG), message);
689 writecf (FS_ERR,tmpstr);
690 } 641 }
642 /* message not in list, raise errormessage */
643 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_UNKNOWNMSG), message);
644 writecf(FS_ERR, tmpstr);
645 } else {
646 /* message neither public, private or server, raise errormessage */
647 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_BOGUSMSG), message);
648 writecf(FS_ERR, tmpstr);
649 }
691} 650}
692
diff --git a/vchat-tls.c b/vchat-tls.c
index 7b0f1fa..187f10b 100755
--- a/vchat-tls.c
+++ b/vchat-tls.c
@@ -15,663 +15,703 @@
15 * 15 *
16 */ 16 */
17 17
18#include <assert.h>
19#include <errno.h>
18#include <stdio.h> 20#include <stdio.h>
19#include <stdlib.h> 21#include <stdlib.h>
20#include <string.h> 22#include <string.h>
21#include <assert.h>
22#include <errno.h>
23 23
24#include <readline/readline.h> 24#include <readline/readline.h>
25 25
26#include "vchat.h"
27#include "vchat-tls.h" 26#include "vchat-tls.h"
27#include "vchat.h"
28 28
29const char *vchat_tls_version = "vchat-tls.c $Id$"; 29const char *vchat_tls_version =
30const char *vchat_tls_version_external = "Unknown implementation; version unknown"; 30 "vchat-tls.c $Id$";
31const char *vchat_tls_version_external =
32 "Unknown implementation; version unknown";
31 33
32/* Helpers to work with vc_x509store_t used by all tls libs */ 34/* Helpers to work with vc_x509store_t used by all tls libs */
33void vc_cleanup_x509store(vc_x509store_t *store) { 35void vc_cleanup_x509store(vc_x509store_t *store) {
34 free(store->cafile); 36 free(store->cafile);
35 free(store->capath); 37 free(store->capath);
36 free(store->crlfile); 38 free(store->crlfile);
37 free(store->certfile); 39 free(store->certfile);
38 free(store->keyfile); 40 free(store->keyfile);
39 memset(store, 0, sizeof(vc_x509store_t)); 41 memset(store, 0, sizeof(vc_x509store_t));
40} 42}
41 43
42void vc_x509store_setflags(vc_x509store_t *store, int flags) { store->flags |= flags; } 44void vc_x509store_setflags(vc_x509store_t *store, int flags) {
43void vc_x509store_clearflags(vc_x509store_t *store, int flags) { store->flags &= ~flags; } 45 store->flags |= flags;
44void vc_x509store_set_pkeycb(vc_x509store_t *store, vc_askpass_cb_t callback) { store->askpass_callback = callback; } 46}
47void vc_x509store_clearflags(vc_x509store_t *store, int flags) {
48 store->flags &= ~flags;
49}
50void vc_x509store_set_pkeycb(vc_x509store_t *store, vc_askpass_cb_t callback) {
51 store->askpass_callback = callback;
52}
45 53
46void vc_x509store_setcafile(vc_x509store_t *store, char *file) { 54void vc_x509store_setcafile(vc_x509store_t *store, char *file) {
47 free(store->cafile); 55 free(store->cafile);
48 store->cafile = ( file ? strdup(file) : 0 ); 56 store->cafile = (file ? strdup(file) : 0);
49 store->flags |= VC_X509S_USE_CAFILE; 57 store->flags |= VC_X509S_USE_CAFILE;
50} 58}
51 59
52void vc_x509store_setcapath(vc_x509store_t *store, char *path) { 60void vc_x509store_setcapath(vc_x509store_t *store, char *path) {
53 free(store->capath); 61 free(store->capath);
54 store->capath = ( path ? strdup(path) : 0 ); 62 store->capath = (path ? strdup(path) : 0);
55} 63}
56 64
57void vc_x509store_setcrlfile(vc_x509store_t *store, char *file) { 65void vc_x509store_setcrlfile(vc_x509store_t *store, char *file) {
58 free(store->crlfile); 66 free(store->crlfile);
59 store->crlfile = ( file ? strdup(file) : 0 ); 67 store->crlfile = (file ? strdup(file) : 0);
60} 68}
61 69
62void vc_x509store_setkeyfile(vc_x509store_t *store, char *file) { 70void vc_x509store_setkeyfile(vc_x509store_t *store, char *file) {
63 free(store->keyfile); 71 free(store->keyfile);
64 store->keyfile = ( file ? strdup(file) : 0 ); 72 store->keyfile = (file ? strdup(file) : 0);
65} 73}
66 74
67void vc_x509store_setcertfile(vc_x509store_t *store, char *file) { 75void vc_x509store_setcertfile(vc_x509store_t *store, char *file) {
68 free(store->certfile); 76 free(store->certfile);
69 store->certfile = ( file ? strdup(file) : 0 ); 77 store->certfile = (file ? strdup(file) : 0);
70 store->flags |= VC_X509S_USE_CERTIFICATE; 78 store->flags |= VC_X509S_USE_CERTIFICATE;
71} 79}
72 80
73static int verify_or_store_fingerprint(const char *fingerprint) { 81static int verify_or_store_fingerprint(const char *fingerprint) {
74 char *fingerprint_file_path = tilde_expand(getstroption(CF_FINGERPRINT)); 82 char *fingerprint_file_path = tilde_expand(getstroption(CF_FINGERPRINT));
75 if (!fingerprint_file_path) { 83 if (!fingerprint_file_path) {
76 writecf(FS_ERR, "Error: The CF_FINGERPRINT path is not set but CF_PINFINGER was requested."); 84 writecf(FS_ERR, "Error: The CF_FINGERPRINT path is not set but "
77 return -1; 85 "CF_PINFINGER was requested.");
86 return -1;
87 }
88
89 FILE *fingerprint_file = fopen(fingerprint_file_path, "r");
90 if (fingerprint_file) {
91 /* Read fingerprint from file */
92 char old_fingerprint[128];
93 char *r = fgets(old_fingerprint, sizeof(old_fingerprint), fingerprint_file);
94 fclose(fingerprint_file);
95
96 if (r) {
97 /* chomp */
98 char *nl = strchr(r, '\n');
99 if (nl)
100 *nl = 0;
101
102 /* verify fingerprint matches stored version */
103 if (!strcmp(fingerprint, old_fingerprint)) {
104 writecf(FS_SERV, "[FINGERPRINT MATCH ]");
105 goto cleanup_happy;
106 }
78 } 107 }
79 108
80 FILE *fingerprint_file = fopen(fingerprint_file_path, "r"); 109 snprintf(tmpstr, TMPSTRSIZE,
81 if (fingerprint_file) { 110 "Error: Found pinned fingerprint (in %s) %s but expected %s",
82 /* Read fingerprint from file */ 111 r ? old_fingerprint : "<FILE READ ERROR>",
83 char old_fingerprint[128]; 112 getstroption(CF_FINGERPRINT), fingerprint);
84 char * r = fgets(old_fingerprint, sizeof(old_fingerprint), fingerprint_file); 113 writecf(FS_ERR, tmpstr);
85 fclose(fingerprint_file); 114 writecf(FS_ERR, "Error: Fingerprint mismatch! Server cert updated?");
86
87 if (r) {
88 /* chomp */
89 char *nl = strchr(r, '\n');
90 if (nl) *nl = 0;
91
92 /* verify fingerprint matches stored version */
93 if (!strcmp(fingerprint, old_fingerprint)) {
94 writecf(FS_SERV, "[FINGERPRINT MATCH ]");
95 goto cleanup_happy;
96 }
97 }
98
99 snprintf(tmpstr, TMPSTRSIZE, "Error: Found pinned fingerprint (in %s) %s but expected %s", r ? old_fingerprint : "<FILE READ ERROR>", getstroption(CF_FINGERPRINT), fingerprint);
100 writecf(FS_ERR, tmpstr);
101 writecf(FS_ERR, "Error: Fingerprint mismatch! Server cert updated?");
102 free(fingerprint_file_path);
103 return 1;
104 } else
105 writecf(FS_ERR, "Warning: No pinned fingerprint found, writing the current one.");
106
107 fingerprint_file = fopen(fingerprint_file_path, "w");
108 if (!fingerprint_file) {
109 snprintf (tmpstr, TMPSTRSIZE, "Warning: Can't write fingerprint file, %s.", strerror(errno));
110 writecf(FS_ERR, tmpstr);
111 } else {
112 fputs(fingerprint, fingerprint_file);
113 fclose(fingerprint_file);
114 writecf(FS_SERV, "[FINGERPRINT STORED ]");
115 }
116cleanup_happy:
117 free(fingerprint_file_path); 115 free(fingerprint_file_path);
118 return 0; 116 return 1;
117 } else
118 writecf(FS_ERR,
119 "Warning: No pinned fingerprint found, writing the current one.");
120
121 fingerprint_file = fopen(fingerprint_file_path, "w");
122 if (!fingerprint_file) {
123 snprintf(tmpstr, TMPSTRSIZE, "Warning: Can't write fingerprint file, %s.",
124 strerror(errno));
125 writecf(FS_ERR, tmpstr);
126 } else {
127 fputs(fingerprint, fingerprint_file);
128 fclose(fingerprint_file);
129 writecf(FS_SERV, "[FINGERPRINT STORED ]");
130 }
131cleanup_happy:
132 free(fingerprint_file_path);
133 return 0;
119} 134}
120 135
121#if defined(TLS_LIB_OPENSSL) && defined(TLS_LIB_MBEDTLS) 136#if defined(TLS_LIB_OPENSSL) && defined(TLS_LIB_MBEDTLS)
122#error "Both TLS_LIB_OPENSSL and TLS_LIB_MBEDTLS are defined. Please select only one." 137#error \
138 "Both TLS_LIB_OPENSSL and TLS_LIB_MBEDTLS are defined. Please select only one."
123#endif 139#endif
124#if !defined(TLS_LIB_OPENSSL) && !defined(TLS_LIB_MBEDTLS) 140#if !defined(TLS_LIB_OPENSSL) && !defined(TLS_LIB_MBEDTLS)
125#error "Neither TLS_LIB_OPENSSL nor TLS_LIB_MBEDTLS are defined. Please select exactly one." 141#error \
142 "Neither TLS_LIB_OPENSSL nor TLS_LIB_MBEDTLS are defined. Please select exactly one."
126#endif 143#endif
127 144
128#ifdef TLS_LIB_OPENSSL 145#ifdef TLS_LIB_OPENSSL
129 146
130#include <openssl/err.h>
131#include <openssl/ssl.h>
132#include <openssl/bio.h> 147#include <openssl/bio.h>
148#include <openssl/conf.h>
149#include <openssl/err.h>
133#include <openssl/evp.h> 150#include <openssl/evp.h>
151#include <openssl/ssl.h>
134#include <openssl/x509.h> 152#include <openssl/x509.h>
135#include <openssl/x509v3.h> 153#include <openssl/x509v3.h>
136#include <openssl/conf.h>
137 154
138void vchat_tls_get_version_external() 155void vchat_tls_get_version_external() {
139{ 156 snprintf(tmpstr, sizeof(tmpstr), "OpenSSL %s with %s",
140 snprintf(tmpstr, sizeof(tmpstr), "OpenSSL %s with %s", SSLeay_version(SSLEAY_VERSION), SSLeay_version(SSLEAY_CFLAGS)); 157 SSLeay_version(SSLEAY_VERSION), SSLeay_version(SSLEAY_CFLAGS));
141 vchat_tls_version_external = strdup(tmpstr); 158 vchat_tls_version_external = strdup(tmpstr);
142} 159}
143 160
144void vc_init_x509store(vc_x509store_t *store) 161void vc_init_x509store(vc_x509store_t *store) {
145{ 162 static int sslinit;
146 static int sslinit; 163 if (!sslinit++) {
147 if (!sslinit++) { 164 SSL_library_init();
148 SSL_library_init (); 165 SSL_load_error_strings();
149 SSL_load_error_strings(); 166 }
150 } 167 memset(store, 0, sizeof(vc_x509store_t));
151 memset(store, 0, sizeof(vc_x509store_t));
152 168
153 /* We want to make verifying the peer the default */ 169 /* We want to make verifying the peer the default */
154 store->flags |= VC_X509S_SSL_VERIFY_PEER; 170 store->flags |= VC_X509S_SSL_VERIFY_PEER;
155} 171}
156 172
157/* connection BIO for openssl */ 173/* connection BIO for openssl */
158static BIO *server_conn = NULL; 174static BIO *server_conn = NULL;
159 175
160static SSL_CTX * vc_create_sslctx( vc_x509store_t *vc_store ); 176static SSL_CTX *vc_create_sslctx(vc_x509store_t *vc_store);
161static int vc_verify_callback(int, X509_STORE_CTX *); 177static int vc_verify_callback(int, X509_STORE_CTX *);
162static X509_STORE * vc_x509store_create(vc_x509store_t *); 178static X509_STORE *vc_x509store_create(vc_x509store_t *);
163
164static SSL_CTX * vc_create_sslctx( vc_x509store_t *vc_store )
165{
166 int flags = 0;
167
168 /* Explicitly use TLSv1 (or maybe later) */
169 SSL_CTX *ctx = SSL_CTX_new(TLS_client_method());
170 X509_STORE *store = vc_x509store_create(vc_store);
171
172 if (!ctx || !store) {
173 snprintf(tmpstr, sizeof(tmpstr), "CREATE CTX: %s",ERR_error_string (ERR_get_error (), NULL));
174 writecf(FS_ERR, tmpstr);
175 if (store)
176 X509_STORE_free(store);
177 if (ctx)
178 SSL_CTX_free(ctx);
179 return NULL;
180 }
181
182 SSL_CTX_set_cert_store(ctx, store);
183
184 /* Disable some insecure protocols explicitly */
185 SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
186 if (getstroption(CF_CIPHERSUITE))
187 SSL_CTX_set_cipher_list(ctx, getstroption(CF_CIPHERSUITE));
188 else
189 SSL_CTX_set_cipher_list(ctx, "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA");
190
191 SSL_CTX_set_verify_depth (ctx, getintoption(CF_VERIFYSSL));
192
193 if( !(vc_store->flags & VC_X509S_SSL_VERIFY_MASK) ) {
194 writecf(FS_DBG, tmpstr);
195 flags = SSL_VERIFY_NONE;
196 } else {
197 if(vc_store->flags & VC_X509S_SSL_VERIFY_PEER)
198 flags |= SSL_VERIFY_PEER;
199 if(vc_store->flags & VC_X509S_SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
200 flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
201 if(vc_store->flags & VC_X509S_SSL_VERIFY_CLIENT_ONCE)
202 flags |= SSL_VERIFY_CLIENT_ONCE;
203 }
204
205 SSL_CTX_set_verify(ctx, flags, vc_verify_callback);
206
207 if(vc_store->flags & VC_X509S_USE_CERTIFICATE) {
208 int r = 0;
209 if(vc_store->certfile)
210 SSL_CTX_use_certificate_chain_file(ctx, vc_store->certfile);
211 179
212 SSL_CTX_set_default_passwd_cb(ctx, vc_store->askpass_callback); 180static SSL_CTX *vc_create_sslctx(vc_x509store_t *vc_store) {
181 int flags = 0;
213 182
214 if(vc_store->keyfile) 183 /* Explicitly use TLSv1 (or maybe later) */
215 r=SSL_CTX_use_PrivateKey_file(ctx, vc_store->keyfile, 184 SSL_CTX *ctx = SSL_CTX_new(TLS_client_method());
216 SSL_FILETYPE_PEM); 185 X509_STORE *store = vc_x509store_create(vc_store);
217 186
218 if( r!=1 || !SSL_CTX_check_private_key(ctx)) { 187 if (!ctx || !store) {
219 snprintf(tmpstr, sizeof(tmpstr), "CREATE CTX: Load private key failed"); 188 snprintf(tmpstr, sizeof(tmpstr), "CREATE CTX: %s",
220 writecf(FS_ERR, tmpstr); 189 ERR_error_string(ERR_get_error(), NULL));
221 SSL_CTX_free(ctx); 190 writecf(FS_ERR, tmpstr);
222 return NULL; 191 if (store)
223 } 192 X509_STORE_free(store);
193 if (ctx)
194 SSL_CTX_free(ctx);
195 return NULL;
196 }
197
198 SSL_CTX_set_cert_store(ctx, store);
199
200 /* Disable some insecure protocols explicitly */
201 SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
202 if (getstroption(CF_CIPHERSUITE))
203 SSL_CTX_set_cipher_list(ctx, getstroption(CF_CIPHERSUITE));
204 else
205 SSL_CTX_set_cipher_list(ctx,
206 "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA");
207
208 SSL_CTX_set_verify_depth(ctx, getintoption(CF_VERIFYSSL));
209
210 if (!(vc_store->flags & VC_X509S_SSL_VERIFY_MASK)) {
211 writecf(FS_DBG, tmpstr);
212 flags = SSL_VERIFY_NONE;
213 } else {
214 if (vc_store->flags & VC_X509S_SSL_VERIFY_PEER)
215 flags |= SSL_VERIFY_PEER;
216 if (vc_store->flags & VC_X509S_SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
217 flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
218 if (vc_store->flags & VC_X509S_SSL_VERIFY_CLIENT_ONCE)
219 flags |= SSL_VERIFY_CLIENT_ONCE;
220 }
221
222 SSL_CTX_set_verify(ctx, flags, vc_verify_callback);
223
224 if (vc_store->flags & VC_X509S_USE_CERTIFICATE) {
225 int r = 0;
226 if (vc_store->certfile)
227 SSL_CTX_use_certificate_chain_file(ctx, vc_store->certfile);
228
229 SSL_CTX_set_default_passwd_cb(ctx, vc_store->askpass_callback);
230
231 if (vc_store->keyfile)
232 r = SSL_CTX_use_PrivateKey_file(ctx, vc_store->keyfile, SSL_FILETYPE_PEM);
233
234 if (r != 1 || !SSL_CTX_check_private_key(ctx)) {
235 snprintf(tmpstr, sizeof(tmpstr), "CREATE CTX: Load private key failed");
236 writecf(FS_ERR, tmpstr);
237 SSL_CTX_free(ctx);
238 return NULL;
224 } 239 }
240 }
225 241
226 SSL_CTX_set_app_data(ctx, vc_store); 242 SSL_CTX_set_app_data(ctx, vc_store);
227 return(ctx); 243 return (ctx);
228} 244}
229 245
230int vc_tls_connect( int serverfd, vc_x509store_t *vc_store ) 246int vc_tls_connect(int serverfd, vc_x509store_t *vc_store) {
231{ 247 SSL_CTX *ctx = vc_create_sslctx(vc_store);
232 SSL_CTX * ctx = vc_create_sslctx(vc_store); 248 X509 *peercert = NULL;
233 X509 *peercert = NULL; 249 BIO *ssl_conn = NULL;
234 BIO *ssl_conn = NULL; 250 const SSL *sslp = NULL;
235 const SSL *sslp = NULL; 251 const SSL_CIPHER *cipher = NULL;
236 const SSL_CIPHER * cipher = NULL;
237
238 server_conn = BIO_new_socket( serverfd, 1 );
239
240 /* To display and check server fingerprint */
241 char fingerprint[EVP_MAX_MD_SIZE*4];
242 unsigned char fingerprint_bin[EVP_MAX_MD_SIZE];
243 unsigned int fingerprint_len;
244 252
245 char * fp = fingerprint; 253 server_conn = BIO_new_socket(serverfd, 1);
246 254
247 long j; 255 /* To display and check server fingerprint */
256 char fingerprint[EVP_MAX_MD_SIZE * 4];
257 unsigned char fingerprint_bin[EVP_MAX_MD_SIZE];
258 unsigned int fingerprint_len;
248 259
249 if( !ctx ) 260 char *fp = fingerprint;
250 goto all_errors;
251 261
252 ssl_conn = BIO_new_ssl(ctx, 1); 262 long j;
253 SSL_CTX_free(ctx);
254 263
255 if( !ssl_conn ) 264 if (!ctx)
256 goto ssl_error; 265 goto all_errors;
257 266
258 BIO_push( ssl_conn, server_conn ); 267 ssl_conn = BIO_new_ssl(ctx, 1);
259 server_conn = ssl_conn; 268 SSL_CTX_free(ctx);
260 fflush(stdout);
261 269
262 if( BIO_do_handshake( server_conn ) <= 0 ) 270 if (!ssl_conn)
263 goto ssl_error; 271 goto ssl_error;
264 272
265 /* Show information about cipher used */ 273 BIO_push(ssl_conn, server_conn);
266 /* Get cipher object */ 274 server_conn = ssl_conn;
267 BIO_get_ssl(ssl_conn, &sslp); 275 fflush(stdout);
268 if (!sslp)
269 goto ssl_error;
270 276
271 cipher = SSL_get_current_cipher(sslp); 277 if (BIO_do_handshake(server_conn) <= 0)
272 if (cipher) { 278 goto ssl_error;
273 char cipher_desc[TMPSTRSIZE];
274 snprintf(tmpstr, TMPSTRSIZE, "[SSL CIPHER ] %s", SSL_CIPHER_description(cipher, cipher_desc, TMPSTRSIZE));
275 writecf(FS_SERV, tmpstr);
276 } else {
277 snprintf(tmpstr, TMPSTRSIZE, "[SSL ERROR ] Cipher not known / SSL object can't be queried!");
278 writecf(FS_ERR, tmpstr);
279 }
280 279
281 /* Accept being connected, _if_ verification passed */ 280 /* Show information about cipher used */
282 peercert = SSL_get_peer_certificate(sslp); 281 /* Get cipher object */
283 if (!peercert) 282 BIO_get_ssl(ssl_conn, &sslp);
284 goto ssl_error; 283 if (!sslp)
284 goto ssl_error;
285 285
286 /* show basic information about peer cert */ 286 cipher = SSL_get_current_cipher(sslp);
287 snprintf(tmpstr, TMPSTRSIZE, "[SSL SUBJECT ] %s", X509_NAME_oneline(X509_get_subject_name(peercert),0,0)); 287 if (cipher) {
288 writecf(FS_SERV, tmpstr); 288 char cipher_desc[TMPSTRSIZE];
289 snprintf(tmpstr, TMPSTRSIZE, "[SSL ISSUER ] %s", X509_NAME_oneline(X509_get_issuer_name(peercert),0,0)); 289 snprintf(tmpstr, TMPSTRSIZE, "[SSL CIPHER ] %s",
290 SSL_CIPHER_description(cipher, cipher_desc, TMPSTRSIZE));
290 writecf(FS_SERV, tmpstr); 291 writecf(FS_SERV, tmpstr);
292 } else {
293 snprintf(
294 tmpstr, TMPSTRSIZE,
295 "[SSL ERROR ] Cipher not known / SSL object can't be queried!");
296 writecf(FS_ERR, tmpstr);
297 }
298
299 /* Accept being connected, _if_ verification passed */
300 peercert = SSL_get_peer_certificate(sslp);
301 if (!peercert)
302 goto ssl_error;
303
304 /* show basic information about peer cert */
305 snprintf(tmpstr, TMPSTRSIZE, "[SSL SUBJECT ] %s",
306 X509_NAME_oneline(X509_get_subject_name(peercert), 0, 0));
307 writecf(FS_SERV, tmpstr);
308 snprintf(tmpstr, TMPSTRSIZE, "[SSL ISSUER ] %s",
309 X509_NAME_oneline(X509_get_issuer_name(peercert), 0, 0));
310 writecf(FS_SERV, tmpstr);
311
312 /* calculate fingerprint */
313 if (!X509_digest(peercert, EVP_sha1(), fingerprint_bin, &fingerprint_len))
314 goto ssl_error;
315
316 assert((fingerprint_len > 1) && (fingerprint_len <= EVP_MAX_MD_SIZE));
317 for (j = 0; j < (int)fingerprint_len; j++)
318 fp += sprintf(fp, "%02X:", fingerprint_bin[j]);
319 assert(fp > fingerprint);
320 fp[-1] = 0;
321 snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] %s (from server)",
322 fingerprint);
323 writecf(FS_SERV, tmpstr);
324
325 /* we don't need the peercert anymore */
326 X509_free(peercert);
327
328 if (getintoption(CF_PINFINGER) && verify_or_store_fingerprint(fingerprint))
329 return 1;
291 330
292 /* calculate fingerprint */ 331 /* If verify of x509 chain was requested, do the check here */
293 if (!X509_digest(peercert,EVP_sha1(),fingerprint_bin,&fingerprint_len)) 332 if (X509_V_OK == SSL_get_verify_result(sslp))
294 goto ssl_error; 333 return 0;
295
296 assert ( ( fingerprint_len > 1 ) && (fingerprint_len <= EVP_MAX_MD_SIZE ));
297 for (j=0; j<(int)fingerprint_len; j++)
298 fp += sprintf(fp, "%02X:", fingerprint_bin[j]);
299 assert ( fp > fingerprint );
300 fp[-1] = 0;
301 snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] %s (from server)", fingerprint);
302 writecf(FS_SERV, tmpstr);
303
304 /* we don't need the peercert anymore */
305 X509_free(peercert);
306
307 if (getintoption(CF_PINFINGER) && verify_or_store_fingerprint(fingerprint))
308 return 1;
309
310 /* If verify of x509 chain was requested, do the check here */
311 if (X509_V_OK == SSL_get_verify_result(sslp))
312 return 0;
313 334
314 if (getintoption(CF_IGNSSL)) { 335 if (getintoption(CF_IGNSSL)) {
315 writecf(FS_ERR, "[SSL VERIFY ERROR ] FAILURE IGNORED!!!"); 336 writecf(FS_ERR, "[SSL VERIFY ERROR ] FAILURE IGNORED!!!");
316 return 0; 337 return 0;
317 } 338 }
318 339
319ssl_error: 340ssl_error:
320 snprintf(tmpstr, TMPSTRSIZE, "[SSL CONNECT ERROR] %s", ERR_error_string (ERR_get_error (), NULL)); 341 snprintf(tmpstr, TMPSTRSIZE, "[SSL CONNECT ERROR] %s",
321 writecf(FS_ERR, tmpstr); 342 ERR_error_string(ERR_get_error(), NULL));
343 writecf(FS_ERR, tmpstr);
322all_errors: 344all_errors:
323 BIO_free_all( server_conn ); 345 BIO_free_all(server_conn);
324 server_conn = NULL; 346 server_conn = NULL;
325 return 1; 347 return 1;
326} 348}
327 349
328#define VC_STORE_ERR_EXIT(s) do { \ 350#define VC_STORE_ERR_EXIT(s) \
329 fprintf(stderr, "[E] SSL_STORE: %s\n", ERR_error_string (ERR_get_error (), NULL)); \ 351 do { \
330 if(s) X509_STORE_free(s); \ 352 fprintf(stderr, "[E] SSL_STORE: %s\n", \
331 return(0); \ 353 ERR_error_string(ERR_get_error(), NULL)); \
332} while(0) 354 if (s) \
355 X509_STORE_free(s); \
356 return (0); \
357 } while (0)
333 358
334X509_STORE *vc_x509store_create(vc_x509store_t *vc_store) { 359X509_STORE *vc_x509store_create(vc_x509store_t *vc_store) {
335 X509_STORE *store = NULL; 360 X509_STORE *store = NULL;
336 X509_LOOKUP *lookup = NULL; 361 X509_LOOKUP *lookup = NULL;
337 362
338 store = X509_STORE_new(); 363 store = X509_STORE_new();
339 364
340 X509_STORE_set_verify_cb_func(store, vc_verify_callback); 365 X509_STORE_set_verify_cb_func(store, vc_verify_callback);
341 366
342 if( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) ) 367 if (!(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())))
343 VC_STORE_ERR_EXIT(store); 368 VC_STORE_ERR_EXIT(store);
344 369
345 if (!vc_store->cafile) { 370 if (!vc_store->cafile) {
346 if( !(vc_store->flags & VC_X509S_USE_CAFILE) ) 371 if (!(vc_store->flags & VC_X509S_USE_CAFILE))
347 X509_LOOKUP_load_file(lookup, 0, X509_FILETYPE_DEFAULT); 372 X509_LOOKUP_load_file(lookup, 0, X509_FILETYPE_DEFAULT);
348 } else if( !X509_LOOKUP_load_file(lookup, vc_store->cafile, 373 } else if (!X509_LOOKUP_load_file(lookup, vc_store->cafile,
349 X509_FILETYPE_PEM) ) 374 X509_FILETYPE_PEM))
350 VC_STORE_ERR_EXIT(store); 375 VC_STORE_ERR_EXIT(store);
351 376
352 if (vc_store->crlfile) { 377 if (vc_store->crlfile) {
353 if( !X509_load_crl_file(lookup, vc_store->crlfile, 378 if (!X509_load_crl_file(lookup, vc_store->crlfile, X509_FILETYPE_PEM))
354 X509_FILETYPE_PEM) ) 379 VC_STORE_ERR_EXIT(store);
355 VC_STORE_ERR_EXIT(store);
356 380
357 X509_STORE_set_flags( store, 381 X509_STORE_set_flags(store,
358 X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL ); 382 X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
359 } 383 }
360 384
361 if ( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir())) ) 385 if (!(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir())))
362 VC_STORE_ERR_EXIT(store); 386 VC_STORE_ERR_EXIT(store);
363 387
364 if ( !vc_store->capath ) { 388 if (!vc_store->capath) {
365 if( !(vc_store->flags & VC_X509S_USE_CAPATH) ) 389 if (!(vc_store->flags & VC_X509S_USE_CAPATH))
366 X509_LOOKUP_add_dir(lookup, 0, X509_FILETYPE_DEFAULT); 390 X509_LOOKUP_add_dir(lookup, 0, X509_FILETYPE_DEFAULT);
367 } else if( !X509_LOOKUP_add_dir(lookup, vc_store->capath, 391 } else if (!X509_LOOKUP_add_dir(lookup, vc_store->capath, X509_FILETYPE_PEM))
368 X509_FILETYPE_PEM) ) 392 VC_STORE_ERR_EXIT(store);
369 VC_STORE_ERR_EXIT(store);
370 393
371 return(store); 394 return (store);
372} 395}
373 396
374int vc_verify_callback(int ok, X509_STORE_CTX *store) { 397int vc_verify_callback(int ok, X509_STORE_CTX *store) {
375 if(!ok) { 398 if (!ok) {
376 snprintf(tmpstr, TMPSTRSIZE, "[SSL VERIFY ERROR ] %s", 399 snprintf(tmpstr, TMPSTRSIZE, "[SSL VERIFY ERROR ] %s",
377 X509_verify_cert_error_string(X509_STORE_CTX_get_error(store))); 400 X509_verify_cert_error_string(X509_STORE_CTX_get_error(store)));
378 writecf(FS_ERR, tmpstr); 401 writecf(FS_ERR, tmpstr);
379 } 402 }
380 return (ok | getintoption(CF_IGNSSL)); 403 return (ok | getintoption(CF_IGNSSL));
381} 404}
382 405
383ssize_t vc_tls_sendmessage(const void *buf, size_t size) { 406ssize_t vc_tls_sendmessage(const void *buf, size_t size) {
384 return BIO_write(server_conn, buf, size); 407 return BIO_write(server_conn, buf, size);
385} 408}
386 409
387ssize_t vc_tls_receivemessage(void *buf, size_t size) { 410ssize_t vc_tls_receivemessage(void *buf, size_t size) {
388 ssize_t received = (ssize_t)BIO_read (server_conn, buf, size); 411 ssize_t received = (ssize_t)BIO_read(server_conn, buf, size);
389 if (received != 0) 412 if (received != 0)
390 return received; 413 return received;
391 if (BIO_should_retry(server_conn)) 414 if (BIO_should_retry(server_conn))
392 return -2; 415 return -2;
393 return 0; 416 return 0;
394} 417}
395 418
396void vc_tls_cleanup() { 419void vc_tls_cleanup() {
397 BIO_free_all( server_conn ); 420 BIO_free_all(server_conn);
398 server_conn = NULL; 421 server_conn = NULL;
399} 422}
400#endif 423#endif
401 424
402#ifdef TLS_LIB_MBEDTLS 425#ifdef TLS_LIB_MBEDTLS
403 426
427#include "mbedtls/error.h"
428#include "mbedtls/version.h"
429#include <mbedtls/ctr_drbg.h>
430#include <mbedtls/debug.h>
431#include <mbedtls/entropy.h>
432#include <mbedtls/md.h>
404#include <mbedtls/net_sockets.h> 433#include <mbedtls/net_sockets.h>
434#include <mbedtls/pk.h>
405#include <mbedtls/ssl.h> 435#include <mbedtls/ssl.h>
406#include <mbedtls/entropy.h>
407#include <mbedtls/ctr_drbg.h>
408#include <mbedtls/x509.h> 436#include <mbedtls/x509.h>
409#include <mbedtls/pk.h>
410#include <mbedtls/md.h>
411#include <mbedtls/debug.h>
412#include "mbedtls/error.h"
413#include "mbedtls/version.h"
414 437
415#include <sys/socket.h> 438#include <sys/socket.h>
416 439
417const char *DRBG_PERS = "mbed TLS vchat client"; 440const char *DRBG_PERS = "mbed TLS vchat client";
418#define MAX_SUITES 512 441#define MAX_SUITES 512
419typedef struct { 442typedef struct {
420 mbedtls_entropy_context _entropy; 443 mbedtls_entropy_context _entropy;
421 mbedtls_ctr_drbg_context _ctr_drbg; 444 mbedtls_ctr_drbg_context _ctr_drbg;
422 mbedtls_x509_crt _cacert; 445 mbedtls_x509_crt _cacert;
423 mbedtls_x509_crt _cert; 446 mbedtls_x509_crt _cert;
424 mbedtls_pk_context _key; 447 mbedtls_pk_context _key;
425 mbedtls_ssl_context _ssl; 448 mbedtls_ssl_context _ssl;
426 mbedtls_ssl_config _conf; 449 mbedtls_ssl_config _conf;
427 int ciphersuits[MAX_SUITES]; 450 int ciphersuits[MAX_SUITES];
428} mbedstate; 451} mbedstate;
429static mbedstate _mbedtls_state; 452static mbedstate _mbedtls_state;
430 453
431void vchat_tls_get_version_external() 454void vchat_tls_get_version_external() {
432{ 455 snprintf(tmpstr, sizeof(tmpstr), "%s", MBEDTLS_VERSION_STRING_FULL);
433 snprintf(tmpstr, sizeof(tmpstr), "%s", MBEDTLS_VERSION_STRING_FULL); 456 vchat_tls_version_external = strdup(tmpstr);
434 vchat_tls_version_external = strdup(tmpstr);
435} 457}
436 458
437static int static_tcp_recv(void *ctx, unsigned char *buf, size_t len ) { 459static int static_tcp_recv(void *ctx, unsigned char *buf, size_t len) {
438 return recv((int)(intptr_t)ctx, buf, len, 0); 460 return recv((int)(intptr_t)ctx, buf, len, 0);
439} 461}
440static int static_tcp_send(void *ctx, const unsigned char *buf, size_t len ) { 462static int static_tcp_send(void *ctx, const unsigned char *buf, size_t len) {
441 return send((int)(intptr_t)ctx, buf, len, 0); 463 return send((int)(intptr_t)ctx, buf, len, 0);
442} 464}
443static int map_openssl_suite(char *openssl_name); 465static int map_openssl_suite(char *openssl_name);
444void vc_init_x509store(vc_x509store_t *store) 466void vc_init_x509store(vc_x509store_t *store) {
445{ 467 static int sslinit;
446 static int sslinit; 468 if (!sslinit++) {
447 if (!sslinit++) { 469 mbedtls_entropy_init(&_mbedtls_state._entropy);
448 mbedtls_entropy_init(&_mbedtls_state._entropy); 470 mbedtls_ctr_drbg_init(&_mbedtls_state._ctr_drbg);
449 mbedtls_ctr_drbg_init(&_mbedtls_state._ctr_drbg); 471
450 472 mbedtls_ctr_drbg_seed(&_mbedtls_state._ctr_drbg, mbedtls_entropy_func,
451 mbedtls_ctr_drbg_seed(&_mbedtls_state._ctr_drbg, mbedtls_entropy_func, &_mbedtls_state._entropy, 473 &_mbedtls_state._entropy,
452 (const unsigned char *) DRBG_PERS, sizeof (DRBG_PERS)); 474 (const unsigned char *)DRBG_PERS, sizeof(DRBG_PERS));
453 } 475 }
454 memset(store, 0, sizeof(vc_x509store_t)); 476 memset(store, 0, sizeof(vc_x509store_t));
455 477
456 /* We want to make verifying the peer the default */ 478 /* We want to make verifying the peer the default */
457 store->flags |= VC_X509S_SSL_VERIFY_PEER; 479 store->flags |= VC_X509S_SSL_VERIFY_PEER;
458} 480}
459 481
460static void vc_tls_report_error(int error, char *message) { 482static void vc_tls_report_error(int error, char *message) {
461 size_t used = snprintf(tmpstr, sizeof(tmpstr), "Error: %s", message); 483 size_t used = snprintf(tmpstr, sizeof(tmpstr), "Error: %s", message);
462 mbedtls_strerror(error, tmpstr + used, sizeof(tmpstr) - used); 484 mbedtls_strerror(error, tmpstr + used, sizeof(tmpstr) - used);
463 writecf(FS_ERR, tmpstr); 485 writecf(FS_ERR, tmpstr);
464} 486}
465 487
466int vc_tls_connect( int serverfd, vc_x509store_t *vc_store ) 488int vc_tls_connect(int serverfd, vc_x509store_t *vc_store) {
467{ 489 /* Some aliases for shorter references */
468 /* Some aliases for shorter references */ 490 mbedstate *s = &_mbedtls_state;
469 mbedstate *s = &_mbedtls_state; 491 mbedtls_ssl_config *conf = &_mbedtls_state._conf;
470 mbedtls_ssl_config *conf = &_mbedtls_state._conf; 492 mbedtls_ssl_context *ssl = &_mbedtls_state._ssl;
471 mbedtls_ssl_context *ssl = &_mbedtls_state._ssl; 493 int ret, suitecount = 0;
472 int ret, suitecount = 0; 494 char fingerprint[128], *token;
473 char fingerprint[128], *token; 495 uint8_t digest[20];
474 uint8_t digest[20]; 496
475 497 mbedtls_x509_crt_init(&s->_cacert);
476 mbedtls_x509_crt_init(&s->_cacert); 498 mbedtls_x509_crt_init(&s->_cert);
477 mbedtls_x509_crt_init(&s->_cert); 499 mbedtls_pk_init(&s->_key);
478 mbedtls_pk_init(&s->_key); 500 mbedtls_ssl_init(ssl);
479 mbedtls_ssl_init(ssl); 501 mbedtls_ssl_config_init(conf);
480 mbedtls_ssl_config_init(conf); 502
481 503 writecf(FS_SERV, "[SOCKET CONNECTED ]");
482 writecf(FS_SERV, "[SOCKET CONNECTED ]"); 504 writecf(FS_SERV, "[UPGRADING TO TLS ]");
483 writecf(FS_SERV, "[UPGRADING TO TLS ]"); 505
484 506 if ((ret = mbedtls_ssl_config_defaults(conf, MBEDTLS_SSL_IS_CLIENT,
485 if ((ret = mbedtls_ssl_config_defaults(conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { 507 MBEDTLS_SSL_TRANSPORT_STREAM,
486 vc_tls_report_error(ret, "Can not initialise tls parameters, mbedtls reports: "); 508 MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
487 return -1; 509 vc_tls_report_error(ret,
488 } 510 "Can not initialise tls parameters, mbedtls reports: ");
489 511 return -1;
490 /* TODO: Always verify peer */ 512 }
491 mbedtls_ssl_conf_authmode(conf, getintoption(CF_IGNSSL) ? MBEDTLS_SSL_VERIFY_OPTIONAL : MBEDTLS_SSL_VERIFY_REQUIRED); 513
492 mbedtls_ssl_conf_rng(conf, mbedtls_ctr_drbg_random, &s->_ctr_drbg); 514 /* TODO: Always verify peer */
493 515 mbedtls_ssl_conf_authmode(conf, getintoption(CF_IGNSSL)
494 char *ciphers = getstroption(CF_CIPHERSUITE); 516 ? MBEDTLS_SSL_VERIFY_OPTIONAL
495 if (!ciphers) 517 : MBEDTLS_SSL_VERIFY_REQUIRED);
496 ciphers = "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA"; 518 mbedtls_ssl_conf_rng(conf, mbedtls_ctr_drbg_random, &s->_ctr_drbg);
497 ciphers = strdup(ciphers); 519
498 for (token = strtok(ciphers, ":"); token && suitecount < MAX_SUITES - 1; token = strtok(NULL, ":")) { 520 char *ciphers = getstroption(CF_CIPHERSUITE);
499 int suite = mbedtls_ssl_get_ciphersuite_id(token); 521 if (!ciphers)
500 if (!suite) 522 ciphers = "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA";
501 suite = map_openssl_suite(token); 523 ciphers = strdup(ciphers);
502 if (suite) 524 for (token = strtok(ciphers, ":"); token && suitecount < MAX_SUITES - 1;
503 s->ciphersuits[suitecount++] = suite; 525 token = strtok(NULL, ":")) {
526 int suite = mbedtls_ssl_get_ciphersuite_id(token);
527 if (!suite)
528 suite = map_openssl_suite(token);
529 if (suite)
530 s->ciphersuits[suitecount++] = suite;
531 }
532 s->ciphersuits[suitecount++] = 0;
533 free(ciphers);
534
535 mbedtls_ssl_conf_ciphersuites(conf, s->ciphersuits);
536
537 if (vc_store->cafile) {
538 if ((ret = mbedtls_x509_crt_parse_file(&s->_cacert, vc_store->cafile)) !=
539 0) {
540 vc_tls_report_error(ret, "Can not load CA cert, mbedtls reports: ");
541 return -1;
504 } 542 }
505 s->ciphersuits[suitecount++] = 0; 543 mbedtls_ssl_conf_ca_chain(conf, &s->_cacert, NULL);
506 free(ciphers); 544 writecf(FS_SERV, "[CA CERT LOADED ]");
507 545 }
508 mbedtls_ssl_conf_ciphersuites(conf, s->ciphersuits); 546
509 547 if (vc_store->flags & VC_X509S_USE_CERTIFICATE) {
510 if (vc_store->cafile) { 548 char *password = NULL;
511 if ((ret = mbedtls_x509_crt_parse_file(&s->_cacert, vc_store->cafile)) != 0) { 549 char password_buf[1024];
512 vc_tls_report_error(ret, "Can not load CA cert, mbedtls reports: "); 550
513 return -1; 551 if ((ret = mbedtls_x509_crt_parse_file(&s->_cert, vc_store->certfile)) !=
514 } 552 0) {
515 mbedtls_ssl_conf_ca_chain(conf, &s->_cacert, NULL); 553 vc_tls_report_error(ret, "Can not load client cert, mbedtls reports: ");
516 writecf(FS_SERV, "[CA CERT LOADED ]"); 554 return -1;
517 } 555 }
556 writecf(FS_SERV, "[CLIENT CERT LOADED ]");
518 557
519 if (vc_store->flags & VC_X509S_USE_CERTIFICATE) { 558 while (1) {
520 char *password = NULL; 559 if ((ret = mbedtls_pk_parse_keyfile(&s->_key, vc_store->keyfile, password
521 char password_buf[1024];
522
523 if ((ret = mbedtls_x509_crt_parse_file(&s->_cert, vc_store->certfile)) != 0) {
524 vc_tls_report_error(ret, "Can not load client cert, mbedtls reports: ");
525 return -1;
526 }
527 writecf(FS_SERV, "[CLIENT CERT LOADED ]");
528
529 while (1) {
530 if ((ret = mbedtls_pk_parse_keyfile(&s->_key, vc_store->keyfile, password
531#if MBEDTLS_VERSION_MAJOR >= 3 560#if MBEDTLS_VERSION_MAJOR >= 3
532 , mbedtls_ctr_drbg_random, &s->_ctr_drbg 561 ,
562 mbedtls_ctr_drbg_random, &s->_ctr_drbg
533#endif 563#endif
534 )) == 0) 564 )) == 0)
535 break; 565 break;
536 if (ret != MBEDTLS_ERR_PK_PASSWORD_REQUIRED && ret != MBEDTLS_ERR_PK_PASSWORD_MISMATCH) { 566 if (ret != MBEDTLS_ERR_PK_PASSWORD_REQUIRED &&
537 vc_tls_report_error(ret, "Can not load client key, mbedtls reports: "); 567 ret != MBEDTLS_ERR_PK_PASSWORD_MISMATCH) {
538 return -1; 568 vc_tls_report_error(ret, "Can not load client key, mbedtls reports: ");
539 } 569 return -1;
540 if (ret == MBEDTLS_ERR_PK_PASSWORD_MISMATCH) 570 }
541 vc_tls_report_error(ret, "Wrong passphrase, mbedtls reports: "); 571 if (ret == MBEDTLS_ERR_PK_PASSWORD_MISMATCH)
542 vc_store->askpass_callback(password_buf, sizeof(password_buf), 0, NULL); 572 vc_tls_report_error(ret, "Wrong passphrase, mbedtls reports: ");
543 password = password_buf; 573 vc_store->askpass_callback(password_buf, sizeof(password_buf), 0, NULL);
544 } 574 password = password_buf;
545 memset_s(password_buf, sizeof(password_buf), 0, sizeof(password_buf)); 575 }
546 writecf(FS_SERV, "[CLIENT KEY LOADED ]"); 576 memset_s(password_buf, sizeof(password_buf), 0, sizeof(password_buf));
547 577 writecf(FS_SERV, "[CLIENT KEY LOADED ]");
548 578
549#if MBEDTLS_VERSION_MAJOR == 3 && MBEDTLS_VERSION_MINOR == 0 579#if MBEDTLS_VERSION_MAJOR == 3 && MBEDTLS_VERSION_MINOR == 0
550 mbedtls_pk_context *pubkey = &(s->_cert.MBEDTLS_PRIVATE(pk)); 580 mbedtls_pk_context *pubkey = &(s->_cert.MBEDTLS_PRIVATE(pk));
551#else 581#else
552 mbedtls_pk_context *pubkey = &(s->_cert.pk); 582 mbedtls_pk_context *pubkey = &(s->_cert.pk);
553#endif 583#endif
554 584
555 if ((ret = mbedtls_pk_check_pair(pubkey, &s->_key 585 if ((ret = mbedtls_pk_check_pair(pubkey, &s->_key
556#if MBEDTLS_VERSION_MAJOR >= 3 586#if MBEDTLS_VERSION_MAJOR >= 3
557 , mbedtls_ctr_drbg_random, &s->_ctr_drbg 587 ,
588 mbedtls_ctr_drbg_random, &s->_ctr_drbg
558#endif 589#endif
559 )) != 0) { 590 )) != 0) {
560 vc_tls_report_error(ret, "Cert and key mismatch, mbedtls reports: "); 591 vc_tls_report_error(ret, "Cert and key mismatch, mbedtls reports: ");
561 return 1; 592 return 1;
562 }
563
564 if ((ret = mbedtls_ssl_conf_own_cert(conf, &s->_cert, &s->_key)) != 0) {
565 vc_tls_report_error(ret, "Setting key and cert to tls session fails, mbedtls reports: ");
566 return -1;
567 }
568 } 593 }
569 594
570 /* Config constructed, pass to ssl */ 595 if ((ret = mbedtls_ssl_conf_own_cert(conf, &s->_cert, &s->_key)) != 0) {
571 /* Init ssl and config structs and configure ssl ctx */ 596 vc_tls_report_error(
572 if ((ret = mbedtls_ssl_setup(ssl, conf)) != 0) { 597 ret, "Setting key and cert to tls session fails, mbedtls reports: ");
573 vc_tls_report_error(ret, "Can not configure parameters on tls context, mbedtls reports: "); 598 return -1;
574 return -1; 599 }
600 }
601
602 /* Config constructed, pass to ssl */
603 /* Init ssl and config structs and configure ssl ctx */
604 if ((ret = mbedtls_ssl_setup(ssl, conf)) != 0) {
605 vc_tls_report_error(
606 ret, "Can not configure parameters on tls context, mbedtls reports: ");
607 return -1;
608 }
609 /* TODO: mbedtls_ssl_set_hostname(&ssl, SERVER_NAME) */
610
611 mbedtls_ssl_set_bio(ssl, (void *)(intptr_t)serverfd, static_tcp_send,
612 static_tcp_recv, NULL);
613
614 while ((ret = mbedtls_ssl_handshake(ssl)) != 0)
615 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
616 vc_tls_report_error(ret, "TLS handshake failed, mbedtls reports: ");
617 return -1;
575 } 618 }
576 /* TODO: mbedtls_ssl_set_hostname(&ssl, SERVER_NAME) */
577
578 mbedtls_ssl_set_bio(ssl, (void*)(intptr_t)serverfd, static_tcp_send, static_tcp_recv, NULL );
579 619
580 while ((ret = mbedtls_ssl_handshake(ssl)) != 0) 620 writecf(FS_SERV, "[TLS HANDSHAKE DONE ]");
581 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 621 snprintf(tmpstr, TMPSTRSIZE, "[TLS CIPHER SUITE ] %s",
582 vc_tls_report_error(ret, "TLS handshake failed, mbedtls reports: "); 622 mbedtls_ssl_get_ciphersuite(ssl));
583 return -1; 623 writecf(FS_SERV, tmpstr);
584 }
585 624
586 writecf(FS_SERV,"[TLS HANDSHAKE DONE ]"); 625 const mbedtls_x509_crt *peer_cert = mbedtls_ssl_get_peer_cert(ssl);
587 snprintf(tmpstr, TMPSTRSIZE, "[TLS CIPHER SUITE ] %s", mbedtls_ssl_get_ciphersuite(ssl)); 626 mbedtls_x509_crt_info(tmpstr, sizeof(tmpstr), "[TLS PEER INFO ] ",
588 writecf(FS_SERV, tmpstr); 627 peer_cert);
589 628
590 const mbedtls_x509_crt* peer_cert = mbedtls_ssl_get_peer_cert(ssl); 629 for (token = strtok(tmpstr, "\n"); token; token = strtok(NULL, "\n"))
591 mbedtls_x509_crt_info(tmpstr, sizeof(tmpstr), "[TLS PEER INFO ] ", peer_cert); 630 writecf(FS_SERV, token);
592
593 for (token = strtok(tmpstr, "\n"); token; token = strtok(NULL, "\n"))
594 writecf(FS_SERV, token);
595 631
596#if MBEDTLS_VERSION_MAJOR == 3 && MBEDTLS_VERSION_MINOR == 0 632#if MBEDTLS_VERSION_MAJOR == 3 && MBEDTLS_VERSION_MINOR == 0
597 const uint8_t * const rawcert_buf = peer_cert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p); 633 const uint8_t *const rawcert_buf =
598 size_t rawcert_len = peer_cert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len); 634 peer_cert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p);
635 size_t rawcert_len = peer_cert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len);
599#else 636#else
600 const uint8_t * const rawcert_buf = peer_cert->raw.p; 637 const uint8_t *const rawcert_buf = peer_cert->raw.p;
601 size_t rawcert_len = peer_cert->raw.len; 638 size_t rawcert_len = peer_cert->raw.len;
602#endif 639#endif
603 const mbedtls_md_info_t *mdinfo = mbedtls_md_info_from_string("SHA1"); 640 const mbedtls_md_info_t *mdinfo = mbedtls_md_info_from_string("SHA1");
604 if (mdinfo) { 641 if (mdinfo) {
605 mbedtls_md(mdinfo, rawcert_buf, rawcert_len, digest); 642 mbedtls_md(mdinfo, rawcert_buf, rawcert_len, digest);
606 643
607 char *fp = fingerprint; 644 char *fp = fingerprint;
608 for (int j=0; j<mbedtls_md_get_size(mdinfo); j++) 645 for (int j = 0; j < mbedtls_md_get_size(mdinfo); j++)
609 fp += sprintf(fp, "%02X:", digest[j]); 646 fp += sprintf(fp, "%02X:", digest[j]);
610 assert ( fp > fingerprint ); 647 assert(fp > fingerprint);
611 fp[-1] = 0; 648 fp[-1] = 0;
612 snprintf(tmpstr, TMPSTRSIZE, "[TLS FINGERPRINT ] %s (from server)", fingerprint); 649 snprintf(tmpstr, TMPSTRSIZE, "[TLS FINGERPRINT ] %s (from server)",
613 writecf(FS_SERV, tmpstr); 650 fingerprint);
614 651 writecf(FS_SERV, tmpstr);
615 if (getintoption(CF_PINFINGER) && verify_or_store_fingerprint(fingerprint))
616 return 1;
617 } else {
618 writecf(FS_ERR, "Warning: Unable to load SHA-1 md");
619 if (getintoption(CF_PINFINGER)) {
620 writecf(FS_ERR, "ERROR: Can not compute fingerprint, but pinning check is required");
621 return 1;
622 }
623 }
624 652
625 ret = mbedtls_ssl_get_verify_result(ssl); 653 if (getintoption(CF_PINFINGER) && verify_or_store_fingerprint(fingerprint))
626 switch (ret) { 654 return 1;
627 case 0: 655 } else {
628 writecf(FS_SERV, "[TLS HANDSHAKE OK ]"); 656 writecf(FS_ERR, "Warning: Unable to load SHA-1 md");
629 break; 657 if (getintoption(CF_PINFINGER)) {
630 case -1: 658 writecf(
631 writecf(FS_ERR, "Error: TLS verify for an unknown reason"); 659 FS_ERR,
632 return -1; 660 "ERROR: Can not compute fingerprint, but pinning check is required");
633 case MBEDTLS_X509_BADCERT_SKIP_VERIFY: 661 return 1;
634 case MBEDTLS_X509_BADCERT_NOT_TRUSTED:
635 if (getintoption(CF_IGNSSL) || !getintoption(CF_VERIFYSSL))
636 return 0;
637 vc_tls_report_error(ret, "TLS verify failed, mbedtls reports: ");
638 return -1;
639 default:
640 vc_tls_report_error(ret, "TLS verify failed, mbedtls reports: ");
641 return -1;
642 } 662 }
643 663 }
644 return 0; 664
665 ret = mbedtls_ssl_get_verify_result(ssl);
666 switch (ret) {
667 case 0:
668 writecf(FS_SERV, "[TLS HANDSHAKE OK ]");
669 break;
670 case -1:
671 writecf(FS_ERR, "Error: TLS verify for an unknown reason");
672 return -1;
673 case MBEDTLS_X509_BADCERT_SKIP_VERIFY:
674 case MBEDTLS_X509_BADCERT_NOT_TRUSTED:
675 if (getintoption(CF_IGNSSL) || !getintoption(CF_VERIFYSSL))
676 return 0;
677 vc_tls_report_error(ret, "TLS verify failed, mbedtls reports: ");
678 return -1;
679 default:
680 vc_tls_report_error(ret, "TLS verify failed, mbedtls reports: ");
681 return -1;
682 }
683
684 return 0;
645} 685}
646 686
647ssize_t vc_tls_sendmessage(const void *buf, size_t size) { 687ssize_t vc_tls_sendmessage(const void *buf, size_t size) {
648 return mbedtls_ssl_write( &_mbedtls_state._ssl, buf, size); 688 return mbedtls_ssl_write(&_mbedtls_state._ssl, buf, size);
649} 689}
650 690
651ssize_t vc_tls_receivemessage(void *buf, size_t size) { 691ssize_t vc_tls_receivemessage(void *buf, size_t size) {
652 ssize_t received = (ssize_t)mbedtls_ssl_read (&_mbedtls_state._ssl, buf, size); 692 ssize_t received = (ssize_t)mbedtls_ssl_read(&_mbedtls_state._ssl, buf, size);
653 switch (received) { 693 switch (received) {
654 case MBEDTLS_ERR_SSL_WANT_READ: 694 case MBEDTLS_ERR_SSL_WANT_READ:
655 case MBEDTLS_ERR_SSL_WANT_WRITE: 695 case MBEDTLS_ERR_SSL_WANT_WRITE:
656 return -2; 696 return -2;
657 case MBEDTLS_ERR_SSL_CONN_EOF: 697 case MBEDTLS_ERR_SSL_CONN_EOF:
658 case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: 698 case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
659 case 0: 699 case 0:
660 return 0; 700 return 0;
661 default: 701 default:
662 if (received > 0) 702 if (received > 0)
663 return received; 703 return received;
664 return -1; 704 return -1;
665 } 705 }
666} 706}
667 707
668void vc_tls_cleanup() { 708void vc_tls_cleanup() {
669 mbedtls_x509_crt_free(&_mbedtls_state._cacert); 709 mbedtls_x509_crt_free(&_mbedtls_state._cacert);
670 mbedtls_x509_crt_free(&_mbedtls_state._cert); 710 mbedtls_x509_crt_free(&_mbedtls_state._cert);
671 mbedtls_pk_free(&_mbedtls_state._key); 711 mbedtls_pk_free(&_mbedtls_state._key);
672 mbedtls_ssl_free(&_mbedtls_state._ssl ); 712 mbedtls_ssl_free(&_mbedtls_state._ssl);
673 mbedtls_ssl_config_free(&_mbedtls_state._conf ); 713 mbedtls_ssl_config_free(&_mbedtls_state._conf);
674 mbedtls_ctr_drbg_free(&_mbedtls_state._ctr_drbg ); 714 mbedtls_ctr_drbg_free(&_mbedtls_state._ctr_drbg);
675} 715}
676 716
677/* Taken from https://testssl.sh/openssl-iana.mapping.html */ 717/* Taken from https://testssl.sh/openssl-iana.mapping.html */
@@ -924,12 +964,12 @@ NULL
924}; 964};
925// fprintf(stderr, "SUCCESS: %s => %s => %d\n\n", xlate_openssl[i], xlate_openssl[i+1], mbedtls_ssl_get_ciphersuite_id(xlate_openssl[i+1])); 965// fprintf(stderr, "SUCCESS: %s => %s => %d\n\n", xlate_openssl[i], xlate_openssl[i+1], mbedtls_ssl_get_ciphersuite_id(xlate_openssl[i+1]));
926static int map_openssl_suite(char *openssl_name) { 966static int map_openssl_suite(char *openssl_name) {
927 int i; 967 int i;
928 for (i=0; xlate_openssl[i]; i+=2) { 968 for (i = 0; xlate_openssl[i]; i += 2) {
929 if (!strcmp(xlate_openssl[i], openssl_name)) 969 if (!strcmp(xlate_openssl[i], openssl_name))
930 return mbedtls_ssl_get_ciphersuite_id(xlate_openssl[i+1]); 970 return mbedtls_ssl_get_ciphersuite_id(xlate_openssl[i + 1]);
931 } 971 }
932 return 0; 972 return 0;
933} 973}
934 974
935#endif 975#endif
diff --git a/vchat-tls.h b/vchat-tls.h
index 440d08e..17d2687 100755
--- a/vchat-tls.h
+++ b/vchat-tls.h
@@ -4,13 +4,13 @@
4 4
5typedef int (*vc_askpass_cb_t)(char *, int, int, void *); 5typedef int (*vc_askpass_cb_t)(char *, int, int, void *);
6struct vc_x509store_t { 6struct vc_x509store_t {
7 char *cafile; 7 char *cafile;
8 char *capath; 8 char *capath;
9 char *crlfile; 9 char *crlfile;
10 vc_askpass_cb_t askpass_callback; 10 vc_askpass_cb_t askpass_callback;
11 char *certfile; 11 char *certfile;
12 char *keyfile; 12 char *keyfile;
13 int flags; 13 int flags;
14}; 14};
15typedef struct vc_x509store_t vc_x509store_t; 15typedef struct vc_x509store_t vc_x509store_t;
16 16
@@ -25,7 +25,7 @@ void vc_x509store_setcapath(vc_x509store_t *, char *);
25void vc_x509store_setcrlfile(vc_x509store_t *, char *); 25void vc_x509store_setcrlfile(vc_x509store_t *, char *);
26void vc_cleanup_x509store(vc_x509store_t *s); 26void vc_cleanup_x509store(vc_x509store_t *s);
27 27
28int vc_tls_connect(int serverfd, vc_x509store_t * ); 28int vc_tls_connect(int serverfd, vc_x509store_t *);
29ssize_t vc_tls_sendmessage(const void *buf, size_t size); 29ssize_t vc_tls_sendmessage(const void *buf, size_t size);
30ssize_t vc_tls_receivemessage(void *buf, size_t size); 30ssize_t vc_tls_receivemessage(void *buf, size_t size);
31void vc_tls_cleanup(); 31void vc_tls_cleanup();
diff --git a/vchat-ui.c b/vchat-ui.c
index 62ef372..bb33287 100755
--- a/vchat-ui.c
+++ b/vchat-ui.c
@@ -10,116 +10,123 @@
10 * without even the implied warranty of merchantability or fitness for a 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 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 12 * any direct, indirect, incidental or special damages arising in any way out
13 * of the use of this software. 13 * of the use of this software.
14 * 14 *
15 */ 15 */
16 16
17/* general includes */ 17/* general includes */
18#include <unistd.h> 18#include <errno.h>
19#include <stdint.h>
20#include <ncurses.h> 19#include <ncurses.h>
20#include <readline/history.h>
21#include <readline/readline.h>
22#include <regex.h>
21#include <signal.h> 23#include <signal.h>
24#include <stdint.h>
22#include <stdlib.h> 25#include <stdlib.h>
26#include <string.h>
23#include <strings.h> 27#include <strings.h>
24#include <errno.h>
25#include <termios.h>
26#include <sys/ioctl.h> 28#include <sys/ioctl.h>
29#include <termios.h>
27#include <time.h> 30#include <time.h>
28#include <string.h> 31#include <unistd.h>
29#include <readline/readline.h>
30#include <readline/history.h>
31#include <regex.h>
32#include <wchar.h> 32#include <wchar.h>
33 33
34#include "vchat.h"
35#include "vchat-user.h" 34#include "vchat-user.h"
35#include "vchat.h"
36 36
37/* version of this module */ 37/* version of this module */
38const char *vchat_ui_version = "vchat-ui.c $Id$"; 38const char *vchat_ui_version =
39 "vchat-ui.c $Id$";
39 40
40/* externally used variables */ 41/* externally used variables */
41/* current string in topic window */ 42/* current string in topic window */
42char topicstr[TOPICSTRSIZE] = "[] VChat 0.20"; 43char topicstr[TOPICSTRSIZE] = "[] VChat 0.20";
43/* current string in console window */ 44/* current string in console window */
44char consolestr[CONSOLESTRSIZE] = "[ Get help: .h for server /h for client commands"; 45char consolestr[CONSOLESTRSIZE] =
46 "[ Get help: .h for server /h for client commands";
45 47
46static unsigned int ui_init = 0; 48static unsigned int ui_init = 0;
47 49
48/* our windows */ 50/* our windows */
49static WINDOW *console = NULL; 51static WINDOW *console = NULL;
50static WINDOW *input = NULL; 52static WINDOW *input = NULL;
51static WINDOW *topic = NULL; 53static WINDOW *topic = NULL;
52static WINDOW *channel = NULL; 54static WINDOW *channel = NULL;
53static WINDOW *private = NULL; 55static WINDOW *private = NULL;
54static WINDOW *output = NULL; 56static WINDOW *output = NULL;
55 57
56/* our screen dimensions */ 58/* our screen dimensions */
57static int screensx = 0; 59static int screensx = 0;
58static int screensy = 0; 60static int screensy = 0;
59/* current horizontal scrolling offset for input line */ 61/* current horizontal scrolling offset for input line */
60static int scroff = 0; 62static int scroff = 0;
61/* cache for stepping value of horizontal scrolling */ 63/* cache for stepping value of horizontal scrolling */
62unsigned int hscroll = 0; 64unsigned int hscroll = 0;
63 65
64static int outputshown = 0; 66static int outputshown = 0;
65static int outputwidth_desired = 0; 67static int outputwidth_desired = 0;
66 68
67static int privheight = 0; 69static int privheight = 0;
68static int privheight_desired = 0; 70static int privheight_desired = 0;
69static int privwinhidden = 0; 71static int privwinhidden = 0;
70int usetime = 1; 72int usetime = 1;
71int outputcountdown = 0; 73int outputcountdown = 0;
72char *querypartner = NULL; 74char *querypartner = NULL;
73 75
74struct sb_entry { 76struct sb_entry {
75 int id; 77 int id;
76 time_t when; 78 time_t when;
77 int stamp; 79 int stamp;
78 char *what; 80 char *what;
79 struct sb_entry *link; 81 struct sb_entry *link;
80}; 82};
81 83
82struct sb_data { 84struct sb_data {
83 struct sb_entry *entries; 85 struct sb_entry *entries;
84 struct sb_entry *last; 86 struct sb_entry *last;
85 int count; 87 int count;
86 int scroll; 88 int scroll;
87}; 89};
88 90
89static struct sb_data *sb_pub = NULL; 91static struct sb_data *sb_pub = NULL;
90static struct sb_data *sb_priv = NULL; 92static struct sb_data *sb_priv = NULL;
91static struct sb_data *sb_out = NULL; 93static struct sb_data *sb_out = NULL;
92 94
93/* Tells, which window is active */ 95/* Tells, which window is active */
94static int sb_win = 0; /* 0 for pub, 1 for priv */ 96static int sb_win = 0; /* 0 for pub, 1 for priv */
95 97
96/* struct to keep filter list */ 98/* struct to keep filter list */
97struct filt { 99struct filt {
98 char colour; 100 char colour;
99 unsigned int id; 101 unsigned int id;
100 char *text; 102 char *text;
101 regex_t regex; 103 regex_t regex;
102 struct filt *next; 104 struct filt *next;
103}; 105};
104 106
105typedef struct filt filt; 107typedef struct filt filt;
106 108
107static filt *filterlist = NULL; 109static filt *filterlist = NULL;
108static int filtertype = 0; 110static int filtertype = 0;
109static int currentstamp = 0; 111static int currentstamp = 0;
110 112
111/* Prototype declarations */ 113/* Prototype declarations */
112 114
113static void resize (int); 115static void resize(int);
114static void forceredraw (void); 116static void forceredraw(void);
115static void forceredraw_wrapper (int a) {(void)a; forceredraw();} 117static void forceredraw_wrapper(int a) {
116static void drawwin (WINDOW *win, struct sb_data *sb); 118 (void)a;
117static int writescr (WINDOW *win, struct sb_entry *entry); 119 forceredraw();
118static int testfilter ( struct sb_entry *entry); 120}
119static int gettextwidth (const char *textbuffer); 121static void drawwin(WINDOW *win, struct sb_data *sb);
120static void resize_output (void); 122static int writescr(WINDOW *win, struct sb_entry *entry);
121static int getsbeheight (struct sb_entry *entry, const int xwidth, int needstime ); 123static int testfilter(struct sb_entry *entry);
122static int getsbdataheight (struct sb_data *data, const int xwidth, int needstime ); 124static int gettextwidth(const char *textbuffer);
125static void resize_output(void);
126static int getsbeheight(struct sb_entry *entry, const int xwidth,
127 int needstime);
128static int getsbdataheight(struct sb_data *data, const int xwidth,
129 int needstime);
123/* CURRENTLY UNUSED 130/* CURRENTLY UNUSED
124static void writecolorized (WINDOW *win, char *string); 131static void writecolorized (WINDOW *win, char *string);
125*/ 132*/
@@ -132,22 +139,29 @@ enum {
132}; 139};
133 140
134/* */ 141/* */
135static void 142static void togglequery() {
136togglequery() { 143 if (querypartner && private) {
137 if( querypartner && private ) { 144 {
138 { struct sb_data *tmp = sb_pub; sb_pub = sb_priv; sb_priv = tmp; } 145 struct sb_data *tmp = sb_pub;
139 { WINDOW *tmp= private; private = channel; channel = tmp; } 146 sb_pub = sb_priv;
147 sb_priv = tmp;
148 }
149 {
150 WINDOW *tmp = private;
151 private
152 = channel;
153 channel = tmp;
154 }
140 } 155 }
141} 156}
142 157
143const char * skip_to_character( const char * string, size_t offset ) { 158const char *skip_to_character(const char *string, size_t offset) {
144 size_t ch_size; 159 size_t ch_size;
145 mbstate_t mbs; 160 mbstate_t mbs;
146 memset(&mbs, 0, sizeof(mbs)); 161 memset(&mbs, 0, sizeof(mbs));
147 162
148 while( offset-- > 0 ) { 163 while (offset-- > 0) {
149 switch( ch_size = mbrlen( string, MB_CUR_MAX, &mbs ) ) 164 switch (ch_size = mbrlen(string, MB_CUR_MAX, &mbs)) {
150 {
151 case (size_t)-1: 165 case (size_t)-1:
152 case (size_t)-2: 166 case (size_t)-2:
153 return NULL; 167 return NULL;
@@ -161,15 +175,14 @@ const char * skip_to_character( const char * string, size_t offset ) {
161 return string; 175 return string;
162} 176}
163 177
164size_t offset_to_character( const char * string, size_t offset ) { 178size_t offset_to_character(const char *string, size_t offset) {
165 mbstate_t mbs; 179 mbstate_t mbs;
166 memset(&mbs, 0, sizeof(mbs)); 180 memset(&mbs, 0, sizeof(mbs));
167 const char * string_offset = string + offset; 181 const char *string_offset = string + offset;
168 size_t ch_size, nchars = 0; 182 size_t ch_size, nchars = 0;
169 183
170 while( string < string_offset ) { 184 while (string < string_offset) {
171 switch( ch_size = mbrlen( string, MB_CUR_MAX, &mbs ) ) 185 switch (ch_size = mbrlen(string, MB_CUR_MAX, &mbs)) {
172 {
173 case (size_t)-1: 186 case (size_t)-1:
174 case (size_t)-2: 187 case (size_t)-2:
175 return -1; 188 return -1;
@@ -184,117 +197,117 @@ size_t offset_to_character( const char * string, size_t offset ) {
184} 197}
185 198
186/* readlines callback when a line is completed */ 199/* readlines callback when a line is completed */
187static void 200static void linecomplete(char *line) {
188linecomplete (char *line)
189{
190 char *c; 201 char *c;
191 int i; 202 int i;
192 203
193 /* send linefeed, return pointer, reset cursors */ 204 /* send linefeed, return pointer, reset cursors */
194 waddch (input, '\n'); 205 waddch(input, '\n');
195 wmove (input, 0, 0); 206 wmove(input, 0, 0);
196 scroff = 0; 207 scroff = 0;
197 208
198 if (line) { 209 if (line) {
199 i = strlen(line) - 1; 210 i = strlen(line) - 1;
200 while (line[i] == ' ') line[i--]='\0'; 211 while (line[i] == ' ')
212 line[i--] = '\0';
201 213
202 if (line[0] && strchr(line,' ') == NULL && line[i] == ':') 214 if (line[0] && strchr(line, ' ') == NULL && line[i] == ':')
203 line[i--] = '\0'; 215 line[i--] = '\0';
204 216
205 /* empty line? nada. */ 217 /* empty line? nada. */
206 if (line[0]) { 218 if (line[0]) {
207 /* add line to history and have it handled in vchat-protocol.c */ 219 /* add line to history and have it handled in vchat-protocol.c */
208 add_history (line); 220 add_history(line);
209 handleline (line); 221 handleline(line);
210 } 222 }
211 free (line); 223 free(line);
212 rl_reset_line_state(); 224 rl_reset_line_state();
213 rl_point = rl_end = rl_done = 0; 225 rl_point = rl_end = rl_done = 0;
214 226
215 /* If in query mode, feed query prefix */ 227 /* If in query mode, feed query prefix */
216 if (( c = querypartner )) 228 if ((c = querypartner))
217 while( *c ) rl_stuff_char( *c++ ); 229 while (*c)
230 rl_stuff_char(*c++);
218 231
219 /* wipe input line and reset cursor */ 232 /* wipe input line and reset cursor */
220 wrefresh (input); 233 wrefresh(input);
221 } 234 }
222} 235}
223 236
224/* redraw-callback for readline */ 237/* redraw-callback for readline */
225static void 238static void vciredraw(void) {
226vciredraw (void)
227{
228 int i; 239 int i;
229 size_t readline_point; 240 size_t readline_point;
230 241
231 /* readline offers us information we don't need 242 /* readline offers us information we don't need
232 so ignore outabound cursor positions */ 243 so ignore outabound cursor positions */
233 if( rl_point < 0 ) rl_point = 0; 244 if (rl_point < 0)
234 //if( rl_point > rl_end ) rl_point = rl_end; 245 rl_point = 0;
246 // if( rl_point > rl_end ) rl_point = rl_end;
235 247
236 readline_point = offset_to_character( rl_line_buffer, rl_point ); 248 readline_point = offset_to_character(rl_line_buffer, rl_point);
237 249
238 /* hscroll value cache set up? */ 250 /* hscroll value cache set up? */
239 if (!hscroll) { 251 if (!hscroll) {
240 /* check config-option or set hardcoded default */ 252 /* check config-option or set hardcoded default */
241 hscroll = getintoption (CF_HSCROLL); 253 hscroll = getintoption(CF_HSCROLL);
242 if (!hscroll) 254 if (!hscroll)
243 hscroll = 15; 255 hscroll = 15;
244 } 256 }
245 257
246 /* calculate horizontal scrolling offset */ 258 /* calculate horizontal scrolling offset */
247 259
248 /* Case 1: readline is left of current scroll offset: Adjust to left to reveal more text */ 260 /* Case 1: readline is left of current scroll offset: Adjust to left to reveal
249 if( readline_point < scroff ) 261 * more text */
262 if (readline_point < scroff)
250 scroff = readline_point - hscroll; 263 scroff = readline_point - hscroll;
251 if( scroff < 1 ) 264 if (scroff < 1)
252 scroff = 0; 265 scroff = 0;
253 266
254 /* Case 2: readline just hit the last char on the line: Adjust to right to leave more space on screen */ 267 /* Case 2: readline just hit the last char on the line: Adjust to right to
255 if( readline_point >= scroff + getmaxx(input) - 1 ) 268 * leave more space on screen */
269 if (readline_point >= scroff + getmaxx(input) - 1)
256 scroff = readline_point - getmaxx(input) + hscroll; 270 scroff = readline_point - getmaxx(input) + hscroll;
257 271
258 /* wipe input line */ 272 /* wipe input line */
259 wmove (input, 0, 0); 273 wmove(input, 0, 0);
260 for (i = 0; i < getmaxx(input) - 1; i++) 274 for (i = 0; i < getmaxx(input) - 1; i++)
261 waddch (input, ' '); 275 waddch(input, ' ');
262 276
263 /* show current line, move cursor, redraw! */ 277 /* show current line, move cursor, redraw! */
264 const char *start_line = skip_to_character( rl_line_buffer, scroff ); 278 const char *start_line = skip_to_character(rl_line_buffer, scroff);
265 const char *end_line = skip_to_character( start_line, getmaxx(input) - 1 ); 279 const char *end_line = skip_to_character(start_line, getmaxx(input) - 1);
266
267 mvwaddnstr (input, 0, 0, start_line, end_line - start_line );
268 wmove (input, 0, readline_point - scroff );
269 wrefresh (input);
270 280
281 mvwaddnstr(input, 0, 0, start_line, end_line - start_line);
282 wmove(input, 0, readline_point - scroff);
283 wrefresh(input);
271} 284}
272 285
273/* called by the eventloop in vchat-client.c */ 286/* called by the eventloop in vchat-client.c */
274void 287void userinput(void) {
275userinput (void)
276{
277 /* let readline handle what the user typed .. */ 288 /* let readline handle what the user typed .. */
278 rl_callback_read_char (); 289 rl_callback_read_char();
279} 290}
280 291
281static int 292static int calcdrawcus(char *const str) {
282calcdrawcus (char * const str) {
283 char *tmp = str; 293 char *tmp = str;
284 int zero = 0; 294 int zero = 0;
285 while( *tmp && (*tmp!=' ') && (*tmp!='\n')) { if(*tmp==1) zero+=2; tmp++; } 295 while (*tmp && (*tmp != ' ') && (*tmp != '\n')) {
296 if (*tmp == 1)
297 zero += 2;
298 tmp++;
299 }
286 return (tmp - str) - zero; 300 return (tmp - str) - zero;
287} 301}
288 302
289static void 303static void sb_flush(struct sb_data *sb) {
290sb_flush ( struct sb_data *sb ) {
291 struct sb_entry *now = sb->entries, *prev = NULL, *tmp; 304 struct sb_entry *now = sb->entries, *prev = NULL, *tmp;
292 while( now ) { 305 while (now) {
293 tmp = (struct sb_entry*)((unsigned long)prev ^ (unsigned long)now->link); 306 tmp = (struct sb_entry *)((unsigned long)prev ^ (unsigned long)now->link);
294 free(now->what ); 307 free(now->what);
295 free(now); 308 free(now);
296 prev = now; 309 prev = now;
297 now = tmp; 310 now = tmp;
298 } 311 }
299 sb->entries = NULL; 312 sb->entries = NULL;
300} 313}
@@ -306,69 +319,69 @@ sb_clear ( struct sb_data **sb ) {
306 *sb = NULL; 319 *sb = NULL;
307}*/ 320}*/
308 321
309static struct sb_entry* 322static struct sb_entry *sb_add(struct sb_data *sb, const char *line,
310sb_add (struct sb_data *sb, const char *line, time_t when) { 323 time_t when) {
311 struct sb_entry *newone = malloc (sizeof(struct sb_entry)); 324 struct sb_entry *newone = malloc(sizeof(struct sb_entry));
312 if( newone ) { 325 if (newone) {
313 if( sb->count == sb->scroll ) sb->scroll++; 326 if (sb->count == sb->scroll)
314 newone->id = sb->count++; 327 sb->scroll++;
315 newone->when = when; 328 newone->id = sb->count++;
316 newone->what = strdup(line); 329 newone->when = when;
317 newone->link = sb->entries; 330 newone->what = strdup(line);
318 newone->stamp= 0xffff; 331 newone->link = sb->entries;
319 if( sb->entries ) 332 newone->stamp = 0xffff;
320 sb->entries->link = (struct sb_entry*)((unsigned long)sb->entries->link ^ (unsigned long)newone); 333 if (sb->entries)
321 else 334 sb->entries->link = (struct sb_entry *)((unsigned long)sb->entries->link ^
322 sb->last = newone; 335 (unsigned long)newone);
323 sb->entries = newone; 336 else
337 sb->last = newone;
338 sb->entries = newone;
324 } 339 }
325 return newone; 340 return newone;
326} 341}
327 342
328void flushout ( ) 343void flushout() {
329{
330 sb_flush(sb_out); 344 sb_flush(sb_out);
331 writeout(" "); 345 writeout(" ");
332 outputwidth_desired = 0; 346 outputwidth_desired = 0;
333 outputshown = 0; 347 outputshown = 0;
334} 348}
335 349
336void hideout( ) 350void hideout() {
337{ 351 if (outputshown) {
338 if( outputshown ) { 352 outputshown = 0;
339 outputshown = 0; 353 resize(0);
340 resize(0);
341 } 354 }
342} 355}
343 356
344void showout (void) 357void showout(void) {
345{
346 writeout(" "); 358 writeout(" ");
347 outputcountdown = 6; 359 outputcountdown = 6;
348 outputshown = 1; 360 outputshown = 1;
349 resize(0); 361 resize(0);
350} 362}
351 363
352void writeout (const char *str) 364void writeout(const char *str) {
353{
354 int i; 365 int i;
355 sb_add(sb_out,str,time(NULL)); 366 sb_add(sb_out, str, time(NULL));
356 i = 1 + gettextwidth( str ); 367 i = 1 + gettextwidth(str);
357 if( i > outputwidth_desired ) outputwidth_desired = i; 368 if (i > outputwidth_desired)
369 outputwidth_desired = i;
358} 370}
359 371
360int writechan (char *str) { 372int writechan(char *str) {
361 struct sb_entry *tmp; 373 struct sb_entry *tmp;
362 int i = 0; 374 int i = 0;
363 time_t now = time(NULL); 375 time_t now = time(NULL);
364 tmp = sb_add(sb_pub,str,now); 376 tmp = sb_add(sb_pub, str, now);
365 377
366 if ( (sb_pub->scroll == sb_pub->count) && ((filtertype == 0) || ( testfilter(tmp)))) { 378 if ((sb_pub->scroll == sb_pub->count) &&
367 i = writescr(channel, tmp); 379 ((filtertype == 0) || (testfilter(tmp)))) {
368 wnoutrefresh(channel); 380 i = writescr(channel, tmp);
381 wnoutrefresh(channel);
369 } 382 }
370 383
371 if( querypartner && private ) 384 if (querypartner && private)
372 topicline(NULL); 385 topicline(NULL);
373 else 386 else
374 consoleline(NULL); 387 consoleline(NULL);
@@ -376,20 +389,20 @@ int writechan (char *str) {
376 return i; 389 return i;
377} 390}
378 391
379int writecf (formtstr id, char *str) { 392int writecf(formtstr id, char *str) {
380 struct sb_entry *tmp; 393 struct sb_entry *tmp;
381 int i = 0; 394 int i = 0;
382 time_t now = time(NULL); 395 time_t now = time(NULL);
383 snprintf(tmpstr,TMPSTRSIZE,getformatstr(id),str); 396 snprintf(tmpstr, TMPSTRSIZE, getformatstr(id), str);
384 tmp = sb_add(sb_pub,tmpstr,now); 397 tmp = sb_add(sb_pub, tmpstr, now);
385 398
386 if ( (sb_pub->scroll == sb_pub->count) && 399 if ((sb_pub->scroll == sb_pub->count) &&
387 ((filtertype == 0) || ( testfilter(tmp)))) { 400 ((filtertype == 0) || (testfilter(tmp)))) {
388 i = writescr(channel, tmp); 401 i = writescr(channel, tmp);
389 wnoutrefresh(channel); 402 wnoutrefresh(channel);
390 } 403 }
391 404
392 if( querypartner && private ) 405 if (querypartner && private)
393 topicline(NULL); 406 topicline(NULL);
394 else 407 else
395 consoleline(NULL); 408 consoleline(NULL);
@@ -397,34 +410,34 @@ int writecf (formtstr id, char *str) {
397 return i; 410 return i;
398} 411}
399 412
400int writepriv (char *str, int maybeep) { 413int writepriv(char *str, int maybeep) {
401 int i = 0; 414 int i = 0;
402 if (private) { 415 if (private) {
403 416
404 time_t now = time (NULL); 417 time_t now = time(NULL);
405 struct sb_entry *tmp; 418 struct sb_entry *tmp;
406 tmp = sb_add(sb_priv,str,now); 419 tmp = sb_add(sb_priv, str, now);
407 420
408 if ( !privwinhidden && (sb_priv->scroll == sb_priv->count) && 421 if (!privwinhidden && (sb_priv->scroll == sb_priv->count) &&
409 ((filtertype == 0) || ( testfilter(tmp)))) { 422 ((filtertype == 0) || (testfilter(tmp)))) {
410 i = writescr(private, tmp); 423 i = writescr(private, tmp);
411 } 424 }
412 if( privwinhidden && !querypartner ) { 425 if (privwinhidden && !querypartner) {
413 if( (maybeep != 0) && (getintoption( CF_BELLPRIV ) != 0 )) 426 if ((maybeep != 0) && (getintoption(CF_BELLPRIV) != 0))
414 putchar( 7 ); 427 putchar(7);
415 privheight_desired = privwinhidden; 428 privheight_desired = privwinhidden;
416 privwinhidden = 0; 429 privwinhidden = 0;
417 resize(0); 430 resize(0);
418 } 431 }
419 wnoutrefresh(private); 432 wnoutrefresh(private);
420 433
421 if( querypartner && private ) 434 if (querypartner && private)
422 consoleline(NULL); 435 consoleline(NULL);
423 else 436 else
424 topicline(NULL); 437 topicline(NULL);
425 438
426 } else 439 } else
427 i = writechan( str ); 440 i = writechan(str);
428 441
429 return i; 442 return i;
430} 443}
@@ -434,339 +447,364 @@ int writepriv (char *str, int maybeep) {
434#if NCURSES_VERSION_MAJOR >= 5 447#if NCURSES_VERSION_MAJOR >= 5
435 448
436typedef struct { 449typedef struct {
437 attr_t attr; 450 attr_t attr;
438 short pair; 451 short pair;
439} ncurs_attr; 452} ncurs_attr;
440 453
441#define WATTR_GET( win, orgattr ) wattr_get( win, &orgattr.attr, &orgattr.pair, NULL) 454#define WATTR_GET(win, orgattr) \
442#define WATTR_SET( win, orgattr ) wattr_set( win, orgattr.attr, orgattr.pair, NULL) 455 wattr_get(win, &orgattr.attr, &orgattr.pair, NULL)
443#define BCOLR_SET( attr, colour ) attr->pair = colour; 456#define WATTR_SET(win, orgattr) wattr_set(win, orgattr.attr, orgattr.pair, NULL)
457#define BCOLR_SET(attr, colour) attr->pair = colour;
444 458
445#else 459#else
446 460
447typedef struct { 461typedef struct {
448 attr_t attr; 462 attr_t attr;
449} ncurs_attr; 463} ncurs_attr;
450 464
451#define WATTR_GET( win, orgattr ) orgattr.attr = wattr_get(win); 465#define WATTR_GET(win, orgattr) orgattr.attr = wattr_get(win);
452#define WATTR_SET( win, orgattr ) wattr_set( win, orgattr.attr); 466#define WATTR_SET(win, orgattr) wattr_set(win, orgattr.attr);
453#define BCOLR_SET( attr, colour ) attr->attr = ((attr->attr) & ~A_COLOR) | COLOR_PAIR((colour)); 467#define BCOLR_SET(attr, colour) \
468 attr->attr = ((attr->attr) & ~A_COLOR) | COLOR_PAIR((colour));
454 469
455#endif 470#endif
456 471
457/* 'A' - 'Z' attriute type */ 472/* 'A' - 'Z' attriute type */
458static int attributes[] = { A_ALTCHARSET, A_BOLD, 0, A_DIM, 0, 0, 0, 0, A_INVIS, 0, 0, A_BLINK, 473static int attributes[] = {A_ALTCHARSET,
459 0, A_NORMAL, 0, A_PROTECT, 0, A_REVERSE, A_STANDOUT, 0, A_UNDERLINE, 474 A_BOLD,
460 0, 0, 1, 0, 0 }; 475 0,
461 476 A_DIM,
462static void 477 0,
463docolorize (char colour, ncurs_attr *attr, ncurs_attr orgattr) { 478 0,
464 if( colour== '0') { 479 0,
465 *attr = orgattr; 480 0,
466 } else if( ( colour > '0') && ( colour <= '9')) { 481 A_INVIS,
467 BCOLR_SET( attr, colour - '0' ); 482 0,
483 0,
484 A_BLINK,
485 0,
486 A_NORMAL,
487 0,
488 A_PROTECT,
489 0,
490 A_REVERSE,
491 A_STANDOUT,
492 0,
493 A_UNDERLINE,
494 0,
495 0,
496 1,
497 0,
498 0};
499
500static void docolorize(char colour, ncurs_attr *attr, ncurs_attr orgattr) {
501 if (colour == '0') {
502 *attr = orgattr;
503 } else if ((colour > '0') && (colour <= '9')) {
504 BCOLR_SET(attr, colour - '0');
468 } else { 505 } else {
469 char upc = colour & ( 0x20 ^ 0xff ); /* colour AND NOT 0x20 */ 506 char upc = colour & (0x20 ^ 0xff); /* colour AND NOT 0x20 */
470 attr_t newattr; 507 attr_t newattr;
471 if( ( upc >= 'A') && ( upc<='Z' ) && ( newattr = attributes[upc - 'A']) ) 508 if ((upc >= 'A') && (upc <= 'Z') && (newattr = attributes[upc - 'A']))
472 attr->attr = ( colour & 0x20 ) ? attr->attr | newattr : attr->attr & ~newattr; 509 attr->attr =
510 (colour & 0x20) ? attr->attr | newattr : attr->attr & ~newattr;
473 } 511 }
474} 512}
475 513
476/* draw arbitrary strings */ 514/* draw arbitrary strings */
477static int 515static int writescr(WINDOW *win, struct sb_entry *entry) {
478writescr ( WINDOW *win, struct sb_entry *entry ) { 516 char tmp[64];
479 char tmp [64];
480 int charcount = 0; 517 int charcount = 0;
481 int i; 518 int i;
482 int textlen = strlen( entry->what ); 519 int textlen = strlen(entry->what);
483 int timelen = ((win == channel)||(win == private)) && usetime ? 520 int timelen = ((win == channel) || (win == private)) && usetime
484 (int)strftime(tmp,64,getformatstr(FS_TIME),localtime(&entry->when)) : 0; 521 ? (int)strftime(tmp, 64, getformatstr(FS_TIME),
485 char textbuffer[ textlen+timelen+1 ]; 522 localtime(&entry->when))
486 ncurs_attr attrbuffer[ textlen+timelen+1 ]; 523 : 0;
487 ncurs_attr orgattr; 524 char textbuffer[textlen + timelen + 1];
525 ncurs_attr attrbuffer[textlen + timelen + 1];
526 ncurs_attr orgattr;
488 527
489 /* illegal window? return */ 528 /* illegal window? return */
490 if( !win || !(textlen+timelen)) return 0; 529 if (!win || !(textlen + timelen))
530 return 0;
491 531
492 /* store original attributes */ 532 /* store original attributes */
493 WATTR_GET( win, orgattr); 533 WATTR_GET(win, orgattr);
494 attrbuffer[ 0 ] = orgattr; 534 attrbuffer[0] = orgattr;
495 535
496 /* copy time string */ 536 /* copy time string */
497 for( i = 0; i < timelen; i++ ) 537 for (i = 0; i < timelen; i++)
498 if( tmp[ i ] == 1 ) { 538 if (tmp[i] == 1) {
499 docolorize( tmp[++i], attrbuffer+charcount, orgattr); 539 docolorize(tmp[++i], attrbuffer + charcount, orgattr);
500 } else { 540 } else {
501 attrbuffer[ charcount+1 ] = attrbuffer[ charcount ]; 541 attrbuffer[charcount + 1] = attrbuffer[charcount];
502 textbuffer[ charcount++ ] = tmp[ i ]; 542 textbuffer[charcount++] = tmp[i];
503 } 543 }
504 544
505 timelen = charcount; 545 timelen = charcount;
506 546
507 /* copy text */ 547 /* copy text */
508 for( i = 0; i< textlen; i++ ) 548 for (i = 0; i < textlen; i++)
509 if( entry->what[ i ] == 1 ) { 549 if (entry->what[i] == 1) {
510 docolorize( entry->what[++i], attrbuffer+charcount, orgattr); 550 docolorize(entry->what[++i], attrbuffer + charcount, orgattr);
511 } else { 551 } else {
512 attrbuffer[ charcount+1 ] = attrbuffer[ charcount ]; 552 attrbuffer[charcount + 1] = attrbuffer[charcount];
513 textbuffer[ charcount++ ] = entry->what[ i ]; 553 textbuffer[charcount++] = entry->what[i];
514 } 554 }
515 555
516 /* zero terminate text --- very important :) */ 556 /* zero terminate text --- very important :) */
517 textbuffer[ charcount ] = 0; 557 textbuffer[charcount] = 0;
518 558
519 /* hilite */ 559 /* hilite */
520 if((win == channel)||(win == private)) { /* do not higlight bars */ 560 if ((win == channel) || (win == private)) { /* do not higlight bars */
521 filt *flt = filterlist; 561 filt *flt = filterlist;
522 char *instr = textbuffer; 562 char *instr = textbuffer;
523 regmatch_t match; 563 regmatch_t match;
524 int j; 564 int j;
525 565
526 while( flt ) { 566 while (flt) {
527 if ( (flt->colour != '-') && (flt->colour != '+')) { 567 if ((flt->colour != '-') && (flt->colour != '+')) {
528 i = timelen; 568 i = timelen;
529 while( i < charcount ) { 569 while (i < charcount) {
530 if( regexec( &flt->regex, instr+i, 1, &match, 0 )) { 570 if (regexec(&flt->regex, instr + i, 1, &match, 0)) {
531 i = charcount; 571 i = charcount;
532 } else { 572 } else {
533 for( j = i + match.rm_so; j < i + match.rm_eo; j++) 573 for (j = i + match.rm_so; j < i + match.rm_eo; j++)
534 docolorize( flt->colour, attrbuffer+j, orgattr ); 574 docolorize(flt->colour, attrbuffer + j, orgattr);
535 i += 1 + match.rm_so; 575 i += 1 + match.rm_so;
536 }
537 }
538 } 576 }
539 flt = flt->next; 577 }
540 } 578 }
579 flt = flt->next;
580 }
541 } 581 }
542 582
543 if (getcurx(win)) waddch(win,'\n'); 583 if (getcurx(win))
544 584 waddch(win, '\n');
545 for( i = 0; i < charcount; i++ ) { 585
546 /* on start of line or attribute changes set new attribute */ 586 for (i = 0; i < charcount; i++) {
547 if( !i || memcmp( attrbuffer+i, attrbuffer+i-1, sizeof(ncurs_attr))) 587 /* on start of line or attribute changes set new attribute */
548 WATTR_SET( win, attrbuffer[i]); 588 if (!i || memcmp(attrbuffer + i, attrbuffer + i - 1, sizeof(ncurs_attr)))
549 if( textbuffer[ i ] == ' ') { 589 WATTR_SET(win, attrbuffer[i]);
550 if ((calcdrawcus(textbuffer+i+1) + getcurx(win) > getmaxx(win) - 1 - 1)&& 590 if (textbuffer[i] == ' ') {
551 (calcdrawcus(textbuffer+i+1) < getmaxx(win) - 1 )) { 591 if ((calcdrawcus(textbuffer + i + 1) + getcurx(win) >
552 /* line wrap found */ 592 getmaxx(win) - 1 - 1) &&
553 WATTR_SET( win, orgattr); 593 (calcdrawcus(textbuffer + i + 1) < getmaxx(win) - 1)) {
554 waddstr( win, "\n "); 594 /* line wrap found */
555 WATTR_SET( win, attrbuffer[ i ]); 595 WATTR_SET(win, orgattr);
556 } 596 waddstr(win, "\n ");
597 WATTR_SET(win, attrbuffer[i]);
557 } 598 }
558 /* plot character */ 599 }
559 waddch( win, (unsigned char)textbuffer[ i ]); 600 /* plot character */
601 waddch(win, (unsigned char)textbuffer[i]);
560 } 602 }
561 603
562 /* restore old attributes */ 604 /* restore old attributes */
563 WATTR_SET (win, orgattr); 605 WATTR_SET(win, orgattr);
564 606
565 return charcount; 607 return charcount;
566} 608}
567 609
568static void 610static void resize_output() {
569resize_output ( ) 611 int outputwidth =
570{ 612 (outputwidth_desired + 7 > screensx) ? screensx - 7 : outputwidth_desired;
571 int outputwidth = (outputwidth_desired + 7 > screensx) ? screensx - 7 : outputwidth_desired; 613 int outputheight = getsbdataheight(sb_out, outputwidth - 1, 0);
572 int outputheight = getsbdataheight(sb_out, outputwidth-1, 0);
573 614
574 if (outputheight + 5 > screensy ) outputheight = screensy - 5; 615 if (outputheight + 5 > screensy)
575 wresize(output,outputheight,outputwidth); 616 outputheight = screensy - 5;
576 mvwin(output,(screensy-outputheight)>>1,(screensx-outputwidth)>>1); 617 wresize(output, outputheight, outputwidth);
618 mvwin(output, (screensy - outputheight) >> 1, (screensx - outputwidth) >> 1);
577 drawwin(output, sb_out); 619 drawwin(output, sb_out);
578} 620}
579 621
580static void 622static void doscroll(int up) {
581doscroll ( int up ) {
582 togglequery(); 623 togglequery();
583 { 624 {
584 WINDOW *destwin = (sb_win && private) ? private : channel; 625 WINDOW *destwin = (sb_win && private) ? private : channel;
585 struct sb_data *sb = (sb_win && private) ? sb_priv : sb_pub; 626 struct sb_data *sb = (sb_win && private) ? sb_priv : sb_pub;
586 struct sb_entry *now = sb->entries, *prev = NULL, *tmp; 627 struct sb_entry *now = sb->entries, *prev = NULL, *tmp;
587 int lines = (getmaxy(destwin) - 1 ) >>1; 628 int lines = (getmaxy(destwin) - 1) >> 1;
588 629
589 if( sb->scroll != sb->count ) 630 if (sb->scroll != sb->count)
590 while( now && (now->id != sb->scroll) ) { 631 while (now && (now->id != sb->scroll)) {
591 tmp = now; now = (struct sb_entry*)((unsigned long)now->link ^ (unsigned long)prev); prev = tmp; 632 tmp = now;
633 now =
634 (struct sb_entry *)((unsigned long)now->link ^ (unsigned long)prev);
635 prev = tmp;
592 } 636 }
593 637
594 if( !up ) { 638 if (!up) {
595 prev = (struct sb_entry*)((unsigned long)now->link ^ (unsigned long)prev); 639 prev =
596 tmp = now; now = (struct sb_entry*)((unsigned long)now->link ^ (unsigned long)prev); prev = tmp; 640 (struct sb_entry *)((unsigned long)now->link ^ (unsigned long)prev);
597 } 641 tmp = now;
642 now = (struct sb_entry *)((unsigned long)now->link ^ (unsigned long)prev);
643 prev = tmp;
644 }
598 645
599 while( now && (lines > 0)) { 646 while (now && (lines > 0)) {
600 if ( (!filtertype) || ( (now->stamp != currentstamp) && ( (now->stamp == (currentstamp | (1<<15))) || testfilter( now ) ) ) ) 647 if ((!filtertype) ||
601 { 648 ((now->stamp != currentstamp) &&
602 lines -= getsbeheight( now, getmaxx(destwin) - 1, usetime ); 649 ((now->stamp == (currentstamp | (1 << 15))) || testfilter(now)))) {
650 lines -= getsbeheight(now, getmaxx(destwin) - 1, usetime);
603 } 651 }
604 tmp = now; now = (struct sb_entry*)((unsigned long)now->link ^ (unsigned long)prev); prev = tmp; 652 tmp = now;
605 } 653 now = (struct sb_entry *)((unsigned long)now->link ^ (unsigned long)prev);
606 if( now ) 654 prev = tmp;
655 }
656 if (now)
607 sb->scroll = now->id; 657 sb->scroll = now->id;
608 else 658 else if (!up)
609 if( !up ) sb->scroll = sb->count; 659 sb->scroll = sb->count;
610 660
611 drawwin(destwin, sb); 661 drawwin(destwin, sb);
612 wnoutrefresh(destwin); 662 wnoutrefresh(destwin);
613 663
614 togglequery(); 664 togglequery();
615 665
616 if( private && (destwin == channel) ) 666 if (private && (destwin == channel))
617 consoleline( NULL); 667 consoleline(NULL);
618 else 668 else
619 topicline( NULL); 669 topicline(NULL);
620 } 670 }
621} 671}
622 672
673void scrollup(void) { doscroll(1); }
623 674
624void 675void scrolldown(void) { doscroll(0); }
625scrollup (void)
626{
627 doscroll( 1 );
628}
629 676
630void 677void scrollwin(void) {
631scrolldown (void) 678 if (!sb_win && private && !privwinhidden)
632{ 679 sb_win = 1;
633 doscroll( 0 ); 680 else
634} 681 sb_win = 0;
635 682 topicline(NULL);
636void 683 consoleline(NULL);
637scrollwin (void)
638{
639 if (!sb_win && private && !privwinhidden) sb_win = 1;
640 else sb_win = 0;
641 topicline(NULL);
642 consoleline(NULL);
643} 684}
644 685
645void 686void growprivwin(void) {
646growprivwin (void) { 687 if (private) {
647 if( private ) { 688 if (privwinhidden)
648 if( privwinhidden) 689 privwinhidden = 0;
649 privwinhidden = 0; 690 if (++privheight_desired > screensy - 5)
650 if( ++privheight_desired > screensy - 5) 691 privheight_desired = screensy - 5;
651 privheight_desired = screensy - 5; 692 resize(0);
652 resize(0); 693 }
653 }
654} 694}
655 695
656void toggleprivwin (void) { 696void toggleprivwin(void) {
657 if( outputshown ) { 697 if (outputshown) {
658 outputshown = 0; 698 outputshown = 0;
659 resize(0); 699 resize(0);
660 } else { 700 } else {
661 if( private ) { 701 if (private) {
662 if( privwinhidden ) { 702 if (privwinhidden) {
663 privheight_desired = privwinhidden; 703 privheight_desired = privwinhidden;
664 privwinhidden = 0; 704 privwinhidden = 0;
665 } else { 705 } else {
666 privwinhidden = privheight_desired; 706 privwinhidden = privheight_desired;
667 privheight_desired = 1; 707 privheight_desired = 1;
668 sb_win = 0; 708 sb_win = 0;
669 sb_priv->scroll = sb_priv->count; 709 sb_priv->scroll = sb_priv->count;
670 } 710 }
671 resize(0); 711 resize(0);
672 } 712 }
673 } 713 }
674} 714}
675 715
676void 716void shrinkprivwin(void) {
677shrinkprivwin (void) { 717 if (private && !privwinhidden) {
678 if( private && !privwinhidden ) { 718 if (--privheight_desired < 1)
679 if( --privheight_desired < 1) privheight_desired = 1; 719 privheight_desired = 1;
680 if( privheight_desired > screensy - 5) privheight_desired = screensy - 5; 720 if (privheight_desired > screensy - 5)
721 privheight_desired = screensy - 5;
681 resize(0); 722 resize(0);
682 } 723 }
683} 724}
684 725
685/* clear message window */ 726/* clear message window */
686void 727void clearpriv() {
687clearpriv ()
688{
689 WINDOW *dest = NULL; 728 WINDOW *dest = NULL;
690 /* do we have a private window? */ 729 /* do we have a private window? */
691 if (private && !privwinhidden ) 730 if (private && !privwinhidden)
692 dest = private; 731 dest = private;
693 else 732 else
694 dest = channel; 733 dest = channel;
695 734
696 /* clear window, move cursor to bottom, redraw */ 735 /* clear window, move cursor to bottom, redraw */
697 wclear (dest); 736 wclear(dest);
698 wmove (dest, getmaxy(dest) - 1, getmaxx(dest) - 1); 737 wmove(dest, getmaxy(dest) - 1, getmaxx(dest) - 1);
699 wrefresh (dest); 738 wrefresh(dest);
700
701} 739}
702 740
703/* clear channel window */ 741/* clear channel window */
704void 742void clearchan() {
705clearchan ()
706{
707 /* clear window, move cursor to bottom, redraw */ 743 /* clear window, move cursor to bottom, redraw */
708 wclear (channel); 744 wclear(channel);
709 wmove (channel, getmaxy(channel) - 1, getmaxx(channel) - 1); 745 wmove(channel, getmaxy(channel) - 1, getmaxx(channel) - 1);
710 wrefresh (channel); 746 wrefresh(channel);
711} 747}
712 748
713/* Get window size */ 749/* Get window size */
714 750
715void ttgtsz(int *x,int *y) { 751void ttgtsz(int *x, int *y) {
716#ifdef TIOCGSIZE 752#ifdef TIOCGSIZE
717 struct ttysize getit; 753 struct ttysize getit;
718#else 754#else
719#ifdef TIOCGWINSZ 755#ifdef TIOCGWINSZ
720 struct winsize getit; 756 struct winsize getit;
721#endif 757#endif
722#endif 758#endif
723 759
724 *x=0; *y=0; 760 *x = 0;
761 *y = 0;
725#ifdef TIOCGSIZE 762#ifdef TIOCGSIZE
726 if(ioctl(1,TIOCGSIZE,&getit)!= -1) { 763 if (ioctl(1, TIOCGSIZE, &getit) != -1) {
727 *x=getit.ts_cols; 764 *x = getit.ts_cols;
728 *y=getit.ts_lines; 765 *y = getit.ts_lines;
729 } 766 }
730#else 767#else
731#ifdef TIOCGWINSZ 768#ifdef TIOCGWINSZ
732 if(ioctl(1,TIOCGWINSZ,&getit)!= -1) { 769 if (ioctl(1, TIOCGWINSZ, &getit) != -1) {
733 *x=getit.ws_col; 770 *x = getit.ws_col;
734 *y=getit.ws_row; 771 *y = getit.ws_row;
735 } 772 }
736#endif 773#endif
737#endif 774#endif
738 } 775}
739 776
740static void 777static void forceredraw(void) {
741forceredraw (void)
742{
743 sb_pub->scroll = sb_pub->count; 778 sb_pub->scroll = sb_pub->count;
744 sb_priv->scroll = sb_priv->count; 779 sb_priv->scroll = sb_priv->count;
745 780
746 resize(0); 781 resize(0);
747 if(console) wclear(console); 782 if (console)
748 if(topic) wclear(topic); 783 wclear(console);
749 if(private) wclear(private); 784 if (topic)
750 if(channel) wclear(channel); 785 wclear(topic);
751 if(output) wclear(output); 786 if (private)
752 if(input) wclear(input); 787 wclear(private);
788 if (channel)
789 wclear(channel);
790 if (output)
791 wclear(output);
792 if (input)
793 wclear(input);
753 resize(0); 794 resize(0);
754
755} 795}
756 796
757/* resize display on SIGWINCH 797/* resize display on SIGWINCH
758 Nowadays used as our main redraw trigger engine */ 798 Nowadays used as our main redraw trigger engine */
759void 799void resize(int signal) {
760resize (int signal) 800 int xsize, ysize, topicheight = topic ? 1 : 0;
761{
762 int xsize,ysize,topicheight=topic?1:0;
763 (void)signal; 801 (void)signal;
764 802
765 ttgtsz(&xsize,&ysize); 803 ttgtsz(&xsize, &ysize);
766 resizeterm(ysize,xsize); 804 resizeterm(ysize, xsize);
767 805
768 /* store screen-dimensions to local functions */ 806 /* store screen-dimensions to local functions */
769 getmaxyx (stdscr, screensy, screensx); 807 getmaxyx(stdscr, screensy, screensx);
770 808
771 /* desired height of PM window is user controllable, 809 /* desired height of PM window is user controllable,
772 actual size depends on space available on screen */ 810 actual size depends on space available on screen */
@@ -775,24 +813,34 @@ resize (int signal)
775 813
776 /* Leave at least 5 lines for input, console and 814 /* Leave at least 5 lines for input, console and
777 pubchannel */ 815 pubchannel */
778 if ( privheight_desired > screensy - 5) 816 if (privheight_desired > screensy - 5)
779 privheight = screensy - 5; 817 privheight = screensy - 5;
780 else 818 else
781 privheight = privheight_desired; 819 privheight = privheight_desired;
782 820
783 /* check dimensions or bump user */ 821 /* check dimensions or bump user */
784 if (screensy - privheight < 4) 822 if (screensy - privheight < 4) {
785 { 823 fprintf(stderr,
786 fprintf (stderr, "vchat-client: screen to short (only %d rows, at least %d expected), bailing out.\n", screensy, privheight + 6); 824 "vchat-client: screen to short (only %d rows, at least %d "
787 snprintf (errstr, ERRSTRSIZE, "vchat-client: screen to short (only %d rows, at least %d expected), bailing out.\n", screensy, privheight + 6); 825 "expected), bailing out.\n",
788 cleanup (0); 826 screensy, privheight + 6);
789 } 827 snprintf(errstr, ERRSTRSIZE,
790 if (screensx < 14) 828 "vchat-client: screen to short (only %d rows, at least %d "
791 { 829 "expected), bailing out.\n",
792 fprintf (stderr, "vchat-client: screen to thin (only %d cols, at least %d expected), bailing out.\n", screensx, 14); 830 screensy, privheight + 6);
793 snprintf (errstr, ERRSTRSIZE, "vchat-client: screen to thin (only %d cols, at least %d expected), bailing out.\n", screensx, 14); 831 cleanup(0);
794 cleanup (0); 832 }
795 } 833 if (screensx < 14) {
834 fprintf(stderr,
835 "vchat-client: screen to thin (only %d cols, at least %d "
836 "expected), bailing out.\n",
837 screensx, 14);
838 snprintf(errstr, ERRSTRSIZE,
839 "vchat-client: screen to thin (only %d cols, at least %d "
840 "expected), bailing out.\n",
841 screensx, 14);
842 cleanup(0);
843 }
796 844
797 /***** 845 /*****
798 * Arrange windows on screen 846 * Arrange windows on screen
@@ -801,38 +849,44 @@ resize (int signal)
801 togglequery(); 849 togglequery();
802 850
803 /* console and input are always there and always 1 line tall */ 851 /* console and input are always there and always 1 line tall */
804 wresize(console,1,screensx); 852 wresize(console, 1, screensx);
805 wresize(input,1,screensx); 853 wresize(input, 1, screensx);
806 854
807 /* If we got a private window and it is not hidden, set its size */ 855 /* If we got a private window and it is not hidden, set its size */
808 if (private && !privwinhidden) 856 if (private && !privwinhidden)
809 wresize(private,privheight,screensx); 857 wresize(private, privheight, screensx);
810 858
811 /* If oldschool vchat is not enabled, we have a topic line */ 859 /* If oldschool vchat is not enabled, we have a topic line */
812 if( topic ) 860 if (topic)
813 wresize(topic,1,screensx); 861 wresize(topic, 1, screensx);
814 862
815 /* public channel is always there and its height depends on: 863 /* public channel is always there and its height depends on:
816 * existence and visibility of priv window 864 * existence and visibility of priv window
817 * existence of a topic line (oldschool vchat style) 865 * existence of a topic line (oldschool vchat style)
818 */ 866 */
819 wresize(channel, ( !private || privwinhidden ) ? screensy - ( topicheight + 2 ) : screensy - (privheight + ( topicheight + 2 )), screensx); 867 wresize(channel,
868 (!private || privwinhidden)
869 ? screensy - (topicheight + 2)
870 : screensy - (privheight + (topicheight + 2)),
871 screensx);
820 872
821 /* Console and input alway take bottommost lines */ 873 /* Console and input alway take bottommost lines */
822 mvwin(console,screensy-2,0); 874 mvwin(console, screensy - 2, 0);
823 mvwin(input,screensy-1,0); 875 mvwin(input, screensy - 1, 0);
824 876
825 /* Private window always is top left */ 877 /* Private window always is top left */
826 if(private && !privwinhidden) 878 if (private && !privwinhidden)
827 mvwin(private,0,0); 879 mvwin(private, 0, 0);
828 880
829 /* Topic window may not exist without priv window, so it is 881 /* Topic window may not exist without priv window, so it is
830 safe to assume sane values for privwinhidden and privheight */ 882 safe to assume sane values for privwinhidden and privheight */
831 if( topic ) 883 if (topic)
832 mvwin(topic,privwinhidden ? 0 : privheight, 0); 884 mvwin(topic, privwinhidden ? 0 : privheight, 0);
833 885
834 /* chan window starts below private window and topic line */ 886 /* chan window starts below private window and topic line */
835 mvwin(channel, ( !private || privwinhidden ) ? topicheight : privheight + topicheight, 0); 887 mvwin(channel,
888 (!private || privwinhidden) ? topicheight : privheight + topicheight,
889 0);
836 890
837 /******* 891 /*******
838 * Now actual redraw starts, note, that we only fill 892 * Now actual redraw starts, note, that we only fill
@@ -847,97 +901,104 @@ resize (int signal)
847 /* pub channel is always there, paint scrollback buffers */ 901 /* pub channel is always there, paint scrollback buffers */
848 drawwin(channel, sb_pub); 902 drawwin(channel, sb_pub);
849 /* if priv exists and is visible, paint scrollback buffers */ 903 /* if priv exists and is visible, paint scrollback buffers */
850 if(private && !privwinhidden) 904 if (private && !privwinhidden)
851 drawwin(private, sb_priv); 905 drawwin(private, sb_priv);
852 /* Send window's contents to curses virtual buffers */ 906 /* Send window's contents to curses virtual buffers */
853 wnoutrefresh(channel); 907 wnoutrefresh(channel);
854 if(private && !privwinhidden) 908 if (private && !privwinhidden)
855 wnoutrefresh(private); 909 wnoutrefresh(private);
856 910
857 togglequery(); 911 togglequery();
858 912
859 /* Resize and draw our message window, render topic and 913 /* Resize and draw our message window, render topic and
860 console line */ 914 console line */
861 if(outputshown) 915 if (outputshown)
862 resize_output(); 916 resize_output();
863 if(topic) 917 if (topic)
864 topicline(NULL); 918 topicline(NULL);
865 consoleline(NULL); 919 consoleline(NULL);
866 if(loggedin) 920 if (loggedin)
867 vciredraw(); 921 vciredraw();
868} 922}
869 923
870static int 924static int gettextwidth(const char *textbuffer) {
871gettextwidth (const char *textbuffer) 925 int width = 0;
872{
873 int width = 0;
874 926
875 do switch( *(textbuffer++) ) { 927 do
876 case 1: 928 switch (*(textbuffer++)) {
877 if (!*(textbuffer++)) return width; 929 case 1:
930 if (!*(textbuffer++))
931 return width;
878 break; 932 break;
879 case 0: 933 case 0:
880 return width; 934 return width;
881 break; 935 break;
882 default: 936 default:
883 width++; 937 width++;
884 break; 938 break;
885 } while( 1 ); 939 }
940 while (1);
886} 941}
887 942
888static int 943static int getsbdataheight(struct sb_data *data, const int xwidth,
889getsbdataheight (struct sb_data *data, const int xwidth, int needstime ) 944 int needstime) {
890{
891 struct sb_entry *now = data->entries, *prev = NULL, *tmp; 945 struct sb_entry *now = data->entries, *prev = NULL, *tmp;
892 int height = 0; 946 int height = 0;
893 while( now ) { 947 while (now) {
894 height += getsbeheight( now, xwidth, needstime); 948 height += getsbeheight(now, xwidth, needstime);
895 tmp = now; now = (struct sb_entry*)((unsigned long)now->link ^ (unsigned long)prev); prev = tmp; 949 tmp = now;
950 now = (struct sb_entry *)((unsigned long)now->link ^ (unsigned long)prev);
951 prev = tmp;
896 } 952 }
897 return height; 953 return height;
898} 954}
899 955
900static int 956static int getsbeheight(struct sb_entry *entry, const int xwidth,
901getsbeheight (struct sb_entry *entry, const int xwidth, int needstime ) 957 int needstime) {
902{
903 int curx = 0, lines = 1; 958 int curx = 0, lines = 1;
904 char tmp[ 64 ], *textbuffer; 959 char tmp[64], *textbuffer;
905 960
906 if( needstime ) { 961 if (needstime) {
907 int timelen = (int)strftime(tmp,64,getformatstr(FS_TIME),localtime(&entry->when)); 962 int timelen =
908 tmp[ timelen ] = 2; 963 (int)strftime(tmp, 64, getformatstr(FS_TIME), localtime(&entry->when));
909 textbuffer=tmp; 964 tmp[timelen] = 2;
965 textbuffer = tmp;
910 } else { 966 } else {
911 textbuffer = entry->what; 967 textbuffer = entry->what;
912 } 968 }
913 969
914 do switch( *textbuffer++ ) { 970 do
915 case ' ': 971 switch (*textbuffer++) {
972 case ' ':
916 if ((calcdrawcus(textbuffer) + curx > xwidth - 1) && 973 if ((calcdrawcus(textbuffer) + curx > xwidth - 1) &&
917 (calcdrawcus(textbuffer) < xwidth)) { 974 (calcdrawcus(textbuffer) < xwidth)) {
918 lines++; curx = 4; 975 lines++;
919 } else { 976 curx = 4;
920 if( curx++ == xwidth ) { 977 } else {
921 curx = 0; lines++; 978 if (curx++ == xwidth) {
922 } 979 curx = 0;
923 } 980 lines++;
981 }
982 }
924 break; 983 break;
925 case 1: 984 case 1:
926 if (!*textbuffer++) return lines; 985 if (!*textbuffer++)
986 return lines;
927 break; 987 break;
928 case 0: 988 case 0:
929 return lines; 989 return lines;
930 break; 990 break;
931 case 2: 991 case 2:
932 textbuffer=entry->what; 992 textbuffer = entry->what;
933 break; 993 break;
934 default: 994 default:
935 if( curx++ == xwidth ) { 995 if (curx++ == xwidth) {
936 curx = 0; lines++; 996 curx = 0;
997 lines++;
937 } 998 }
938 break; 999 break;
939 } while( 1 ); 1000 }
940 1001 while (1);
941} 1002}
942 1003
943/* Check, which kind of filter we have to apply: 1004/* Check, which kind of filter we have to apply:
@@ -947,8 +1008,7 @@ getsbeheight (struct sb_entry *entry, const int xwidth, int needstime )
947 If no, or only colouring rules have been found, 1008 If no, or only colouring rules have been found,
948 no line filtering applies. 1009 no line filtering applies.
949*/ 1010*/
950static int 1011static int analyzefilters(void) {
951analyzefilters( void ) {
952 filt *filters = filterlist; 1012 filt *filters = filterlist;
953 int type = 0; 1013 int type = 0;
954 1014
@@ -965,96 +1025,106 @@ analyzefilters( void ) {
965 tested the line against. This Stamp 1025 tested the line against. This Stamp
966 is updated for each change to the 1026 is updated for each change to the
967 filter list */ 1027 filter list */
968 if( ++currentstamp == 0x3fff ) currentstamp = 1; 1028 if (++currentstamp == 0x3fff)
969 1029 currentstamp = 1;
970 while( (type!=1) && filters ) { 1030
971 if( filters->colour == '-' ) type = 2; 1031 while ((type != 1) && filters) {
972 if( filters->colour == '+' ) type = 1; 1032 if (filters->colour == '-')
973 filters=filters->next; 1033 type = 2;
1034 if (filters->colour == '+')
1035 type = 1;
1036 filters = filters->next;
974 } 1037 }
975 return type; 1038 return type;
976} 1039}
977 1040
978static int 1041static int testfilter(struct sb_entry *entry) {
979testfilter ( struct sb_entry* entry ) { 1042 int match = 0;
980 int match = 0; 1043 filt *filters = filterlist;
981 filt *filters = filterlist; 1044 char filtercolour = filtertype == 2 ? '-' : '+';
982 char filtercolour = filtertype == 2 ? '-' : '+';
983 1045
984 while( !match && filters ) { 1046 while (!match && filters) {
985 if( filters->colour == filtercolour ) 1047 if (filters->colour == filtercolour)
986 match = regexec( &filters->regex, entry->what, 0, NULL, 0 ) ? 0 : 1; 1048 match = regexec(&filters->regex, entry->what, 0, NULL, 0) ? 0 : 1;
987 filters=filters->next; 1049 filters = filters->next;
988 } 1050 }
989 match = ( filtertype == 2 ) ? ( 1 - match ) : match; 1051 match = (filtertype == 2) ? (1 - match) : match;
990 entry->stamp = (match << 15) | currentstamp; 1052 entry->stamp = (match << 15) | currentstamp;
991 1053
992 return match; 1054 return match;
993} 1055}
994 1056
995static void 1057static void drawwin(WINDOW *win, struct sb_data *sb) {
996drawwin (WINDOW *win, struct sb_data *sb )
997{
998 if (win) { 1058 if (win) {
999 struct sb_entry *now = sb->entries, *prev = NULL, *tmp; 1059 struct sb_entry *now = sb->entries, *prev = NULL, *tmp;
1000 struct sb_entry *vis[getmaxy(win)]; 1060 struct sb_entry *vis[getmaxy(win)];
1001 int sumlines = 0, sumbuffers = 0; 1061 int sumlines = 0, sumbuffers = 0;
1002 1062
1003 /* public scrollback */ 1063 /* public scrollback */
1004 if( sb->scroll != sb->count ) 1064 if (sb->scroll != sb->count)
1005 while( now && (now->id != sb->scroll) ) { 1065 while (now && (now->id != sb->scroll)) {
1006 tmp = now; now = (struct sb_entry*)((unsigned long)now->link ^ (unsigned long)prev); prev = tmp; 1066 tmp = now;
1007 } 1067 now =
1068 (struct sb_entry *)((unsigned long)now->link ^ (unsigned long)prev);
1069 prev = tmp;
1070 }
1008 1071
1009 if( (win == output) || (filtertype == 0)) { 1072 if ((win == output) || (filtertype == 0)) {
1010 while( now && (sumlines <= getmaxy(win) - 1 )) { 1073 while (now && (sumlines <= getmaxy(win) - 1)) {
1011 sumlines += getsbeheight( now, getmaxx(win) - 1, ((win == channel)||(win == private)) && usetime ); 1074 sumlines +=
1012 vis[ sumbuffers++ ] = now; 1075 getsbeheight(now, getmaxx(win) - 1,
1013 tmp = now; now = (struct sb_entry*)((unsigned long)now->link ^ (unsigned long)prev); prev = tmp; 1076 ((win == channel) || (win == private)) && usetime);
1014 } 1077 vis[sumbuffers++] = now;
1015 } else { 1078 tmp = now;
1016 while( now && (sumlines <= getmaxy(win) - 1 )) { 1079 now =
1017 1080 (struct sb_entry *)((unsigned long)now->link ^ (unsigned long)prev);
1018 /* If stamp matches exactly, line has been filtered out, since top 1081 prev = tmp;
1019 bit off means hidden */ 1082 }
1020 if( now->stamp != currentstamp) { 1083 } else {
1021 1084 while (now && (sumlines <= getmaxy(win) - 1)) {
1022 /* If stamp matches and has top bit set, it has been identified 1085
1023 positively. Else stamp does not match and line has to be 1086 /* If stamp matches exactly, line has been filtered out, since top
1024 tested against filters, which updates stamp. */ 1087 bit off means hidden */
1025 if( (now->stamp == (currentstamp | 0x8000) ) || testfilter( now )) 1088 if (now->stamp != currentstamp) {
1026 { 1089
1027 sumlines += getsbeheight( now, getmaxx(win) - 1, ((win == channel)||(win == private)) && usetime ); 1090 /* If stamp matches and has top bit set, it has been identified
1028 vis[ sumbuffers++ ] = now; 1091 positively. Else stamp does not match and line has to be
1029 } 1092 tested against filters, which updates stamp. */
1030 1093 if ((now->stamp == (currentstamp | 0x8000)) || testfilter(now)) {
1031 } 1094 sumlines +=
1032 tmp = now; now = (struct sb_entry*)((unsigned long)now->link ^ (unsigned long)prev); prev = tmp; 1095 getsbeheight(now, getmaxx(win) - 1,
1096 ((win == channel) || (win == private)) && usetime);
1097 vis[sumbuffers++] = now;
1033 } 1098 }
1099 }
1100 tmp = now;
1101 now =
1102 (struct sb_entry *)((unsigned long)now->link ^ (unsigned long)prev);
1103 prev = tmp;
1034 } 1104 }
1105 }
1035 1106
1036 /* If buffer is not completely filled, clear window */ 1107 /* If buffer is not completely filled, clear window */
1037 if( sumlines < getmaxy(win) ) 1108 if (sumlines < getmaxy(win))
1038 wclear(win); 1109 wclear(win);
1039 1110
1040 /* Move pointer to bottom to let curses scroll */ 1111 /* Move pointer to bottom to let curses scroll */
1041 wmove(win, getmaxy(win) - 1, getmaxx(win) - 1); 1112 wmove(win, getmaxy(win) - 1, getmaxx(win) - 1);
1042 1113
1043 /* Plot visible lines */ 1114 /* Plot visible lines */
1044 while (sumbuffers--) writescr( win, vis[sumbuffers] ); 1115 while (sumbuffers--)
1116 writescr(win, vis[sumbuffers]);
1045 } 1117 }
1046} 1118}
1047 1119
1048/* initialize curses and display */ 1120/* initialize curses and display */
1049void 1121void initui(void) {
1050initui (void)
1051{
1052 Keymap keymap; 1122 Keymap keymap;
1053 1123
1054 /* init curses */ 1124 /* init curses */
1055 if (!ui_init) { 1125 if (!ui_init) {
1056 initscr (); 1126 initscr();
1057 ui_init = 1; 1127 ui_init = 1;
1058 } 1128 }
1059 1129
1060 /* install signalhandler */ 1130 /* install signalhandler */
@@ -1063,131 +1133,144 @@ initui (void)
1063 signal(SIGCONT, forceredraw_wrapper); 1133 signal(SIGCONT, forceredraw_wrapper);
1064 1134
1065 /* set options */ 1135 /* set options */
1066 keypad (stdscr, TRUE); 1136 keypad(stdscr, TRUE);
1067 nonl (); 1137 nonl();
1068 cbreak (); 1138 cbreak();
1069 1139
1070 /* color or monochome display? */ 1140 /* color or monochome display? */
1071 if (has_colors ()) 1141 if (has_colors()) {
1072 { 1142 /* start color and set a colorset */
1073 /* start color and set a colorset */ 1143 start_color();
1074 start_color (); 1144 use_default_colors();
1075 use_default_colors(); 1145 init_pair(1, COLOR_RED, -1);
1076 init_pair (1, COLOR_RED, -1); 1146 init_pair(2, COLOR_GREEN, -1);
1077 init_pair (2, COLOR_GREEN, -1); 1147 init_pair(3, COLOR_YELLOW, -1);
1078 init_pair (3, COLOR_YELLOW, -1); 1148 init_pair(4, COLOR_BLUE, -1);
1079 init_pair (4, COLOR_BLUE, -1); 1149 init_pair(5, COLOR_MAGENTA, -1);
1080 init_pair (5, COLOR_MAGENTA, -1); 1150 init_pair(6, COLOR_CYAN, -1);
1081 init_pair (6, COLOR_CYAN, -1); 1151 init_pair(7, COLOR_WHITE, -1);
1082 init_pair (7, COLOR_WHITE, -1); 1152 init_pair(8, COLOR_WHITE, COLOR_RED);
1083 init_pair (8, COLOR_WHITE, COLOR_RED); 1153 init_pair(9, COLOR_WHITE, COLOR_BLUE);
1084 init_pair (9, COLOR_WHITE, COLOR_BLUE); 1154 init_pair(10, COLOR_WHITE, COLOR_BLACK);
1085 init_pair (10, COLOR_WHITE, COLOR_BLACK); 1155 } else {
1086 } 1156 /* monochrome, start color and set a colorset anyways */
1087 else 1157 start_color();
1088 { 1158 init_pair(1, -1, -1);
1089 /* monochrome, start color and set a colorset anyways */ 1159 init_pair(2, -1, -1);
1090 start_color (); 1160 init_pair(3, -1, -1);
1091 init_pair (1, -1, -1); 1161 init_pair(4, -1, -1);
1092 init_pair (2, -1, -1); 1162 init_pair(5, -1, -1);
1093 init_pair (3, -1, -1); 1163 init_pair(6, -1, -1);
1094 init_pair (4, -1, -1); 1164 init_pair(7, -1, -1);
1095 init_pair (5, -1, -1); 1165 init_pair(8, -1, -1);
1096 init_pair (6, -1, -1); 1166 init_pair(9, -1, -1);
1097 init_pair (7, -1, -1); 1167 init_pair(10, -1, -1);
1098 init_pair (8, -1, -1); 1168 }
1099 init_pair (9, -1, -1);
1100 init_pair (10, -1, -1);
1101 }
1102 1169
1103 /* store screen-dimensions to local functions */ 1170 /* store screen-dimensions to local functions */
1104 getmaxyx (stdscr, screensy, screensx); 1171 getmaxyx(stdscr, screensy, screensx);
1105 1172
1106 if (!privheight_desired) privheight_desired = getintoption(CF_PRIVHEIGHT); 1173 if (!privheight_desired)
1107 if ( privheight_desired > screensy - 5) privheight = screensy - 5; else privheight = privheight_desired; 1174 privheight_desired = getintoption(CF_PRIVHEIGHT);
1175 if (privheight_desired > screensy - 5)
1176 privheight = screensy - 5;
1177 else
1178 privheight = privheight_desired;
1108 1179
1109 /* check dimensions or bump user */ 1180 /* check dimensions or bump user */
1110 if (screensy - privheight < 4) 1181 if (screensy - privheight < 4) {
1111 { 1182 fprintf(stderr,
1112 fprintf (stderr, "vchat-client: screen to short (only %d rows, at least %d expected), bailing out.\n", screensy, privheight + 6); 1183 "vchat-client: screen to short (only %d rows, at least %d "
1113 snprintf (errstr, ERRSTRSIZE, "vchat-client: screen to short (only %d rows, at least %d expected), bailing out.\n", screensy, privheight + 6); 1184 "expected), bailing out.\n",
1114 cleanup (0); 1185 screensy, privheight + 6);
1115 } 1186 snprintf(errstr, ERRSTRSIZE,
1116 if (screensx < 14) 1187 "vchat-client: screen to short (only %d rows, at least %d "
1117 { 1188 "expected), bailing out.\n",
1118 fprintf (stderr, "vchat-client: screen to thin (only %d cols, at least %d expected), bailing out.\n", screensx, 14); 1189 screensy, privheight + 6);
1119 snprintf (errstr, ERRSTRSIZE, "vchat-client: screen to thin (only %d cols, at least %d expected), bailing out.\n", screensx, 14); 1190 cleanup(0);
1120 cleanup (0); 1191 }
1121 } 1192 if (screensx < 14) {
1193 fprintf(stderr,
1194 "vchat-client: screen to thin (only %d cols, at least %d "
1195 "expected), bailing out.\n",
1196 screensx, 14);
1197 snprintf(errstr, ERRSTRSIZE,
1198 "vchat-client: screen to thin (only %d cols, at least %d "
1199 "expected), bailing out.\n",
1200 screensx, 14);
1201 cleanup(0);
1202 }
1122 1203
1123 /* setup our windows */ 1204 /* setup our windows */
1124 console = newwin (1, screensx, screensy - 2, 0); 1205 console = newwin(1, screensx, screensy - 2, 0);
1125 input = newwin (1, screensx, screensy - 1, 0); 1206 input = newwin(1, screensx, screensy - 1, 0);
1126 if (privheight) private = newwin (privheight, screensx, 0, 0); 1207 if (privheight)
1127 if( private || getintoption(CF_USETOPIC)) 1208 private
1128 topic = newwin (1, screensx, privheight, 0); 1209 = newwin(privheight, screensx, 0, 0);
1129 channel = newwin (screensy - (privheight+3), screensx, (privheight+1), 0); 1210 if (private || getintoption(CF_USETOPIC))
1130 output = newwin (1, screensx, 1, 0); 1211 topic = newwin(1, screensx, privheight, 0);
1212 channel = newwin(screensy - (privheight + 3), screensx, (privheight + 1), 0);
1213 output = newwin(1, screensx, 1, 0);
1131 1214
1132 /* promblems opening windows? bye! */ 1215 /* promblems opening windows? bye! */
1133 if (!console || !input || (!topic && getintoption(CF_USETOPIC))|| !channel || !output || ( !private && privheight )) 1216 if (!console || !input || (!topic && getintoption(CF_USETOPIC)) || !channel ||
1134 { 1217 !output || (!private && privheight)) {
1135 fprintf (stderr, "vchat-client: could not open windows, bailing out.\n"); 1218 fprintf(stderr, "vchat-client: could not open windows, bailing out.\n");
1136 cleanup (0); 1219 cleanup(0);
1137 } 1220 }
1138 1221
1139 /* Prepare our scrollback buffers */ 1222 /* Prepare our scrollback buffers */
1140 sb_pub = (struct sb_data*)malloc( sizeof(struct sb_data)); 1223 sb_pub = (struct sb_data *)malloc(sizeof(struct sb_data));
1141 sb_out = (struct sb_data*)malloc( sizeof(struct sb_data)); 1224 sb_out = (struct sb_data *)malloc(sizeof(struct sb_data));
1142 if( privheight) 1225 if (privheight)
1143 sb_priv = (struct sb_data*)malloc( sizeof(struct sb_data)); 1226 sb_priv = (struct sb_data *)malloc(sizeof(struct sb_data));
1144 else 1227 else
1145 sb_priv = sb_pub; 1228 sb_priv = sb_pub;
1146 1229
1147 memset( sb_pub, 0, sizeof(struct sb_data)); 1230 memset(sb_pub, 0, sizeof(struct sb_data));
1148 memset( sb_priv, 0, sizeof(struct sb_data)); 1231 memset(sb_priv, 0, sizeof(struct sb_data));
1149 memset( sb_out, 0, sizeof(struct sb_data)); 1232 memset(sb_out, 0, sizeof(struct sb_data));
1150 1233
1151 /* set colors for windows */ 1234 /* set colors for windows */
1152 if (has_colors()) { 1235 if (has_colors()) {
1153 if (getintoption(CF_INVWINBAR)) { 1236 if (getintoption(CF_INVWINBAR)) {
1154 wbkgd (console, COLOR_PAIR (0)); 1237 wbkgd(console, COLOR_PAIR(0));
1155 wattron (console, A_REVERSE); 1238 wattron(console, A_REVERSE);
1156 } else { 1239 } else {
1157 wattrset (console, COLOR_PAIR (9)); 1240 wattrset(console, COLOR_PAIR(9));
1158 wbkgd (console, COLOR_PAIR (9)); 1241 wbkgd(console, COLOR_PAIR(9));
1159 } 1242 }
1160 wattrset (input, COLOR_PAIR (0)); 1243 wattrset(input, COLOR_PAIR(0));
1161 wbkgd (output, COLOR_PAIR(8)); 1244 wbkgd(output, COLOR_PAIR(8));
1162 wbkgd (channel, COLOR_PAIR (0)); 1245 wbkgd(channel, COLOR_PAIR(0));
1163 wbkgd (input, COLOR_PAIR (0)); 1246 wbkgd(input, COLOR_PAIR(0));
1164 if (private) 1247 if (private)
1165 wbkgd (private, COLOR_PAIR (0)); 1248 wbkgd(private, COLOR_PAIR(0));
1166 if (topic) { 1249 if (topic) {
1167 if (getintoption(CF_INVWINBAR)) { 1250 if (getintoption(CF_INVWINBAR)) {
1168 wbkgd (input, COLOR_PAIR (0)); 1251 wbkgd(input, COLOR_PAIR(0));
1169 wattron(topic, A_REVERSE); 1252 wattron(topic, A_REVERSE);
1170 } else { 1253 } else {
1171 wattrset (topic, COLOR_PAIR (9)); 1254 wattrset(topic, COLOR_PAIR(9));
1172 wbkgd (topic, COLOR_PAIR (9)); 1255 wbkgd(topic, COLOR_PAIR(9));
1173 } 1256 }
1174 } 1257 }
1175 } else { 1258 } else {
1176 wattron (console, A_REVERSE); 1259 wattron(console, A_REVERSE);
1177 wattron (output, A_REVERSE); 1260 wattron(output, A_REVERSE);
1178 wbkgd(output, A_REVERSE); 1261 wbkgd(output, A_REVERSE);
1179 if( topic ) 1262 if (topic)
1180 wattron (topic, A_REVERSE); 1263 wattron(topic, A_REVERSE);
1181 } 1264 }
1182 1265
1183 /* set some options */ 1266 /* set some options */
1184 scrollok (channel, TRUE); 1267 scrollok(channel, TRUE);
1185 if (private) 1268 if (private)
1186 scrollok (private, TRUE); 1269 scrollok(private, TRUE);
1187 scrollok (input, TRUE); 1270 scrollok(input, TRUE);
1188 scrollok (output, TRUE); 1271 scrollok(output, TRUE);
1189 //idlok(channel,TRUE); 1272 // idlok(channel,TRUE);
1190 wtimeout (input, 100); 1273 wtimeout(input, 100);
1191 1274
1192 /* setup readlines display */ 1275 /* setup readlines display */
1193 /* FIXME: present only in newer readline versions 1276 /* FIXME: present only in newer readline versions
@@ -1198,88 +1281,88 @@ initui (void)
1198 rl_redisplay_function = vciredraw; 1281 rl_redisplay_function = vciredraw;
1199 1282
1200 /* get keymap, throw out unwanted binding */ 1283 /* get keymap, throw out unwanted binding */
1201 keymap = rl_get_keymap (); 1284 keymap = rl_get_keymap();
1202 rl_unbind_command_in_map ("clear-screen", keymap); 1285 rl_unbind_command_in_map("clear-screen", keymap);
1203 rl_unbind_command_in_map ("complete", keymap); 1286 rl_unbind_command_in_map("complete", keymap);
1204 rl_unbind_command_in_map ("possible-completions", keymap); 1287 rl_unbind_command_in_map("possible-completions", keymap);
1205 rl_unbind_command_in_map ("insert-completions", keymap); 1288 rl_unbind_command_in_map("insert-completions", keymap);
1206 1289
1207 /* bind CTRL-L to clearmsg() */ 1290 /* bind CTRL-L to clearmsg() */
1208 rl_bind_key ('J'-'@', (rl_command_func_t *) clearpriv); 1291 rl_bind_key('J' - '@', (rl_command_func_t *)clearpriv);
1209 rl_bind_key ('O'-'@', (rl_command_func_t *) clearchan); 1292 rl_bind_key('O' - '@', (rl_command_func_t *)clearchan);
1210 rl_bind_key ('L'-'@', (rl_command_func_t *) forceredraw); 1293 rl_bind_key('L' - '@', (rl_command_func_t *)forceredraw);
1211 rl_bind_key ('B'-'@', (rl_command_func_t *) scrollup); 1294 rl_bind_key('B' - '@', (rl_command_func_t *)scrollup);
1212 rl_bind_key ('P'-'@', (rl_command_func_t *) scrollup); 1295 rl_bind_key('P' - '@', (rl_command_func_t *)scrollup);
1213 rl_bind_key ('F'-'@', (rl_command_func_t *) scrolldown); 1296 rl_bind_key('F' - '@', (rl_command_func_t *)scrolldown);
1214 rl_bind_key ('N'-'@', (rl_command_func_t *) scrolldown); 1297 rl_bind_key('N' - '@', (rl_command_func_t *)scrolldown);
1215 rl_bind_key ('R'-'@', (rl_command_func_t *) scrollwin); 1298 rl_bind_key('R' - '@', (rl_command_func_t *)scrollwin);
1216 rl_bind_key ('T'-'@', (rl_command_func_t *) shrinkprivwin); 1299 rl_bind_key('T' - '@', (rl_command_func_t *)shrinkprivwin);
1217 rl_bind_key ('G'-'@', (rl_command_func_t *) growprivwin); 1300 rl_bind_key('G' - '@', (rl_command_func_t *)growprivwin);
1218 rl_bind_key ('X'-'@', (rl_command_func_t *) toggleprivwin); 1301 rl_bind_key('X' - '@', (rl_command_func_t *)toggleprivwin);
1219 1302
1220 rl_generic_bind (ISFUNC, "\\M-[5~", (void *)scrollup, keymap); 1303 rl_generic_bind(ISFUNC, "\\M-[5~", (void *)scrollup, keymap);
1221 rl_generic_bind (ISFUNC, "\\M-[6~", (void *)scrolldown, keymap); 1304 rl_generic_bind(ISFUNC, "\\M-[6~", (void *)scrolldown, keymap);
1222 1305
1223 /* bind TAB to menu complete from readline */ 1306 /* bind TAB to menu complete from readline */
1224 rl_bind_key ('\t', (rl_command_func_t *) rl_menu_complete); 1307 rl_bind_key('\t', (rl_command_func_t *)rl_menu_complete);
1225 1308
1226 /* application name for .inputrc - err, we don't load it */ 1309 /* application name for .inputrc - err, we don't load it */
1227 rl_readline_name = "vchat-client"; 1310 rl_readline_name = "vchat-client";
1228 1311
1229 /* set up nick completion functions .. */ 1312 /* set up nick completion functions .. */
1230 rl_ignore_completion_duplicates = 0; 1313 rl_ignore_completion_duplicates = 0;
1231 rl_attempted_completion_function = (rl_completion_func_t *) ul_complete_user; 1314 rl_attempted_completion_function = (rl_completion_func_t *)ul_complete_user;
1232 1315
1233 /* .. and 'line completed' callback */ 1316 /* .. and 'line completed' callback */
1234 rl_callback_handler_install ("", (rl_vcpfunc_t *) linecomplete); 1317 rl_callback_handler_install("", (rl_vcpfunc_t *)linecomplete);
1235 1318
1236 if( getintoption(CF_PRIVCOLLAPS) ) 1319 if (getintoption(CF_PRIVCOLLAPS))
1237 toggleprivwin(); 1320 toggleprivwin();
1238 1321
1239 resize(0); 1322 resize(0);
1240} 1323}
1241 1324
1242/* render consoleline to screen */ 1325/* render consoleline to screen */
1243void 1326void consoleline(char *message) {
1244consoleline (char *message)
1245{
1246 /* clear console, set string (or default), redraw display */ 1327 /* clear console, set string (or default), redraw display */
1247 int i; 1328 int i;
1248 ncurs_attr old_att, new_att; 1329 ncurs_attr old_att, new_att;
1249 1330
1250 togglequery(); 1331 togglequery();
1251 1332
1252 memset( &new_att, 0, sizeof(new_att)); 1333 memset(&new_att, 0, sizeof(new_att));
1253 BCOLR_SET( (&new_att), 8 ); 1334 BCOLR_SET((&new_att), 8);
1254 wmove (console, 0, 0); 1335 wmove(console, 0, 0);
1255 WATTR_GET( console, old_att); 1336 WATTR_GET(console, old_att);
1256 if(sb_pub->scroll!=sb_pub->count) 1337 if (sb_pub->scroll != sb_pub->count)
1257 WATTR_SET( console, new_att); 1338 WATTR_SET(console, new_att);
1258 1339
1259 for (i = 0; i < getmaxx(console) - 1; i++) 1340 for (i = 0; i < getmaxx(console) - 1; i++)
1260 waddch (console, ' '); 1341 waddch(console, ' ');
1261 1342
1262 if( !message && usetime ) 1343 if (!message && usetime) {
1263 { 1344 char date[10];
1264 char date[10]; 1345 time_t now = time(NULL);
1265 time_t now = time(NULL); 1346 strftime(date, sizeof(date), getformatstr(FS_CONSOLETIME), localtime(&now));
1266 strftime( date, sizeof(date), getformatstr(FS_CONSOLETIME), localtime(&now)); 1347 snprintf(tmpstr, TMPSTRSIZE, "%s%s", date, consolestr);
1267 snprintf( tmpstr, TMPSTRSIZE, "%s%s", date, consolestr); 1348 mvwaddnstr(console, 0, 0, tmpstr, getmaxx(console) - 1);
1268 mvwaddnstr (console, 0, 0, tmpstr, getmaxx(console) - 1);
1269 } else { 1349 } else {
1270 mvwaddnstr (console, 0, 0, message ? message : consolestr, getmaxx(console) - 1); 1350 mvwaddnstr(console, 0, 0, message ? message : consolestr,
1351 getmaxx(console) - 1);
1271 } 1352 }
1272 1353
1273 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_SBINF),sb_pub->scroll,sb_pub->count); 1354 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_SBINF), sb_pub->scroll,
1274 mvwaddstr (console, 0, getmaxx(console) - 1 - (strlen(tmpstr)-1),tmpstr); 1355 sb_pub->count);
1275 if (sb_win == 0) mvwaddch (console, 0, getmaxx(console) - 1,'*'); 1356 mvwaddstr(console, 0, getmaxx(console) - 1 - (strlen(tmpstr) - 1), tmpstr);
1357 if (sb_win == 0)
1358 mvwaddch(console, 0, getmaxx(console) - 1, '*');
1276 1359
1277 WATTR_SET( console, old_att); 1360 WATTR_SET(console, old_att);
1278 1361
1279 wnoutrefresh(console); 1362 wnoutrefresh(console);
1280 if(outputshown) { 1363 if (outputshown) {
1281 redrawwin(output); 1364 redrawwin(output);
1282 wnoutrefresh(output); 1365 wnoutrefresh(output);
1283 } 1366 }
1284 1367
1285 togglequery(); 1368 togglequery();
@@ -1288,41 +1371,41 @@ consoleline (char *message)
1288} 1371}
1289 1372
1290/* render topicline to screen */ 1373/* render topicline to screen */
1291void 1374void topicline(char *message) {
1292topicline (char *message)
1293{
1294 int i; 1375 int i;
1295 ncurs_attr old_att, new_att; 1376 ncurs_attr old_att, new_att;
1296 1377
1297 if( !topic ) 1378 if (!topic)
1298 return; 1379 return;
1299 1380
1300 togglequery(); 1381 togglequery();
1301 1382
1302 memset( &new_att, 0, sizeof(new_att)); 1383 memset(&new_att, 0, sizeof(new_att));
1303 BCOLR_SET( (&new_att), 8 ); 1384 BCOLR_SET((&new_att), 8);
1304 1385
1305 /* clear topic, set string (or default), redraw display */ 1386 /* clear topic, set string (or default), redraw display */
1306 wmove (topic, 0, 0); 1387 wmove(topic, 0, 0);
1307 1388
1308 WATTR_GET( topic, old_att); 1389 WATTR_GET(topic, old_att);
1309 if( private && (sb_priv->scroll!=sb_priv->count)) 1390 if (private && (sb_priv->scroll != sb_priv->count))
1310 WATTR_SET( topic, new_att); 1391 WATTR_SET(topic, new_att);
1311 1392
1312 for (i = 0; i < getmaxx(topic) - 1; i++) 1393 for (i = 0; i < getmaxx(topic) - 1; i++)
1313 waddch (topic, ' '); 1394 waddch(topic, ' ');
1314 mvwaddnstr (topic, 0, 0, message ? message : topicstr, getmaxx(topic) - 1); 1395 mvwaddnstr(topic, 0, 0, message ? message : topicstr, getmaxx(topic) - 1);
1315 if (private) { 1396 if (private) {
1316 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_SBINF),sb_priv->scroll,sb_priv->count); 1397 snprintf(tmpstr, TMPSTRSIZE, getformatstr(FS_SBINF), sb_priv->scroll,
1317 mvwaddstr (topic, 0, getmaxx(topic) - 1 - (strlen(tmpstr)-1),tmpstr); 1398 sb_priv->count);
1318 if (sb_win == 1) mvwaddch (topic, 0, getmaxx(topic) - 1,'*'); 1399 mvwaddstr(topic, 0, getmaxx(topic) - 1 - (strlen(tmpstr) - 1), tmpstr);
1400 if (sb_win == 1)
1401 mvwaddch(topic, 0, getmaxx(topic) - 1, '*');
1319 } 1402 }
1320 WATTR_SET( topic, old_att); 1403 WATTR_SET(topic, old_att);
1321 1404
1322 wnoutrefresh(topic); 1405 wnoutrefresh(topic);
1323 if(outputshown) { 1406 if (outputshown) {
1324 redrawwin(output); 1407 redrawwin(output);
1325 wnoutrefresh(output); 1408 wnoutrefresh(output);
1326 } 1409 }
1327 1410
1328 togglequery(); 1411 togglequery();
@@ -1331,23 +1414,19 @@ topicline (char *message)
1331} 1414}
1332 1415
1333/* end userinterface */ 1416/* end userinterface */
1334void 1417void exitui(void) {
1335exitui (void)
1336{
1337 if (ui_init) { 1418 if (ui_init) {
1338 rl_callback_handler_remove (); 1419 rl_callback_handler_remove();
1339 endwin (); 1420 endwin();
1340 ui_init = 0; 1421 ui_init = 0;
1341 } 1422 }
1342} 1423}
1343 1424
1344/* prompt for a nick */ 1425/* prompt for a nick */
1345/* FIXME: must not be called when used rl_callback_read_char()/userinput() 1426/* FIXME: must not be called when used rl_callback_read_char()/userinput()
1346 * before */ 1427 * before */
1347void 1428void nickprompt(void) {
1348nickprompt (void) 1429 char *newnick = 0;
1349{
1350 char * newnick = 0;
1351 1430
1352 if (own_nick_get()) 1431 if (own_nick_get())
1353 return; 1432 return;
@@ -1358,15 +1437,15 @@ nickprompt (void)
1358 newnick = readline(""); 1437 newnick = readline("");
1359 1438
1360 own_nick_set(newnick); 1439 own_nick_set(newnick);
1361 setstroption(CF_NICK,newnick); 1440 setstroption(CF_NICK, newnick);
1362 1441
1363 /* try to get readlines stats clean again */ 1442 /* try to get readlines stats clean again */
1364 //rl_free_line_state (); 1443 // rl_free_line_state ();
1365 memset( rl_line_buffer, 0, rl_end ); 1444 memset(rl_line_buffer, 0, rl_end);
1366 rl_point = rl_end = rl_done = 0; 1445 rl_point = rl_end = rl_done = 0;
1367 1446
1368 /* wipe input line and reset cursor */ 1447 /* wipe input line and reset cursor */
1369 rl_kill_full_line(0,0); 1448 rl_kill_full_line(0, 0);
1370 wclear(input); 1449 wclear(input);
1371 1450
1372 /* reset consoleline */ 1451 /* reset consoleline */
@@ -1374,20 +1453,18 @@ nickprompt (void)
1374} 1453}
1375 1454
1376/* special callback for readline, doesn't show the characters */ 1455/* special callback for readline, doesn't show the characters */
1377static void 1456static void vcnredraw(void) {
1378vcnredraw (void)
1379{
1380 int i; 1457 int i;
1381 char *passbof="-*-*-*-*-*-*-"; 1458 char *passbof = "-*-*-*-*-*-*-";
1382 1459
1383 /* wipe input line and reset cursor */ 1460 /* wipe input line and reset cursor */
1384 wmove(input, 0, 0); 1461 wmove(input, 0, 0);
1385 for (i = 0; i < getmaxx(input) - 1; i++) 1462 for (i = 0; i < getmaxx(input) - 1; i++)
1386 waddch(input, ' '); 1463 waddch(input, ' ');
1387 wmove(input, 0, 0); 1464 wmove(input, 0, 0);
1388 1465
1389 /* draw as many stars as there are characters */ 1466 /* draw as many stars as there are characters */
1390 mvwaddnstr(input, 0, 0, &passbof[rl_point%2], 12); 1467 mvwaddnstr(input, 0, 0, &passbof[rl_point % 2], 12);
1391 wmove(input, 0, getmaxx(input) - 1); 1468 wmove(input, 0, getmaxx(input) - 1);
1392 wrefresh(input); 1469 wrefresh(input);
1393} 1470}
@@ -1395,9 +1472,7 @@ vcnredraw (void)
1395/* passphrase callback for OpenSSL */ 1472/* passphrase callback for OpenSSL */
1396/* FIXME: must not be called when used rl_callback_read_char()/userinput() 1473/* FIXME: must not be called when used rl_callback_read_char()/userinput()
1397 * before */ 1474 * before */
1398int 1475int passprompt(char *buf, int size, int rwflag, void *userdata) {
1399passprompt (char *buf, int size, int rwflag, void *userdata)
1400{
1401 int i; 1476 int i;
1402 char *passphrase = NULL; 1477 char *passphrase = NULL;
1403 (void)rwflag; 1478 (void)rwflag;
@@ -1409,45 +1484,43 @@ passprompt (char *buf, int size, int rwflag, void *userdata)
1409 1484
1410 /* prompt user for non-empty passphrase */ 1485 /* prompt user for non-empty passphrase */
1411 consoleline("Please enter PEM passphrase for private key:"); 1486 consoleline("Please enter PEM passphrase for private key:");
1412 while (!passphrase || !passphrase[0]) 1487 while (!passphrase || !passphrase[0]) {
1413 { 1488 if (passphrase)
1414 if (passphrase) 1489 free(passphrase);
1415 free (passphrase); 1490 passphrase = readline("");
1416 passphrase = readline (""); 1491 }
1417 }
1418 1492
1419 /* reset redrawing function to default, reset consoleline */ 1493 /* reset redrawing function to default, reset consoleline */
1420 rl_redisplay_function = vciredraw; 1494 rl_redisplay_function = vciredraw;
1421 consoleline(NULL); 1495 consoleline(NULL);
1422 1496
1423 /* copy passphrase to buffer */ 1497 /* copy passphrase to buffer */
1424 strncpy (buf, passphrase, size); 1498 strncpy(buf, passphrase, size);
1425 1499
1426 /* try to get readlines stats clean again */ 1500 /* try to get readlines stats clean again */
1427 //rl_free_line_state (); 1501 // rl_free_line_state ();
1428 memset( rl_line_buffer, 0, rl_end ); 1502 memset(rl_line_buffer, 0, rl_end);
1429 rl_point = rl_end = rl_done = 0; 1503 rl_point = rl_end = rl_done = 0;
1430 1504
1431 /* wipe input line and reset cursor */ 1505 /* wipe input line and reset cursor */
1432 wmove (input, 0, 0); 1506 wmove(input, 0, 0);
1433 for (i = 0; i < getmaxx(input) - 1; i++) 1507 for (i = 0; i < getmaxx(input) - 1; i++)
1434 waddch (input, ' '); 1508 waddch(input, ' ');
1435 wmove (input, 0, 0); 1509 wmove(input, 0, 0);
1436 wrefresh (input); 1510 wrefresh(input);
1437 1511
1438 /* return passphrase to OpenSSL */ 1512 /* return passphrase to OpenSSL */
1439 return strlen (buf); 1513 return strlen(buf);
1440} 1514}
1441 1515
1442/* Filter stuff */ 1516/* Filter stuff */
1443static int 1517static int check_valid_colour(char colour) {
1444check_valid_colour( char colour ) { 1518 return !((colour != '-') && (colour != '+') &&
1445 return !( (colour !='-')&&(colour !='+') && (colour < '0' || colour > '9') && 1519 (colour < '0' || colour > '9') &&
1446 (colour < 'A' || colour > 'Z' || !attributes[ colour-'A' ]) && 1520 (colour < 'A' || colour > 'Z' || !attributes[colour - 'A']) &&
1447 (colour < 'a' || colour > 'z' || !attributes[ colour-'a' ])); 1521 (colour < 'a' || colour > 'z' || !attributes[colour - 'a']));
1448} 1522}
1449 1523
1450
1451/* scans filterlist and removes possible matches 1524/* scans filterlist and removes possible matches
1452 test functions may return: 1525 test functions may return:
1453 RMFILTER_RMANDCONT 1526 RMFILTER_RMANDCONT
@@ -1456,102 +1529,101 @@ check_valid_colour( char colour ) {
1456 RMFILTER_KEEPANDSTOP 1529 RMFILTER_KEEPANDSTOP
1457 returns number of removed entries 1530 returns number of removed entries
1458*/ 1531*/
1459static int 1532static int removefromfilterlist(int (*test)(filt *flt, void *data, char colour),
1460removefromfilterlist( int(*test)(filt *flt, void *data, char colour), void *data, char colour) { 1533 void *data, char colour) {
1461 filt **flt = &filterlist, *tmp; 1534 filt **flt = &filterlist, *tmp;
1462 int removed = 0, stop = 0; 1535 int removed = 0, stop = 0;
1463 1536
1464 while( *flt && !stop ) { 1537 while (*flt && !stop) {
1465 switch( test( *flt, data, colour ) ) { 1538 switch (test(*flt, data, colour)) {
1466 case RMFILTER_RMANDSTOP: /* remove */ 1539 case RMFILTER_RMANDSTOP: /* remove */
1467 stop = 1; 1540 stop = 1;
1468 case RMFILTER_RMANDCONT: 1541 case RMFILTER_RMANDCONT:
1469 snprintf( tmpstr, TMPSTRSIZE, " Removed ID: [% 3d] Color: [%c] Regex: [%s] ", (*flt)->id, (*flt)->colour, (*flt)->text); 1542 snprintf(tmpstr, TMPSTRSIZE,
1470 writeout(tmpstr); 1543 " Removed ID: [% 3d] Color: [%c] Regex: [%s] ", (*flt)->id,
1471 /* Release regex.h resources */ 1544 (*flt)->colour, (*flt)->text);
1472 regfree( &((*flt)->regex)); 1545 writeout(tmpstr);
1473 /* free ASCII text memory */ 1546 /* Release regex.h resources */
1474 free( (*flt)->text); 1547 regfree(&((*flt)->regex));
1475 /* unlink from list */ 1548 /* free ASCII text memory */
1476 tmp = *flt; 1549 free((*flt)->text);
1477 *flt = (*flt)->next; 1550 /* unlink from list */
1478 /* free filter block itself */ 1551 tmp = *flt;
1479 free( tmp ); 1552 *flt = (*flt)->next;
1480 /* reflect changes on whole screen */ 1553 /* free filter block itself */
1481 removed++; 1554 free(tmp);
1482 break; 1555 /* reflect changes on whole screen */
1483 case RMFILTER_KEEPANDSTOP: /* don't remove but stop scanning */ 1556 removed++;
1484 stop = 1; 1557 break;
1485 break; 1558 case RMFILTER_KEEPANDSTOP: /* don't remove but stop scanning */
1486 default: 1559 stop = 1;
1487 /* advance in list */ 1560 break;
1488 if( *flt ) flt = &((*flt)->next); 1561 default:
1489 break; 1562 /* advance in list */
1490 } 1563 if (*flt)
1564 flt = &((*flt)->next);
1565 break;
1566 }
1491 } 1567 }
1492 /* return number of removed items */ 1568 /* return number of removed items */
1493 return removed; 1569 return removed;
1494} 1570}
1495 1571
1496static int 1572static int test_clear(filt *flt, void *data, char c) {
1497test_clear( filt *flt, void *data, char c ) {
1498 (void)data; 1573 (void)data;
1499 if( !c || ( c == flt->colour ) || ( (c == '*') && (flt->colour != '-') && (flt->colour != '+') ) ) 1574 if (!c || (c == flt->colour) ||
1500 return RMFILTER_RMANDCONT; 1575 ((c == '*') && (flt->colour != '-') && (flt->colour != '+')))
1576 return RMFILTER_RMANDCONT;
1501 else 1577 else
1502 return RMFILTER_KEEPANDCONT; 1578 return RMFILTER_KEEPANDCONT;
1503} 1579}
1504 1580
1505static int 1581static int test_simplerm(filt *flt, void *data, char colour) {
1506test_simplerm( filt *flt, void *data, char colour) { 1582 if (!strcmp(flt->text, (char *)data))
1507 if( !strcmp( flt->text, (char*)data)) 1583 return test_clear(flt, NULL, colour);
1508 return test_clear(flt, NULL, colour);
1509 else 1584 else
1510 return RMFILTER_KEEPANDCONT; 1585 return RMFILTER_KEEPANDCONT;
1511} 1586}
1512 1587
1513static int 1588static int test_numericrm(filt *flt, void *data, char colour) {
1514test_numericrm( filt *flt, void *data, char colour) { 1589 if (flt->id == (long)data)
1515 if( flt->id == (long)data) 1590 return test_clear(flt, NULL, colour);
1516 return test_clear(flt, NULL, colour);
1517 else 1591 else
1518 return RMFILTER_KEEPANDCONT; 1592 return RMFILTER_KEEPANDCONT;
1519} 1593}
1520 1594
1521/* clears filter list */ 1595/* clears filter list */
1522void 1596void clearfilters(char colour) {
1523clearfilters( char colour ) { 1597 flushout();
1524 flushout( ); 1598 if (removefromfilterlist(test_clear, NULL, colour)) {
1525 if( removefromfilterlist( test_clear, NULL, colour ) ) { 1599 /* There actually WERE items removed */
1526 /* There actually WERE items removed */ 1600 filtertype = analyzefilters();
1527 filtertype = analyzefilters( );
1528 } else { 1601 } else {
1529 writeout(" No matches on filter list. "); 1602 writeout(" No matches on filter list. ");
1530 } 1603 }
1531 showout(); 1604 showout();
1532} 1605}
1533 1606
1534/* removes filter pattern */ 1607/* removes filter pattern */
1535void 1608void removefilter(char *tail) {
1536removefilter( char *tail ) {
1537 int rmv = 0, val; 1609 int rmv = 0, val;
1538 char* end; 1610 char *end;
1539 1611
1540 flushout( ); 1612 flushout();
1541 1613
1542 rmv = removefromfilterlist( test_simplerm, (void *)tail, 0 ); 1614 rmv = removefromfilterlist(test_simplerm, (void *)tail, 0);
1543 if(!rmv) { 1615 if (!rmv) {
1544 val = strtol(tail, &end, 10); 1616 val = strtol(tail, &end, 10);
1545 if( (tail != end) && (!*end) ) 1617 if ((tail != end) && (!*end))
1546 rmv = removefromfilterlist( test_numericrm, (void *)(uintptr_t)val, 0); 1618 rmv = removefromfilterlist(test_numericrm, (void *)(uintptr_t)val, 0);
1547 } 1619 }
1548 1620
1549 if( rmv ) { 1621 if (rmv) {
1550 /* There actually WERE items removed */ 1622 /* There actually WERE items removed */
1551 filtertype = analyzefilters( ); 1623 filtertype = analyzefilters();
1552 } else { 1624 } else {
1553 snprintf( tmpstr, TMPSTRSIZE, " Not on filter list: %s ", tail); 1625 snprintf(tmpstr, TMPSTRSIZE, " Not on filter list: %s ", tail);
1554 writeout( tmpstr ); 1626 writeout(tmpstr);
1555 } 1627 }
1556 showout(); 1628 showout();
1557} 1629}
@@ -1559,139 +1631,158 @@ removefilter( char *tail ) {
1559static unsigned int uniqueidpool = 1; 1631static unsigned int uniqueidpool = 1;
1560 1632
1561/* returns unique id for filter pattern or 0 for failure */ 1633/* returns unique id for filter pattern or 0 for failure */
1562unsigned int 1634unsigned int addfilter(char colour, char *regex) {
1563addfilter( char colour, char *regex ) { 1635 filt *newflt = malloc(sizeof(filt)), **flt = &filterlist;
1564 filt *newflt = malloc( sizeof(filt)), **flt = &filterlist;
1565 1636
1566 if( !newflt ) return 0; 1637 if (!newflt)
1567 flushout( ); 1638 return 0;
1639 flushout();
1568 1640
1569 /* check colour validity */ 1641 /* check colour validity */
1570 if( !check_valid_colour( colour ) ){ 1642 if (!check_valid_colour(colour)) {
1571 free( newflt ); 1643 free(newflt);
1572 writeout( " Not a valid colour code. " ); 1644 writeout(" Not a valid colour code. ");
1573 showout( ); 1645 showout();
1574 return 0; 1646 return 0;
1575 } 1647 }
1576 1648
1577 if( regcomp( &newflt->regex, regex, REG_ICASE | REG_EXTENDED | REG_NEWLINE) ) { 1649 if (regcomp(&newflt->regex, regex, REG_ICASE | REG_EXTENDED | REG_NEWLINE)) {
1578 /* couldn't compile regex ... print error, return */ 1650 /* couldn't compile regex ... print error, return */
1579 free( newflt ); 1651 free(newflt);
1580 1652
1581 snprintf( tmpstr, TMPSTRSIZE, " %s ", regex); 1653 snprintf(tmpstr, TMPSTRSIZE, " %s ", regex);
1582 writeout( " Bad regular expression: "); 1654 writeout(" Bad regular expression: ");
1583 writeout( tmpstr ); 1655 writeout(tmpstr);
1584 showout( ); 1656 showout();
1585 return 0; 1657 return 0;
1586 } else { 1658 } else {
1587 int len = strlen(regex) + 1; 1659 int len = strlen(regex) + 1;
1588 /* grab id from ID pool an increase free ID counter */ 1660 /* grab id from ID pool an increase free ID counter */
1589 newflt->id = uniqueidpool++; 1661 newflt->id = uniqueidpool++;
1590 newflt->colour = colour; 1662 newflt->colour = colour;
1591 newflt->next = NULL; 1663 newflt->next = NULL;
1592 /* take a copy of plain regex text for later identification by user */ 1664 /* take a copy of plain regex text for later identification by user */
1593 newflt->text = malloc( len ); 1665 newflt->text = malloc(len);
1594 memcpy( newflt->text, regex, len ); 1666 memcpy(newflt->text, regex, len);
1595 } 1667 }
1596 1668
1597 /* append new filter to filterlist */ 1669 /* append new filter to filterlist */
1598 while( *flt ) flt=&((*flt)->next); 1670 while (*flt)
1671 flt = &((*flt)->next);
1599 *flt = newflt; 1672 *flt = newflt;
1600 1673
1601 filtertype = analyzefilters( ); 1674 filtertype = analyzefilters();
1602 1675
1603 if ( colour == '-' ) { 1676 if (colour == '-') {
1604 snprintf( tmpstr, TMPSTRSIZE, " \"%s\" successfully added to ignorance list. ( ID = %d). ", (*flt)->text, (*flt)->id); 1677 snprintf(tmpstr, TMPSTRSIZE,
1605 } else if( colour == '+' ) { 1678 " \"%s\" successfully added to ignorance list. ( ID = %d). ",
1606 snprintf( tmpstr, TMPSTRSIZE, " \"%s\" successfully added to zoom list. ( ID = %d). ", (*flt)->text, (*flt)->id); 1679 (*flt)->text, (*flt)->id);
1680 } else if (colour == '+') {
1681 snprintf(tmpstr, TMPSTRSIZE,
1682 " \"%s\" successfully added to zoom list. ( ID = %d). ",
1683 (*flt)->text, (*flt)->id);
1607 } else { 1684 } else {
1608 snprintf( tmpstr, TMPSTRSIZE, " \"%s\" successfully added to hilitelist. (ID = %d). ", (*flt)->text, (*flt)->id); 1685 snprintf(tmpstr, TMPSTRSIZE,
1686 " \"%s\" successfully added to hilitelist. (ID = %d). ",
1687 (*flt)->text, (*flt)->id);
1609 } 1688 }
1610 writeout(tmpstr ); 1689 writeout(tmpstr);
1611 showout( ); 1690 showout();
1612 1691
1613 return newflt->id; 1692 return newflt->id;
1614} 1693}
1615 1694
1616void 1695void listfilters(void) {
1617listfilters( void ) { 1696 filt *flt = filterlist;
1618 filt *flt = filterlist; 1697 int shownhi = 0, shownign = 0, shownzoom = 0;
1619 int shownhi = 0, shownign = 0, shownzoom = 0;
1620 1698
1621 flushout( ); 1699 flushout();
1622 1700
1623 while( flt ) { 1701 while (flt) {
1624 if( (flt->colour != '-') && (flt->colour != '+')) { 1702 if ((flt->colour != '-') && (flt->colour != '+')) {
1625 if(!shownhi) { 1703 if (!shownhi) {
1626 writeout(" Your hilites:"); 1704 writeout(" Your hilites:");
1627 shownhi = 1; 1705 shownhi = 1;
1628 }
1629 snprintf( tmpstr, TMPSTRSIZE, " ID: [% 3d] Color: [%c] Regex: [%s]", flt->id, flt->colour, flt->text);
1630 writeout( tmpstr );
1631 } 1706 }
1632 flt = flt->next; 1707 snprintf(tmpstr, TMPSTRSIZE, " ID: [% 3d] Color: [%c] Regex: [%s]",
1708 flt->id, flt->colour, flt->text);
1709 writeout(tmpstr);
1710 }
1711 flt = flt->next;
1633 } 1712 }
1634 1713
1635 flt = filterlist; 1714 flt = filterlist;
1636 1715
1637 while( flt ) { 1716 while (flt) {
1638 if( flt->colour == '-') { 1717 if (flt->colour == '-') {
1639 if(!shownign) { 1718 if (!shownign) {
1640 if(shownhi) writeout(" "); 1719 if (shownhi)
1641 writeout(" You do ignore:"); 1720 writeout(" ");
1642 shownign = 1; 1721 writeout(" You do ignore:");
1643 } 1722 shownign = 1;
1644 snprintf( tmpstr, TMPSTRSIZE, " ID: [% 3d] Regex: [%s]", flt->id, flt->text);
1645 writeout( tmpstr );
1646 } 1723 }
1647 flt = flt->next; 1724 snprintf(tmpstr, TMPSTRSIZE, " ID: [% 3d] Regex: [%s]",
1725 flt->id, flt->text);
1726 writeout(tmpstr);
1727 }
1728 flt = flt->next;
1648 } 1729 }
1649 1730
1650 flt = filterlist; 1731 flt = filterlist;
1651 1732
1652 while( flt ) { 1733 while (flt) {
1653 if( flt->colour == '+') { 1734 if (flt->colour == '+') {
1654 if(!shownzoom) { 1735 if (!shownzoom) {
1655 if(shownhi || shownign) writeout(" "); 1736 if (shownhi || shownign)
1656 writeout(" On your whitelist:"); 1737 writeout(" ");
1657 shownzoom = 1; 1738 writeout(" On your whitelist:");
1658 } 1739 shownzoom = 1;
1659 snprintf( tmpstr, TMPSTRSIZE, " ID: [% 3d] Regex: [%s]", flt->id, flt->text);
1660 writeout( tmpstr );
1661 } 1740 }
1662 flt = flt->next; 1741 snprintf(tmpstr, TMPSTRSIZE, " ID: [% 3d] Regex: [%s]",
1742 flt->id, flt->text);
1743 writeout(tmpstr);
1744 }
1745 flt = flt->next;
1663 } 1746 }
1664 1747
1665 if( !shownign && !shownhi && !shownzoom) { 1748 if (!shownign && !shownhi && !shownzoom) {
1666 writeout(" No entries on your filter list. "); 1749 writeout(" No entries on your filter list. ");
1667 } 1750 }
1668 showout(); 1751 showout();
1669} 1752}
1670 1753
1671void 1754void handlequery(char *tail) {
1672handlequery( char *tail ) { 1755 if (*tail) {
1673 if( *tail ) {
1674 // ".m %s " -> string + 4 1756 // ".m %s " -> string + 4
1675 if( querypartner && private ) { 1757 if (querypartner && private) {
1676 WINDOW *tmp= private; private = channel; channel = tmp; 1758 WINDOW *tmp = private;
1759 private
1760 = channel;
1761 channel = tmp;
1677 } 1762 }
1678 querypartner = (char *)realloc( querypartner, 5 + strlen( tail )); 1763 querypartner = (char *)realloc(querypartner, 5 + strlen(tail));
1679 if( querypartner ) { 1764 if (querypartner) {
1680 snprintf( querypartner, 5 + strlen( tail ), ".m %s ", tail ); 1765 snprintf(querypartner, 5 + strlen(tail), ".m %s ", tail);
1681 if( private ) { 1766 if (private) {
1682 WINDOW *tmp= private; private = channel; channel = tmp; 1767 WINDOW *tmp = private;
1768 private
1769 = channel;
1770 channel = tmp;
1683 } 1771 }
1684 } 1772 }
1685 resize( 0 ); 1773 resize(0);
1686 } else { 1774 } else {
1687 // QUERY ends 1775 // QUERY ends
1688 if( querypartner ) { 1776 if (querypartner) {
1689 free( querypartner ); 1777 free(querypartner);
1690 querypartner = NULL; 1778 querypartner = NULL;
1691 if( private ) { 1779 if (private) {
1692 WINDOW *tmp= private; private = channel; channel = tmp; 1780 WINDOW *tmp = private;
1781 private
1782 = channel;
1783 channel = tmp;
1693 } 1784 }
1694 resize( 0 ); 1785 resize(0);
1695 } 1786 }
1696 } 1787 }
1697} 1788}
diff --git a/vchat-user.c b/vchat-user.c
index 881a3cf..1ab2048 100755
--- a/vchat-user.c
+++ b/vchat-user.c
@@ -3,42 +3,48 @@
3 3
4*/ 4*/
5 5
6#include <regex.h>
6#include <stdint.h> 7#include <stdint.h>
8#include <stdio.h>
7#include <stdlib.h> 9#include <stdlib.h>
8#include <strings.h> 10#include <strings.h>
9#include <stdio.h>
10#include <sys/time.h> 11#include <sys/time.h>
11#include <regex.h> 12
12#include <readline/readline.h> 13#include <readline/readline.h>
13 14
14#include "vchat.h"
15#include "vchat-user.h" 15#include "vchat-user.h"
16#include "vchat.h"
16 17
17/* version of this module */ 18/* version of this module */
18char *vchat_us_version = "vchat-user.c $Id$"; 19char *vchat_us_version =
19 20 "vchat-user.c $Id$";
20typedef struct 21
21{ 22typedef struct {
22 char *nick; 23 char *nick;
23 enum { UL_NONE = 0x00, UL_ME = 0x01, UL_IN_MY_CHAN = 0x02, UL_NOT_IN_LIST = 0x04 } flags; 24 enum {
25 UL_NONE = 0x00,
26 UL_ME = 0x01,
27 UL_IN_MY_CHAN = 0x02,
28 UL_NOT_IN_LIST = 0x04
29 } flags;
24 uint64_t last_public; 30 uint64_t last_public;
25 uint64_t last_private; 31 uint64_t last_private;
26} user; 32} user;
27static user *g_users; //< all users, incl self 33static user *g_users; //< all users, incl self
28static size_t g_users_count; //< number of users in list 34static size_t g_users_count; //< number of users in list
29static char *g_nick; //< own nick 35static char *g_nick; //< own nick
30static int g_channel; //< own channel 36static int g_channel; //< own channel
31unsigned int ul_case_first = 0; 37unsigned int ul_case_first = 0;
32 38
33static char **g_dict; 39static char **g_dict;
34static size_t g_dict_len; 40static size_t g_dict_len;
35 41
36static int ul_nick_lookup( const char *nick, int *exact_match ) { 42static int ul_nick_lookup(const char *nick, int *exact_match) {
37 int i; 43 int i;
38 44
39 *exact_match = 1; 45 *exact_match = 1;
40 for( i=0; i<g_users_count; ++i ) 46 for (i = 0; i < g_users_count; ++i)
41 if( !strcasecmp( g_users[i].nick, nick ) ) 47 if (!strcasecmp(g_users[i].nick, nick))
42 return i; 48 return i;
43 *exact_match = 0; 49 *exact_match = 0;
44 return i; 50 return i;
@@ -46,78 +52,83 @@ static int ul_nick_lookup( const char *nick, int *exact_match ) {
46 52
47static int64_t ul_now() { 53static int64_t ul_now() {
48 struct timeval now; 54 struct timeval now;
49 gettimeofday(&now,(struct timezone*) 0); 55 gettimeofday(&now, (struct timezone *)0);
50 return ((uint64_t)now.tv_sec * 1000) + ((uint64_t)now.tv_usec / 1000 ); 56 return ((uint64_t)now.tv_sec * 1000) + ((uint64_t)now.tv_usec / 1000);
51} 57}
52 58
53/* own nick and channel setters/getters */ 59/* own nick and channel setters/getters */
54void own_nick_set( char *nick ) { 60void own_nick_set(char *nick) {
55 if( nick ) { 61 if (nick) {
56 int base; 62 int base;
57 if( g_nick ) 63 if (g_nick)
58 base = ul_rename( g_nick, nick ); 64 base = ul_rename(g_nick, nick);
59 else 65 else
60 base = ul_add( nick, 0 ); 66 base = ul_add(nick, 0);
61 if( base >= 0 ) { 67 if (base >= 0) {
62 g_users[base].flags |= UL_ME; 68 g_users[base].flags |= UL_ME;
63 g_nick = g_users[base].nick; 69 g_nick = g_users[base].nick;
64 } 70 }
65 } else 71 } else
66 ul_del( g_nick ); 72 ul_del(g_nick);
67 73
68 setstroption(CF_NICK, nick); 74 setstroption(CF_NICK, nick);
69} 75}
70 76
71void own_channel_set( int channel ) { 77void own_channel_set(int channel) {
72 if( channel != g_channel ) { 78 if (channel != g_channel) {
73 /* Remove all users from my chan, will be re-set on join message */ 79 /* Remove all users from my chan, will be re-set on join message */
74 int i; 80 int i;
75 for( i=0; i<g_users_count; ++i ) 81 for (i = 0; i < g_users_count; ++i)
76 g_users[i].flags &= ~UL_IN_MY_CHAN; 82 g_users[i].flags &= ~UL_IN_MY_CHAN;
77 } 83 }
78 84
79 g_channel = channel; 85 g_channel = channel;
80} 86}
81 87
82char const *own_nick_get( ) { 88char const *own_nick_get() { return g_nick; }
83 return g_nick;
84}
85 89
86int own_nick_check( char *nick ) { 90int own_nick_check(char *nick) {
87 if( !g_nick ) return -1; 91 if (!g_nick)
88 return !strcasecmp(g_nick,nick); 92 return -1;
93 return !strcasecmp(g_nick, nick);
89} 94}
90 95
91int own_channel_get( ) { 96int own_channel_get() { return g_channel; }
92 return g_channel;
93}
94 97
95/* Add/remove/rename */ 98/* Add/remove/rename */
96int ul_add(char *name, int in_my_chan_flag ) { 99int ul_add(char *name, int in_my_chan_flag) {
97 100
98 /* Test if user is already known */ 101 /* Test if user is already known */
99 int exact_match, base = ul_nick_lookup( name, &exact_match ); 102 int exact_match, base = ul_nick_lookup(name, &exact_match);
100 if( !exact_match ) { 103 if (!exact_match) {
101 /* Make space for new user */ 104 /* Make space for new user */
102 user * new_users = realloc( g_users, sizeof( user ) * ( 1 + g_users_count ) ); 105 user *new_users = realloc(g_users, sizeof(user) * (1 + g_users_count));
103 if( !new_users ) return -1; 106 if (!new_users)
107 return -1;
104 108
105 /* Copy the tail */ 109 /* Copy the tail */
106 g_users = new_users; 110 g_users = new_users;
107 memmove( g_users + base + 1, g_users + base, ( g_users_count - base ) * sizeof( user ) ); 111 memmove(g_users + base + 1, g_users + base,
108 g_users[base].nick = strdup( name ); 112 (g_users_count - base) * sizeof(user));
109 g_users[base].flags = UL_NONE; 113 g_users[base].nick = strdup(name);
110 g_users[base].last_public = 0; 114 g_users[base].flags = UL_NONE;
115 g_users[base].last_public = 0;
111 g_users[base].last_private = 0; 116 g_users[base].last_private = 0;
112 117
113 g_users_count++; 118 g_users_count++;
114 } 119 }
115 120
116 g_users[base].flags &= ~UL_NOT_IN_LIST; 121 g_users[base].flags &= ~UL_NOT_IN_LIST;
117 switch( in_my_chan_flag ) { 122 switch (in_my_chan_flag) {
118 case 1: g_users[base].flags |= UL_IN_MY_CHAN; break; 123 case 1:
119 case 0: g_users[base].flags &= ~UL_IN_MY_CHAN; break; 124 g_users[base].flags |= UL_IN_MY_CHAN;
120 case -1: default: break; 125 break;
126 case 0:
127 g_users[base].flags &= ~UL_IN_MY_CHAN;
128 break;
129 case -1:
130 default:
131 break;
121 } 132 }
122 133
123 return base; 134 return base;
@@ -125,30 +136,33 @@ int ul_add(char *name, int in_my_chan_flag ) {
125 136
126int ul_del(char *name) { 137int ul_del(char *name) {
127 /* Test if user is already known */ 138 /* Test if user is already known */
128 int exact_match, base = ul_nick_lookup( name, &exact_match ); 139 int exact_match, base = ul_nick_lookup(name, &exact_match);
129 if( !exact_match ) return -1; 140 if (!exact_match)
141 return -1;
130 142
131 /* Release the name buffer */ 143 /* Release the name buffer */
132 free( g_users[base].nick ); 144 free(g_users[base].nick);
133 if( g_users[base].flags & UL_ME ) g_nick = 0; 145 if (g_users[base].flags & UL_ME)
146 g_nick = 0;
134 147
135 /* Copy the tail */ 148 /* Copy the tail */
136 memmove( g_users + base, g_users + base + 1, ( g_users_count - base - 1 ) * sizeof( user ) ); 149 memmove(g_users + base, g_users + base + 1,
150 (g_users_count - base - 1) * sizeof(user));
137 151
138 /* Shrink user list, realloc to a smaller size never fails */ 152 /* Shrink user list, realloc to a smaller size never fails */
139 g_users = realloc( g_users, sizeof( user ) * --g_users_count ); 153 g_users = realloc(g_users, sizeof(user) * --g_users_count);
140 return 0; 154 return 0;
141} 155}
142 156
143int ul_rename(char *oldname, char *newname) { 157int ul_rename(char *oldname, char *newname) {
144 /* Ensure user */ 158 /* Ensure user */
145 int base = ul_add( oldname, -1 ); 159 int base = ul_add(oldname, -1);
146 if( base >= 0 ) { 160 if (base >= 0) {
147 free( g_users[base].nick ); 161 free(g_users[base].nick);
148 g_users[base].nick = strdup( newname ); 162 g_users[base].nick = strdup(newname);
149 if( g_users[base].flags & UL_ME ) 163 if (g_users[base].flags & UL_ME)
150 g_nick = g_users[base].nick; 164 g_nick = g_users[base].nick;
151 if( g_users[base].flags & UL_IN_MY_CHAN ) 165 if (g_users[base].flags & UL_IN_MY_CHAN)
152 ul_public_action(newname); 166 ul_public_action(newname);
153 } 167 }
154 return base; 168 return base;
@@ -156,23 +170,23 @@ int ul_rename(char *oldname, char *newname) {
156 170
157void ul_clear() { 171void ul_clear() {
158 int i; 172 int i;
159 for( i=0; i<g_users_count; ++i ) 173 for (i = 0; i < g_users_count; ++i)
160 free( g_users[i].nick ); 174 free(g_users[i].nick);
161 free( g_users ); 175 free(g_users);
162 g_nick = 0; 176 g_nick = 0;
163} 177}
164 178
165void ul_rebuild_list( ) { 179void ul_rebuild_list() {
166 int i; 180 int i;
167 for( i=0; i<g_users_count; ++i ) 181 for (i = 0; i < g_users_count; ++i)
168 g_users[i].flags |= UL_NOT_IN_LIST; 182 g_users[i].flags |= UL_NOT_IN_LIST;
169} 183}
170 184
171void ul_clean() { 185void ul_clean() {
172 int i; 186 int i;
173 for( i=0; i<g_users_count; ++i ) { 187 for (i = 0; i < g_users_count; ++i) {
174 if( g_users[i].flags & UL_NOT_IN_LIST ) { 188 if (g_users[i].flags & UL_NOT_IN_LIST) {
175 ul_del( g_users[i].nick ); 189 ul_del(g_users[i].nick);
176 --i; 190 --i;
177 } 191 }
178 } 192 }
@@ -187,237 +201,270 @@ void ul_leave_chan(char *name) {
187void ul_enter_chan(char *name) { 201void ul_enter_chan(char *name) {
188 /* Ensure user and put him on the channel */ 202 /* Ensure user and put him on the channel */
189 int base = ul_add(name, 1); 203 int base = ul_add(name, 1);
190 if( base >= 0 ) 204 if (base >= 0)
191 ul_public_action(name); 205 ul_public_action(name);
192 206
193 /* Reflect in UI */ 207 /* Reflect in UI */
194 if( own_nick_check( name ) ) 208 if (own_nick_check(name))
195 ownjoin( g_channel ); 209 ownjoin(g_channel);
196} 210}
197 211
198void ul_private_action(char *name) { 212void ul_private_action(char *name) {
199 /* Ensure user and keep channel state */ 213 /* Ensure user and keep channel state */
200 int base = ul_add(name, -1); 214 int base = ul_add(name, -1);
201 if( base >= 0 ) 215 if (base >= 0)
202 g_users[base].last_private = ul_now(); 216 g_users[base].last_private = ul_now();
203} 217}
204 218
205void ul_public_action(char *name) { 219void ul_public_action(char *name) {
206 /* Ensure user and put him on the channel */ 220 /* Ensure user and put him on the channel */
207 int base = ul_add(name, 1); 221 int base = ul_add(name, 1);
208 if( base >= 0 ) 222 if (base >= 0)
209 g_users[base].last_public = ul_now(); 223 g_users[base].last_public = ul_now();
210} 224}
211 225
212void ul_add_to_dict(char *dict_items) { 226void ul_add_to_dict(char *dict_items) {
213 char *i; 227 char *i;
214 for(i=strtok(dict_items," ");i;i=strtok(0," ")) { 228 for (i = strtok(dict_items, " "); i; i = strtok(0, " ")) {
215 g_dict = realloc( g_dict, sizeof(char*) * ( 1 + g_dict_len ) ); 229 g_dict = realloc(g_dict, sizeof(char *) * (1 + g_dict_len));
216 if( !g_dict ) exit(1); 230 if (!g_dict)
231 exit(1);
217 g_dict[g_dict_len++] = strdup(i); 232 g_dict[g_dict_len++] = strdup(i);
218 } 233 }
219} 234}
220 235
221/* Finding users ul_finduser? */ 236/* Finding users ul_finduser? */
222char * ul_match_user(char *regex) { 237char *ul_match_user(char *regex) {
223 char *dest = tmpstr; 238 char *dest = tmpstr;
224 int i; 239 int i;
225 regex_t preg; 240 regex_t preg;
226 241
227 *dest = 0; 242 *dest = 0;
228 if( !regcomp( &preg, regex, REG_ICASE | REG_EXTENDED | REG_NEWLINE)) { 243 if (!regcomp(&preg, regex, REG_ICASE | REG_EXTENDED | REG_NEWLINE)) {
229 244
230 /* does the username match? */ 245 /* does the username match? */
231 /* XXX overflow for too many matches */ 246 /* XXX overflow for too many matches */
232 for( i=0; i<g_users_count; ++i ) 247 for (i = 0; i < g_users_count; ++i)
233 if( !regexec( &preg, g_users[i].nick, 0, NULL, 0)) /* append username to list */ 248 if (!regexec(&preg, g_users[i].nick, 0, NULL,
234 dest += snprintf ( dest, 256, " %s", g_users[i].nick); 249 0)) /* append username to list */
235 250 dest += snprintf(dest, 256, " %s", g_users[i].nick);
236 } 251 }
237 regfree( &preg ); 252 regfree(&preg);
238 return tmpstr; 253 return tmpstr;
239} 254}
240 255
241static int ul_compare_private( const void *a, const void *b ) { 256static int ul_compare_private(const void *a, const void *b) {
242 const user *_a = (const user *)a, *_b = (const user *)b; 257 const user *_a = (const user *)a, *_b = (const user *)b;
243 if( _a->last_private > _b->last_private ) return -1; 258 if (_a->last_private > _b->last_private)
259 return -1;
244 return 1; 260 return 1;
245} 261}
246 262
247static int ul_compare_begin_of_line_ncase( const void *a, const void *b ) { 263static int ul_compare_begin_of_line_ncase(const void *a, const void *b) {
248 const user *_a = (const user *)a, *_b = (const user *)b; 264 const user *_a = (const user *)a, *_b = (const user *)b;
249 size_t tmpstr_len; 265 size_t tmpstr_len;
250 int a_i, b_i; 266 int a_i, b_i;
251 267
252 /* First ensure that users in current channel win */ 268 /* First ensure that users in current channel win */
253 if( !(_a->flags & UL_IN_MY_CHAN ) ) return 1; 269 if (!(_a->flags & UL_IN_MY_CHAN))
254 if( !(_b->flags & UL_IN_MY_CHAN ) ) return -1; 270 return 1;
255 271 if (!(_b->flags & UL_IN_MY_CHAN))
256 tmpstr_len = strlen( tmpstr ); 272 return -1;
257 a_i = strncasecmp( _a->nick, tmpstr, tmpstr_len ); 273
258 b_i = strncasecmp( _b->nick, tmpstr, tmpstr_len ); 274 tmpstr_len = strlen(tmpstr);
259 275 a_i = strncasecmp(_a->nick, tmpstr, tmpstr_len);
260 if( a_i && b_i ) return 0; // Both nicks dont match 276 b_i = strncasecmp(_b->nick, tmpstr, tmpstr_len);
261 if( !a_i && b_i ) return -1; // a matches insensitive, b doesnt 277
262 if( a_i && !b_i ) return 1; // b matches insensitive, a doesnt 278 if (a_i && b_i)
279 return 0; // Both nicks dont match
280 if (!a_i && b_i)
281 return -1; // a matches insensitive, b doesnt
282 if (a_i && !b_i)
283 return 1; // b matches insensitive, a doesnt
263 284
264 /* From here both nicks match the prefix, ensure that own_nick 285 /* From here both nicks match the prefix, ensure that own_nick
265 always appears last */ 286 always appears last */
266 if( _a->flags & UL_ME ) return 1; 287 if (_a->flags & UL_ME)
267 if( _b->flags & UL_ME ) return -1; 288 return 1;
289 if (_b->flags & UL_ME)
290 return -1;
268 291
269 /* Now the user with the most recent public activity wins */ 292 /* Now the user with the most recent public activity wins */
270 if( _a->last_public > _b->last_public ) return -1; 293 if (_a->last_public > _b->last_public)
294 return -1;
271 295
272 return 1; 296 return 1;
273} 297}
274 298
275static int ul_compare_begin_of_line_case( const void *a, const void *b ) { 299static int ul_compare_begin_of_line_case(const void *a, const void *b) {
276 const user *_a = (const user *)a, *_b = (const user *)b; 300 const user *_a = (const user *)a, *_b = (const user *)b;
277 size_t tmpstr_len; 301 size_t tmpstr_len;
278 int a_i, b_i, a_s, b_s; 302 int a_i, b_i, a_s, b_s;
279 303
280 /* First ensure that users in current channel win */ 304 /* First ensure that users in current channel win */
281 if( !(_a->flags & UL_IN_MY_CHAN ) ) return 1; 305 if (!(_a->flags & UL_IN_MY_CHAN))
282 if( !(_b->flags & UL_IN_MY_CHAN ) ) return -1; 306 return 1;
283 307 if (!(_b->flags & UL_IN_MY_CHAN))
284 tmpstr_len = strlen( tmpstr ); 308 return -1;
285 a_i = strncasecmp( _a->nick, tmpstr, tmpstr_len ); 309
286 a_s = strncmp ( _a->nick, tmpstr, tmpstr_len ); 310 tmpstr_len = strlen(tmpstr);
287 b_i = strncasecmp( _b->nick, tmpstr, tmpstr_len ); 311 a_i = strncasecmp(_a->nick, tmpstr, tmpstr_len);
288 b_s = strncmp ( _b->nick, tmpstr, tmpstr_len ); 312 a_s = strncmp(_a->nick, tmpstr, tmpstr_len);
289 313 b_i = strncasecmp(_b->nick, tmpstr, tmpstr_len);
290 if( a_i && b_i ) return 0; // Both nicks dont match at all 314 b_s = strncmp(_b->nick, tmpstr, tmpstr_len);
291 if( !a_i && b_i ) return -1; // a matches insensitive, b doesnt 315
292 if( a_i && !b_i ) return 1; // b matches insensitive, a doesnt 316 if (a_i && b_i)
293 317 return 0; // Both nicks dont match at all
294 if( !a_s && b_s ) return -1; // a matches sensitive, b doesnt 318 if (!a_i && b_i)
295 if( a_s && !b_s ) return 1; // b matches sensitive, a doesnt 319 return -1; // a matches insensitive, b doesnt
320 if (a_i && !b_i)
321 return 1; // b matches insensitive, a doesnt
322
323 if (!a_s && b_s)
324 return -1; // a matches sensitive, b doesnt
325 if (a_s && !b_s)
326 return 1; // b matches sensitive, a doesnt
296 327
297 /* From now we know that both match with same quality, ensure 328 /* From now we know that both match with same quality, ensure
298 that own nick always appears last */ 329 that own nick always appears last */
299 if( _a->flags & UL_ME ) return 1; 330 if (_a->flags & UL_ME)
300 if( _b->flags & UL_ME ) return -1; 331 return 1;
332 if (_b->flags & UL_ME)
333 return -1;
301 334
302 /* Now the user with the most recent public activity wins */ 335 /* Now the user with the most recent public activity wins */
303 if( _a->last_public > _b->last_public ) return -1; 336 if (_a->last_public > _b->last_public)
337 return -1;
304 338
305 return 1; 339 return 1;
306} 340}
307 341
308static int ul_compare_middle_ncase( const void *a, const void *b ) { 342static int ul_compare_middle_ncase(const void *a, const void *b) {
309 const user *_a = (const user *)a, *_b = (const user *)b; 343 const user *_a = (const user *)a, *_b = (const user *)b;
310 344
311 /* Ensure that own nick appears last in list */ 345 /* Ensure that own nick appears last in list */
312 if( _a->flags & UL_ME ) return 1; 346 if (_a->flags & UL_ME)
313 if( _b->flags & UL_ME ) return -1; 347 return 1;
348 if (_b->flags & UL_ME)
349 return -1;
314 350
315 return strcasecmp( _a->nick, _b->nick ); 351 return strcasecmp(_a->nick, _b->nick);
316} 352}
317 353
318static int ul_compare_middle_case( const void *a, const void *b ) { 354static int ul_compare_middle_case(const void *a, const void *b) {
319 const user *_a = (const user *)a, *_b = (const user *)b; 355 const user *_a = (const user *)a, *_b = (const user *)b;
320 size_t tmpstr_len; 356 size_t tmpstr_len;
321 int a_s, b_s; 357 int a_s, b_s;
322 358
323 /* Ensure that own nick appears last in list */ 359 /* Ensure that own nick appears last in list */
324 if( _a->flags & UL_ME ) return 1; 360 if (_a->flags & UL_ME)
325 if( _b->flags & UL_ME ) return -1; 361 return 1;
362 if (_b->flags & UL_ME)
363 return -1;
326 364
327 tmpstr_len = strlen( tmpstr ); 365 tmpstr_len = strlen(tmpstr);
328 a_s = strncmp( _a->nick, tmpstr, tmpstr_len ); 366 a_s = strncmp(_a->nick, tmpstr, tmpstr_len);
329 b_s = strncmp( _b->nick, tmpstr, tmpstr_len ); 367 b_s = strncmp(_b->nick, tmpstr, tmpstr_len);
330 368
331 if( !a_s && b_s ) return -1; // a matches sensitive, b doesnt 369 if (!a_s && b_s)
332 if( a_s && !b_s ) return 1; // b matches sensitive, a doesnt 370 return -1; // a matches sensitive, b doesnt
371 if (a_s && !b_s)
372 return 1; // b matches sensitive, a doesnt
333 373
334 /* From now both strings either both or both dont match 374 /* From now both strings either both or both dont match
335 decide their position by case insensitive match */ 375 decide their position by case insensitive match */
336 return strcasecmp( _a->nick, _b->nick ); 376 return strcasecmp(_a->nick, _b->nick);
337} 377}
338 378
339/* Nick completion function for readline */ 379/* Nick completion function for readline */
340char **ul_complete_user(char *text, int start, int end ) { 380char **ul_complete_user(char *text, int start, int end) {
341 char **result = 0; 381 char **result = 0;
342 int i, result_count = 0, dict_result_count = 0; 382 int i, result_count = 0, dict_result_count = 0;
343 383
344 /* Never want readline to complete filenames */ 384 /* Never want readline to complete filenames */
345 rl_attempted_completion_over = 1; 385 rl_attempted_completion_over = 1;
346 386
347 /* Check for amount of custom dict matches */ 387 /* Check for amount of custom dict matches */
348 if( end && ( start != end ) ) 388 if (end && (start != end))
349 for( i=0; i<g_dict_len; ++i ) 389 for (i = 0; i < g_dict_len; ++i)
350 if( !strncasecmp( g_dict[i], text+start, end-start ) ) 390 if (!strncasecmp(g_dict[i], text + start, end - start))
351 ++dict_result_count; 391 ++dict_result_count;
352 392
353 /* Prepare return array ... of max g_users_count (char*) 393 /* Prepare return array ... of max g_users_count (char*)
354 Plus least common prefix in [0] and null terminator 394 Plus least common prefix in [0] and null terminator
355 */ 395 */
356 result = malloc( sizeof(char*) * ( 2 + g_users_count + dict_result_count ) ); 396 result = malloc(sizeof(char *) * (2 + g_users_count + dict_result_count));
357 if( !result ) return 0; 397 if (!result)
398 return 0;
358 399
359 if( start == 0 && end == 0 ) { 400 if (start == 0 && end == 0) {
360 /* Completion on begin of line yields list of everyone we 401 /* Completion on begin of line yields list of everyone we
361 were in private conversation, sorted by time of last .m */ 402 were in private conversation, sorted by time of last .m */
362 qsort( g_users, g_users_count, sizeof(user), ul_compare_private ); 403 qsort(g_users, g_users_count, sizeof(user), ul_compare_private);
363 for( i=0; i<g_users_count; ++i ) 404 for (i = 0; i < g_users_count; ++i)
364 if( g_users[i].last_private ) { 405 if (g_users[i].last_private) {
365 snprintf( tmpstr, TMPSTRSIZE, ".m %s", g_users[i].nick ); 406 snprintf(tmpstr, TMPSTRSIZE, ".m %s", g_users[i].nick);
366 result[++result_count] = strdup(tmpstr); 407 result[++result_count] = strdup(tmpstr);
367 } 408 }
368 /* No common prefix */ 409 /* No common prefix */
369 if( result_count ) result[0] = strdup(""); 410 if (result_count)
411 result[0] = strdup("");
370 412
371 } else if( start == 0 && end > 0 ) { 413 } else if (start == 0 && end > 0) {
372 /* Completion on begin of line with some chars already typed yields 414 /* Completion on begin of line with some chars already typed yields
373 a list of everyone in channel, matching prefix, sorted by last 415 a list of everyone in channel, matching prefix, sorted by last
374 public activity */ 416 public activity */
375 snprintf( tmpstr, end + 1, "%s", text ); 417 snprintf(tmpstr, end + 1, "%s", text);
376 if( ul_case_first ) 418 if (ul_case_first)
377 qsort( g_users, g_users_count, sizeof(user), ul_compare_begin_of_line_case ); 419 qsort(g_users, g_users_count, sizeof(user),
420 ul_compare_begin_of_line_case);
378 else 421 else
379 qsort( g_users, g_users_count, sizeof(user), ul_compare_begin_of_line_ncase ); 422 qsort(g_users, g_users_count, sizeof(user),
423 ul_compare_begin_of_line_ncase);
380 424
381 for( i=0; i<g_users_count; ++i ) 425 for (i = 0; i < g_users_count; ++i)
382 if( ( g_users[i].flags & UL_IN_MY_CHAN ) && !strncasecmp( g_users[i].nick, tmpstr, end ) ) { 426 if ((g_users[i].flags & UL_IN_MY_CHAN) &&
383 snprintf( tmpstr, TMPSTRSIZE, "%s:", g_users[i].nick ); 427 !strncasecmp(g_users[i].nick, tmpstr, end)) {
428 snprintf(tmpstr, TMPSTRSIZE, "%s:", g_users[i].nick);
384 result[++result_count] = strdup(tmpstr); 429 result[++result_count] = strdup(tmpstr);
385 } 430 }
386 431
387 /* Copy matches from personal dict to the end */ 432 /* Copy matches from personal dict to the end */
388 for( i=0; i<g_dict_len; ++i ) 433 for (i = 0; i < g_dict_len; ++i)
389 if( !strncasecmp( g_dict[i], tmpstr, end-start ) ) { 434 if (!strncasecmp(g_dict[i], tmpstr, end - start)) {
390 snprintf( tmpstr, TMPSTRSIZE, "%s:", g_dict[i] ); 435 snprintf(tmpstr, TMPSTRSIZE, "%s:", g_dict[i]);
391 result[++result_count] = strdup(tmpstr); 436 result[++result_count] = strdup(tmpstr);
392 } 437 }
393 438
394 /* Copy common prefix */ 439 /* Copy common prefix */
395 if( result_count ) result[0] = strndup(text, end); 440 if (result_count)
396 } else if( start != end ) { 441 result[0] = strndup(text, end);
442 } else if (start != end) {
397 /* Completion in the middle of the line most likely is a .m XY<TAB> 443 /* Completion in the middle of the line most likely is a .m XY<TAB>
398 and thus should complete all users, sorted alphabetically without 444 and thus should complete all users, sorted alphabetically without
399 preferences. */ 445 preferences. */
400 snprintf( tmpstr, end - start + 1, "%s", text ); 446 snprintf(tmpstr, end - start + 1, "%s", text);
401 if( ul_case_first ) 447 if (ul_case_first)
402 qsort( g_users, g_users_count, sizeof(user), ul_compare_middle_case ); 448 qsort(g_users, g_users_count, sizeof(user), ul_compare_middle_case);
403 else 449 else
404 qsort( g_users, g_users_count, sizeof(user), ul_compare_middle_ncase ); 450 qsort(g_users, g_users_count, sizeof(user), ul_compare_middle_ncase);
405 451
406 for( i=0; i<g_users_count; ++i ) 452 for (i = 0; i < g_users_count; ++i)
407 if( !strncasecmp( g_users[i].nick, tmpstr, end - start ) ) 453 if (!strncasecmp(g_users[i].nick, tmpstr, end - start))
408 result[++result_count] = strdup(g_users[i].nick); 454 result[++result_count] = strdup(g_users[i].nick);
409 455
410 /* Copy matches from personal dict to the end */ 456 /* Copy matches from personal dict to the end */
411 for( i=0; i<g_dict_len; ++i ) 457 for (i = 0; i < g_dict_len; ++i)
412 if( !strncasecmp( g_dict[i], tmpstr, end-start ) ) 458 if (!strncasecmp(g_dict[i], tmpstr, end - start))
413 result[++result_count] = strdup(g_dict[i]); 459 result[++result_count] = strdup(g_dict[i]);
414 460
415 /* Copy common prefix */ 461 /* Copy common prefix */
416 if( result_count ) result[0] = strndup(text, end - start); 462 if (result_count)
463 result[0] = strndup(text, end - start);
417 } /* else: completion of an empty word in the middle yields nothing */ 464 } /* else: completion of an empty word in the middle yields nothing */
418 465
419 if( !result_count ) { 466 if (!result_count) {
420 free( result ); 467 free(result);
421 result = 0; 468 result = 0;
422 } else 469 } else
423 result[++result_count] = 0; 470 result[++result_count] = 0;
diff --git a/vchat.h b/vchat.h
index 54fd006..dbd5a9f 100755
--- a/vchat.h
+++ b/vchat.h
@@ -10,7 +10,7 @@
10 * without even the implied warranty of merchantability or fitness for a 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 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 12 * any direct, indirect, incidental or special damages arising in any way out
13 * of the use of this software. 13 * of the use of this software.
14 * 14 *
15 */ 15 */
16 16
@@ -18,56 +18,126 @@
18typedef enum { SM_IGNORE, SM_INFO, SM_USERINFO, SM_CHANNEL, SM_ERROR } smtype; 18typedef enum { SM_IGNORE, SM_INFO, SM_USERINFO, SM_CHANNEL, SM_ERROR } smtype;
19 19
20/* servermessage structure */ 20/* servermessage structure */
21struct servermessage 21struct servermessage {
22{ 22 char id[4]; /* three-character message id */
23 char id[4]; /* three-character message id */ 23 smtype type; /* message type */
24 smtype type; /* message type */ 24 void (*funct)(char *); /* function used by client */
25 void (*funct) (char *); /* function used by client */ 25 void (*hook)(char *); /* function hook for scripting */
26 void (*hook) (char *); /* function hook for scripting */
27}; 26};
28typedef struct servermessage servermessage; 27typedef struct servermessage servermessage;
29 28
30/* configuration types and variable numbers */ 29/* configuration types and variable numbers */
31typedef enum { CO_NIL, CO_STR, CO_INT } conftype; 30typedef enum { CO_NIL, CO_STR, CO_INT } conftype;
32typedef enum { CF_NIL, CF_NICK, CF_FROM, CF_SERVERHOST, CF_SERVERPORT, 31typedef enum {
33CF_CIPHERSUITE, CF_CONFIGFILE, CF_CERTFILE, CF_KEYFILE, CF_CAFILE, CF_FORMFILE, 32 CF_NIL,
34CF_LOGINSCRIPT, CF_FINGERPRINT, CF_PINFINGER, CF_USESSL, CF_IGNSSL, CF_VERIFYSSL, CF_USECERT, 33 CF_NICK,
35CF_PRIVHEIGHT, CF_PRIVCOLLAPS, CF_INVWINBAR, CF_HSCROLL, CF_CHANNEL, CF_USETIME, CF_USETOPIC, 34 CF_FROM,
36CF_SCROLLBPRIV, CF_SCROLLBACK, CF_SCROLLBPRIVT, CF_SCROLLBACKT, CF_ENCODING, 35 CF_SERVERHOST,
37CF_BELLPRIV, CF_CASEFIRST, CF_AUTORECONN, CF_KEEPALIVE } confopt; 36 CF_SERVERPORT,
37 CF_CIPHERSUITE,
38 CF_CONFIGFILE,
39 CF_CERTFILE,
40 CF_KEYFILE,
41 CF_CAFILE,
42 CF_FORMFILE,
43 CF_LOGINSCRIPT,
44 CF_FINGERPRINT,
45 CF_PINFINGER,
46 CF_USESSL,
47 CF_IGNSSL,
48 CF_VERIFYSSL,
49 CF_USECERT,
50 CF_PRIVHEIGHT,
51 CF_PRIVCOLLAPS,
52 CF_INVWINBAR,
53 CF_HSCROLL,
54 CF_CHANNEL,
55 CF_USETIME,
56 CF_USETOPIC,
57 CF_SCROLLBPRIV,
58 CF_SCROLLBACK,
59 CF_SCROLLBPRIVT,
60 CF_SCROLLBACKT,
61 CF_ENCODING,
62 CF_BELLPRIV,
63 CF_CASEFIRST,
64 CF_AUTORECONN,
65 CF_KEEPALIVE
66} confopt;
38 67
39/* format strings */ 68/* format strings */
40typedef enum { FS_PLAIN, FS_CHAN, FS_PRIV, FS_SERV, FS_GLOB, FS_DBG, FS_ERR, 69typedef enum {
41FS_IDLE, FS_TIME, FS_CONSOLETIME, FS_TOPICW, FS_NOTOPICW, FS_CONSOLE, FS_CONNECTED, FS_CANTCONNECT, 70 FS_PLAIN,
42FS_TOPIC, FS_NOTOPIC, FS_CHGTOPIC, FS_USONLINE, FS_USMATCH, FS_SIGNON, FS_SIGNOFF, 71 FS_CHAN,
43FS_JOIN, FS_LEAVE, FS_NICKCHANGE, FS_UNKNOWNMSG, FS_BOGUSMSG, FS_RXPUBURL, 72 FS_PRIV,
44FS_MYPUBURL, FS_RXPUBMSG, FS_MYPUBMSG, FS_TXPUBMSG, FS_RXPRIVMSG, FS_TXPRIVMSG, 73 FS_SERV,
45FS_BGPRIVMSG, FS_PUBTHOUGHT, FS_TXPUBTHOUGHT, FS_TXPUBNTHOUGHT, FS_PUBACTION, 74 FS_GLOB,
46FS_TXPUBACTION, FS_BGTXPUBACTION, FS_COMMAND, FS_LOCALCOMMAND, FS_BOGUSCOMMAND, 75 FS_DBG,
47FS_SBINF, FS_MISSTYPED, FS_UNKNCMD, FS_BADREGEX, FS_ERR_STRING } formtstr; 76 FS_ERR,
77 FS_IDLE,
78 FS_TIME,
79 FS_CONSOLETIME,
80 FS_TOPICW,
81 FS_NOTOPICW,
82 FS_CONSOLE,
83 FS_CONNECTED,
84 FS_CANTCONNECT,
85 FS_TOPIC,
86 FS_NOTOPIC,
87 FS_CHGTOPIC,
88 FS_USONLINE,
89 FS_USMATCH,
90 FS_SIGNON,
91 FS_SIGNOFF,
92 FS_JOIN,
93 FS_LEAVE,
94 FS_NICKCHANGE,
95 FS_UNKNOWNMSG,
96 FS_BOGUSMSG,
97 FS_RXPUBURL,
98 FS_MYPUBURL,
99 FS_RXPUBMSG,
100 FS_MYPUBMSG,
101 FS_TXPUBMSG,
102 FS_RXPRIVMSG,
103 FS_TXPRIVMSG,
104 FS_BGPRIVMSG,
105 FS_PUBTHOUGHT,
106 FS_TXPUBTHOUGHT,
107 FS_TXPUBNTHOUGHT,
108 FS_PUBACTION,
109 FS_TXPUBACTION,
110 FS_BGTXPUBACTION,
111 FS_COMMAND,
112 FS_LOCALCOMMAND,
113 FS_BOGUSCOMMAND,
114 FS_SBINF,
115 FS_MISSTYPED,
116 FS_UNKNCMD,
117 FS_BADREGEX,
118 FS_ERR_STRING
119} formtstr;
48 120
49/* configoption structure */ 121/* configoption structure */
50struct configoption 122struct configoption {
51{ 123 confopt id;
52 confopt id;
53 conftype type; 124 conftype type;
54 char *varname; 125 char *varname;
55 char *defaultvalue; 126 char *defaultvalue;
56 char *value; 127 char *value;
57 union { 128 union {
58 char **pstr; 129 char **pstr;
59 unsigned int *pint; 130 unsigned int *pint;
60 } localvar; 131 } localvar;
61}; 132};
62 133
63typedef struct configoption configoption; 134typedef struct configoption configoption;
64 135
65/* format strings */ 136/* format strings */
66struct formatstring 137struct formatstring {
67{
68 formtstr id; 138 formtstr id;
69 char *idstring; 139 char *idstring;
70 char *formatstr; 140 char *formatstr;
71}; 141};
72typedef struct formatstring formatstring; 142typedef struct formatstring formatstring;
73 143
@@ -82,16 +152,16 @@ extern unsigned int want_tcp_keepalive;
82#define ERRSTRSIZE 1024 152#define ERRSTRSIZE 1024
83extern char errstr[]; 153extern char errstr[];
84extern const char *vchat_cl_version; 154extern const char *vchat_cl_version;
85void loadcfg (char *file,int complain,void (*lineparser) (char *)); 155void loadcfg(char *file, int complain, void (*lineparser)(char *));
86void loadformats (char *file); 156void loadformats(char *file);
87void cleanup(int signal); 157void cleanup(int signal);
88 158
89/* configuration helper functions from vchat-client.c */ 159/* configuration helper functions from vchat-client.c */
90char *getformatstr (formtstr id); 160char *getformatstr(formtstr id);
91char *getstroption (confopt option); 161char *getstroption(confopt option);
92void setstroption (confopt option, char *string); 162void setstroption(confopt option, char *string);
93int getintoption (confopt option); 163int getintoption(confopt option);
94void setintoption (confopt option, int value); 164void setintoption(confopt option, int value);
95 165
96/* vchat-ui.c */ 166/* vchat-ui.c */
97extern const char *vchat_ui_version; 167extern const char *vchat_ui_version;
@@ -104,66 +174,71 @@ extern char consolestr[];
104extern char *encoding; 174extern char *encoding;
105 175
106/* init / exit functions */ 176/* init / exit functions */
107void initui (void); 177void initui(void);
108void exitui (void); 178void exitui(void);
109 179
110/* called from eventloop in vchat-client.c */ 180/* called from eventloop in vchat-client.c */
111void userinput (void); 181void userinput(void);
112 182
113/* display various messages */ 183/* display various messages */
114int writechan (char *str); 184int writechan(char *str);
115int writepriv (char *str, int maybeep ); 185int writepriv(char *str, int maybeep);
116void writeout (const char *str); 186void writeout(const char *str);
117void showout (void); 187void showout(void);
118void flushout (void); 188void flushout(void);
119#define msgout(STR) {flushout();writeout(STR);showout();} 189#define msgout(STR) \
120void hideout (void); 190 { \
121int writecf (formtstr id, char *str); 191 flushout(); \
192 writeout(STR); \
193 showout(); \
194 }
195void hideout(void);
196int writecf(formtstr id, char *str);
122 197
123extern int outputcountdown; 198extern int outputcountdown;
124 199
125/* update console / topic window */ 200/* update console / topic window */
126void consoleline (char *); 201void consoleline(char *);
127void topicline (char *); 202void topicline(char *);
128 203
129/* prompt for nick or password */ 204/* prompt for nick or password */
130void nickprompt (void); 205void nickprompt(void);
131int passprompt (char *buf, int size, int rwflag, void *userdata); 206int passprompt(char *buf, int size, int rwflag, void *userdata);
132 207
133/* filter functions */ 208/* filter functions */
134void refilterscrollback( void); 209void refilterscrollback(void);
135 210
136unsigned int addfilter ( char colour, char *regex ); 211unsigned int addfilter(char colour, char *regex);
137void removefilter ( char *line ); 212void removefilter(char *line);
138void listfilters ( void ); 213void listfilters(void);
139void clearfilters ( char colour ); 214void clearfilters(char colour);
140 215
141void handlequery ( char *line ); 216void handlequery(char *line);
142 217
143/* vchat-protocol.c */ 218/* vchat-protocol.c */
144extern const char *vchat_io_version; 219extern const char *vchat_io_version;
145void protocol_parsemsg (char *message); 220void protocol_parsemsg(char *message);
146 221
147/* helpers for vchat-user.c */ 222/* helpers for vchat-user.c */
148void ownjoin (int channel); 223void ownjoin(int channel);
149void ownleave (int channel); 224void ownleave(int channel);
150void ownnickchange (const char *newnick); 225void ownnickchange(const char *newnick);
151 226
152/* vchat-commands.c */ 227/* vchat-commands.c */
153extern const char *vchat_cm_version; 228extern const char *vchat_cm_version;
154void command_version ( char *tail); 229void command_version(char *tail);
155 230
156/* user input */ 231/* user input */
157void handleline (char *); 232void handleline(char *);
158 233
159/* struct for defining "/command" handlers */ 234/* struct for defining "/command" handlers */
160typedef struct { 235typedef struct {
161 int number; 236 int number;
162 char name[10]; 237 char name[10];
163 int len; 238 int len;
164 void (*handler)(char *); 239 void (*handler)(char *);
165 char *short_help; 240 char *short_help;
166 char *help; 241 char *help;
167} commandentry; 242} commandentry;
168 243
169/* vchat-tls.c */ 244/* vchat-tls.c */