summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xMakefile9
-rwxr-xr-xvchat-client.c8
-rwxr-xr-xvchat-commands.c31
-rwxr-xr-xvchat-config.h3
-rwxr-xr-xvchat-protocol.c140
-rwxr-xr-xvchat-ui.c113
-rwxr-xr-xvchat-user.c660
-rw-r--r--vchat-user.h40
-rwxr-xr-xvchat.h43
9 files changed, 456 insertions, 591 deletions
diff --git a/Makefile b/Makefile
index 81c4fbe..ae11362 100755
--- a/Makefile
+++ b/Makefile
@@ -6,18 +6,19 @@
6# configuration # 6# configuration #
7############################################## 7##############################################
8 8
9CFLAGS = -Wall -Os 9#CFLAGS = -Wall -Os
10#CFLAGS = -Wall -g -ggdb 10CFLAGS = -Wall -g -ggdb
11 11
12## use this line when you've got an readline before 4.(x|2) 12## use this line when you've got an readline before 4.(x|2)
13#CFLAGS += -DOLDREADLINE 13#CFLAGS += -DOLDREADLINE
14 14
15CFLAGS += $(OLDREADLINE) 15#CFLAGS += $(OLDREADLINE)
16 16
17## you might need one or more of these: 17## you might need one or more of these:
18#CFLAGS += -I/usr/local/ssl/include -L/usr/local/ssl/lib 18#CFLAGS += -I/usr/local/ssl/include -L/usr/local/ssl/lib
19#CFLAGS += -I/usr/local/include -L/usr/local/lib 19#CFLAGS += -I/usr/local/include -L/usr/local/lib
20#CFLAGS += -I/usr/pkg/include -L/usr/pkg/lib 20#CFLAGS += -I/usr/pkg/include -L/usr/pkg/lib
21CFLAGS+=-I../readline-6.2/
21 22
22## enable dietlibc 23## enable dietlibc
23#CC = diet cc 24#CC = diet cc
@@ -29,7 +30,7 @@ CFLAGS += $(OLDREADLINE)
29## the install prefix best is /usr/local 30## the install prefix best is /usr/local
30PREFIX=/usr/local 31PREFIX=/usr/local
31 32
32LIBS = -lreadline -lncurses -lssl -lcrypto 33LIBS = ../readline-6.2/libreadline.a -lncurses -lssl -lcrypto
33OBJS = vchat-client.o vchat-ui.o vchat-protocol.o vchat-user.o vchat-commands.o vchat-ssl.o 34OBJS = vchat-client.o vchat-ui.o vchat-protocol.o vchat-user.o vchat-commands.o vchat-ssl.o
34 35
35 36
diff --git a/vchat-client.c b/vchat-client.c
index 7324cda..d5960a5 100755
--- a/vchat-client.c
+++ b/vchat-client.c
@@ -27,7 +27,9 @@
27#include <signal.h> 27#include <signal.h>
28#include <readline/readline.h> 28#include <readline/readline.h>
29#include <locale.h> 29#include <locale.h>
30
30#include "vchat.h" 31#include "vchat.h"
32#include "vchat-user.h"
31 33
32/* version of this module */ 34/* version of this module */
33char *vchat_cl_version = "$Id$"; 35char *vchat_cl_version = "$Id$";
@@ -432,8 +434,8 @@ void usage( char *name) {
432 printf (" -s set server (default \"%s\")\n",getstroption(CF_SERVERHOST)); 434 printf (" -s set server (default \"%s\")\n",getstroption(CF_SERVERHOST));
433 printf (" -p set port (default %s)\n",getstroption(CF_SERVERPORT)); 435 printf (" -p set port (default %s)\n",getstroption(CF_SERVERPORT));
434 printf (" -c set channel (default %d)\n",getintoption(CF_CHANNEL)); 436 printf (" -c set channel (default %d)\n",getintoption(CF_CHANNEL));
435 if (nick) 437 if (own_nick_get())
436 printf(" -n set nickname (default \"%s\")\n",nick); 438 printf(" -n set nickname (default \"%s\")\n",own_nick_get());
437 else 439 else
438 puts (" -n set nickname"); 440 puts (" -n set nickname");
439 printf (" -f set from (default \"%s\")\n",getstroption(CF_FROM)); 441 printf (" -f set from (default \"%s\")\n",getstroption(CF_FROM));
@@ -468,7 +470,7 @@ main (int argc, char **argv)
468 case 's': setstroption(CF_SERVERHOST,optarg); break; 470 case 's': setstroption(CF_SERVERHOST,optarg); break;
469 case 'p': setstroption(CF_SERVERPORT,optarg); break; 471 case 'p': setstroption(CF_SERVERPORT,optarg); break;
470 case 'c': setintoption(CF_CHANNEL,strtol(optarg,NULL,10)); break; 472 case 'c': setintoption(CF_CHANNEL,strtol(optarg,NULL,10)); break;
471 case 'n': setstroption(CF_NICK,optarg); break; 473 case 'n': own_nick_set(optarg); break;
472 case 'f': setstroption(CF_FROM,optarg); break; 474 case 'f': setstroption(CF_FROM,optarg); break;
473 case 'h': usage(argv[0]); exit(0); break; 475 case 'h': usage(argv[0]); exit(0); break;
474 default : usage(argv[0]); exit(1); 476 default : usage(argv[0]); exit(1);
diff --git a/vchat-commands.c b/vchat-commands.c
index b3c955e..e4f1d99 100755
--- a/vchat-commands.c
+++ b/vchat-commands.c
@@ -26,6 +26,7 @@
26/* local includes */ 26/* local includes */
27#include "vchat.h" 27#include "vchat.h"
28#include "vchat-help.h" 28#include "vchat-help.h"
29#include "vchat-user.h"
29 30
30/* version of this module */ 31/* version of this module */
31char *vchat_cm_version = "$Id$"; 32char *vchat_cm_version = "$Id$";
@@ -155,14 +156,14 @@ static void
155doaction( char *tail ) 156doaction( char *tail )
156{ 157{
157 while( *tail == ' ' ) tail++; 158 while( *tail == ' ' ) tail++;
158 159
159 if( *tail ) { 160 if( *tail ) {
160 /* send users message to server */ 161 /* send users message to server */
161 snprintf (tmpstr, TMPSTRSIZE, ".a %s", tail); 162 snprintf (tmpstr, TMPSTRSIZE, ".a %s", tail);
162 networkoutput (tmpstr); 163 networkoutput (tmpstr);
163 164
164 /* show action in channel window */ 165 /* show action in channel window */
165 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_TXPUBACTION), nick, tail); 166 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_TXPUBACTION), own_nick_get(), tail);
166 writechan (tmpstr); 167 writechan (tmpstr);
167 } else { 168 } else {
168 /* missing action */ 169 /* missing action */
@@ -174,31 +175,31 @@ doaction( char *tail )
174static void 175static void
175privatemessagetx ( char *tail ) { 176privatemessagetx ( char *tail ) {
176 char *mesg; 177 char *mesg;
177 178
178 /* find nick */ 179 /* find nick */
179 while( *tail==' ') tail++; 180 while( *tail==' ') tail++;
180 181
181 /* find message */ 182 /* find message */
182 mesg = tail; 183 mesg = tail;
183 while ( *mesg && *mesg!=' ') mesg++; 184 while ( *mesg && *mesg!=' ') mesg++;
184 185
185 /* check for nick && message */ 186 /* check for nick && message */
186 if(*tail && *mesg) { 187 if(*tail && *mesg) {
187 188
188 /* terminate nick, move to rel start */ 189 /* terminate nick, move to rel start */
189 *mesg++ = '\0'; 190 *mesg++ = '\0';
190 191
191 /* form message and send to server */ 192 /* form message and send to server */
192 snprintf (tmpstr, TMPSTRSIZE, ".m %s %s", tail, mesg); 193 snprintf (tmpstr, TMPSTRSIZE, ".m %s %s", tail, mesg);
193 networkoutput (tmpstr); 194 networkoutput (tmpstr);
194 195
195 /* show message in private window */ 196 /* show message in private window */
196 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_TXPRIVMSG), tail, mesg); 197 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_TXPRIVMSG), tail, mesg);
197 writepriv (tmpstr, 0); 198 writepriv (tmpstr, 0);
198 199
199 /* note we messaged someone */ 200 /* note we messaged someone */
200 ul_msgto(tail); 201 ul_private_action(tail);
201 202
202 } else { 203 } else {
203 /* Bump user to fill in missing parts */ 204 /* Bump user to fill in missing parts */
204 msgout( *tail ? " Won't send empty message. ":" Recipient missing. " ); 205 msgout( *tail ? " Won't send empty message. ":" Recipient missing. " );
@@ -267,11 +268,11 @@ handleline (char *line)
267static void 268static void
268output_default(char *line ) { 269output_default(char *line ) {
269 /* prepare for output on display */ 270 /* prepare for output on display */
270 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_TXPUBMSG), nick, line); 271 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_TXPUBMSG), own_nick_get(), line);
271 272
272 /* send original line to server */ 273 /* send original line to server */
273 networkoutput (line); 274 networkoutput (line);
274 275
275 /* output message to channel window */ 276 /* output message to channel window */
276 writechan (tmpstr); 277 writechan (tmpstr);
277} 278}
@@ -282,7 +283,7 @@ command_user(char *tail)
282{ 283{
283 while( *tail == ' ') tail++; 284 while( *tail == ' ') tail++;
284 if( *tail ) { 285 if( *tail ) {
285 char * out = ul_matchuser( tail); 286 char * out = ul_match_user( tail);
286 if( *out ) { 287 if( *out ) {
287 snprintf( tmpstr, TMPSTRSIZE, getformatstr(FS_USMATCH), tail, out); 288 snprintf( tmpstr, TMPSTRSIZE, getformatstr(FS_USMATCH), tail, out);
288 } else { 289 } else {
diff --git a/vchat-config.h b/vchat-config.h
index 2f0aaaf..96fed27 100755
--- a/vchat-config.h
+++ b/vchat-config.h
@@ -28,7 +28,7 @@ extern unsigned int hscroll;
28 28
29static volatile configoption configoptions[] = { 29static volatile configoption configoptions[] = {
30/* config-option type name in file default value value localvar */ 30/* config-option type name in file default value value localvar */
31 {CF_NICK, CO_STR, "nick", NULL, NULL, { .pstr = &nick } }, 31 {CF_NICK, CO_STR, "nick", NULL, NULL, { NULL } },
32 {CF_FROM, CO_STR, "from", "vc-alpha-0.17", NULL, { NULL } }, 32 {CF_FROM, CO_STR, "from", "vc-alpha-0.17", NULL, { NULL } },
33 {CF_SERVERHOST, CO_STR, "host", "localhost", NULL, { NULL } }, 33 {CF_SERVERHOST, CO_STR, "host", "localhost", NULL, { NULL } },
34 {CF_SERVERPORT, CO_STR, "port", "2325", NULL, { NULL } }, 34 {CF_SERVERPORT, CO_STR, "port", "2325", NULL, { NULL } },
@@ -53,6 +53,7 @@ static volatile configoption configoptions[] = {
53 {CF_SCROLLBPRIVT,CO_INT, "privscrollt",(char *) 0, (char *)-1, { NULL } }, 53 {CF_SCROLLBPRIVT,CO_INT, "privscrollt",(char *) 0, (char *)-1, { NULL } },
54 {CF_SCROLLBACKT, CO_INT, "scrolltime", (char *) 86400, (char *)-1, { NULL } }, 54 {CF_SCROLLBACKT, CO_INT, "scrolltime", (char *) 86400, (char *)-1, { NULL } },
55 {CF_BELLPRIV, CO_INT, "bellonpm", (char *) 0, (char *)-1, { NULL } }, 55 {CF_BELLPRIV, CO_INT, "bellonpm", (char *) 0, (char *)-1, { NULL } },
56 {CF_CASEFIRST, CO_INT, "casefirst", (char *) 0, (char *)-1, { .pint = &ul_case_first } },
56 {CF_AUTORECONN, CO_INT, "autoreconn", (char *) 0, (char *)-1, { NULL } }, 57 {CF_AUTORECONN, CO_INT, "autoreconn", (char *) 0, (char *)-1, { NULL } },
57 {CF_NIL, CO_NIL, NULL, NULL, NULL, { NULL } }, 58 {CF_NIL, CO_NIL, NULL, NULL, NULL, { NULL } },
58}; 59};
diff --git a/vchat-protocol.c b/vchat-protocol.c
index 1a29b07..55c8b55 100755
--- a/vchat-protocol.c
+++ b/vchat-protocol.c
@@ -31,6 +31,7 @@
31 31
32/* local includes */ 32/* local includes */
33#include "vchat.h" 33#include "vchat.h"
34#include "vchat-user.h"
34#include "vchat-ssl.h" 35#include "vchat-ssl.h"
35 36
36/* version of this module */ 37/* version of this module */
@@ -208,6 +209,7 @@ pubaction (char *message)
208 nick = strchr (message, ' '); 209 nick = strchr (message, ' ');
209 nick[0] = '\0'; 210 nick[0] = '\0';
210 nick++; 211 nick++;
212 ul_public_action(nick);
211 213
212 action = strchr (nick, ' '); 214 action = strchr (nick, ' ');
213 action[0] = '\0'; 215 action[0] = '\0';
@@ -228,11 +230,12 @@ pubthoughts (char *message)
228 nick = strchr (message, ' '); 230 nick = strchr (message, ' ');
229 nick[0] = '\0'; 231 nick[0] = '\0';
230 nick++; 232 nick++;
233 ul_public_action(nick);
231 234
232 thoughts = strchr (nick, ' '); 235 thoughts = strchr (nick, ' ');
233 thoughts[0] = '\0'; 236 thoughts[0] = '\0';
234 thoughts++; 237 thoughts++;
235 238
236 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_PUBTHOUGHT),nick,thoughts); 239 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_PUBTHOUGHT),nick,thoughts);
237 writechan (tmpstr); 240 writechan (tmpstr);
238} 241}
@@ -269,7 +272,7 @@ static void
269topicinfo (char *message) 272topicinfo (char *message)
270{ 273{
271 char *channel = NULL, *topic = NULL; 274 char *channel = NULL, *topic = NULL;
272 int tmpchan = 0; 275 int tmpchan = 0, ownchan = own_channel_get();
273 276
274 /* search start of channel number */ 277 /* search start of channel number */
275 channel = strchr (message, ' '); 278 channel = strchr (message, ' ');
@@ -283,12 +286,12 @@ topicinfo (char *message)
283 /* convert channel number to integer */ 286 /* convert channel number to integer */
284 tmpchan = atoi (channel); 287 tmpchan = atoi (channel);
285 288
286 if (tmpchan == chan) { 289 if (tmpchan == ownchan ) {
287 /* show change in topic window */ 290 /* show change in topic window */
288 if (strlen(topic)) 291 if (strlen(topic))
289 snprintf (topicstr, TOPICSTRSIZE, getformatstr(FS_TOPICW), chan, topic); 292 snprintf (topicstr, TOPICSTRSIZE, getformatstr(FS_TOPICW), ownchan, topic);
290 else 293 else
291 snprintf (topicstr, TOPICSTRSIZE, getformatstr(FS_NOTOPICW), chan); 294 snprintf (topicstr, TOPICSTRSIZE, getformatstr(FS_NOTOPICW), ownchan );
292 topicline(NULL); 295 topicline(NULL);
293 } 296 }
294 297
@@ -308,11 +311,12 @@ static void
308topicchange (char *message) 311topicchange (char *message)
309{ 312{
310 char *nick = NULL, *topic = NULL; 313 char *nick = NULL, *topic = NULL;
311 int len; 314 int len, ownchan = own_channel_get();
312 315
313 /* search start of nickname */ 316 /* search start of nickname */
314 nick = strchr (message, ' '); 317 nick = strchr (message, ' ');
315 nick++; 318 nick++;
319 ul_public_action(nick);
316 320
317 /* search start of message before topic, terminate nick */ 321 /* search start of message before topic, terminate nick */
318 topic = strchr (nick, ' '); 322 topic = strchr (nick, ' ');
@@ -330,7 +334,7 @@ topicchange (char *message)
330 topic[len-1] = '\0'; 334 topic[len-1] = '\0';
331 335
332 /* show change in topic window */ 336 /* show change in topic window */
333 snprintf (topicstr, TOPICSTRSIZE, getformatstr(FS_TOPICW), chan, topic); 337 snprintf (topicstr, TOPICSTRSIZE, getformatstr(FS_TOPICW), ownchan, topic);
334 topicline(NULL); 338 topicline(NULL);
335 339
336 /* announce change in channel window */ 340 /* announce change in channel window */
@@ -356,15 +360,14 @@ justloggedin (char *message)
356 str2++; 360 str2++;
357 361
358 /* if we have a new nick, store it */ 362 /* if we have a new nick, store it */
359 if (!nick || strcasecmp (nick, str1)) 363 own_nick_set( str1 );
360 setstroption(CF_NICK,str1);
361 364
362 /* show change in console window */ 365 /* show change in console window */
363 snprintf (consolestr, CONSOLESTRSIZE, getformatstr(FS_CONSOLE), nick, getstroption (CF_SERVERHOST), getstroption (CF_SERVERPORT)); 366 snprintf (consolestr, CONSOLESTRSIZE, getformatstr(FS_CONSOLE), str1, getstroption (CF_SERVERHOST), getstroption (CF_SERVERPORT));
364 consoleline (NULL); 367 consoleline (NULL);
365 368
366 /* announce login as servermessage */ 369 /* announce login as servermessage */
367 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_SIGNON), nick, str2); 370 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_SIGNON), str1, str2);
368 writechan (tmpstr); 371 writechan (tmpstr);
369 372
370 /* we're not logged in, change status and request nicks */ 373 /* we're not logged in, change status and request nicks */
@@ -380,31 +383,15 @@ justloggedin (char *message)
380void 383void
381ownjoin (int channel) 384ownjoin (int channel)
382{ 385{
383 /* change global channel info */
384 chan = channel;
385 networkoutput(".t"); 386 networkoutput(".t");
386 snprintf(tmpstr, TMPSTRSIZE, ".S %d",chan); 387 snprintf(tmpstr, TMPSTRSIZE, ".S %d",channel);
387 networkoutput(tmpstr); 388 networkoutput(tmpstr);
388} 389}
389 390
390/* this user leaves a channel */
391void
392ownleave (int channel)
393{
394 /* change global channel info */
395 chan = 0;
396}
397
398/* this user changes his nick */ 391/* this user changes his nick */
399void 392void
400ownnickchange (char *newnick) 393ownnickchange (char *newnick)
401{ 394{
402 /* free old nick, store copy of new nick */
403 setstroption(CF_NICK,newnick);
404
405 /* show change in console window */
406 snprintf (consolestr, CONSOLESTRSIZE, getformatstr(FS_CONSOLE), nick, getstroption (CF_SERVERHOST), getstroption (CF_SERVERPORT));
407 consoleline (NULL);
408} 395}
409 396
410/* parse and handle a nick error message 397/* parse and handle a nick error message
@@ -431,12 +418,13 @@ nickerr (char *message)
431 if (!loggedin) 418 if (!loggedin)
432 { 419 {
433 /* free bogus nick */ 420 /* free bogus nick */
434 setstroption(CF_NICK,NULL); 421 own_nick_set(NULL);
422
435 /* get new nick via vchat-ui.c */ 423 /* get new nick via vchat-ui.c */
436 nickprompt (); 424 nickprompt ();
437 425
438 /* form login message and send it to server */ 426 /* form login message and send it to server */
439 snprintf (tmpstr, TMPSTRSIZE, ".l %s %s %d", nick, getstroption (CF_FROM), getintoption (CF_CHANNEL)); 427 snprintf (tmpstr, TMPSTRSIZE, ".l %s %s %d", own_nick_get(), getstroption (CF_FROM), getintoption (CF_CHANNEL));
440 networkoutput (tmpstr); 428 networkoutput (tmpstr);
441 } 429 }
442} 430}
@@ -455,13 +443,13 @@ login (char *message) {
455 writecf (FS_SERV,&message[2]); 443 writecf (FS_SERV,&message[2]);
456 444
457 /* we don't know our nick? */ 445 /* we don't know our nick? */
458 if (!nick) { 446 if (!own_nick_get() ) {
459 /* find message after nick */ 447 /* find message after nick */
460 msg = strchr (&message[4], ' '); 448 msg = strchr (&message[4], ' ');
461 if (msg) { 449 if (msg) {
462 /* terminate string before message and copy nick */ 450 /* terminate string before message and copy nick */
463 msg[0] = '\0'; 451 msg[0] = '\0';
464 setstroption(CF_NICK,&message[4]); 452 own_nick_set(&message[4]);
465 } else { 453 } else {
466 /* no string in servers message (huh?), ask user for nick */ 454 /* no string in servers message (huh?), ask user for nick */
467 nickprompt (); 455 nickprompt ();
@@ -469,7 +457,7 @@ login (char *message) {
469 } 457 }
470 458
471 /* form login message and send it to server */ 459 /* form login message and send it to server */
472 snprintf (tmpstr, TMPSTRSIZE, ".l %s %s %d", nick, getstroption (CF_FROM), getintoption (CF_CHANNEL)); 460 snprintf (tmpstr, TMPSTRSIZE, ".l %s %s %d", own_nick_get(), getstroption (CF_FROM), getintoption (CF_CHANNEL));
473 networkoutput (tmpstr); 461 networkoutput (tmpstr);
474} 462}
475 463
@@ -485,11 +473,11 @@ anonlogin (char *message)
485 writecf (FS_SERV,&message[2]); 473 writecf (FS_SERV,&message[2]);
486 474
487 /* we don't know our nick? ask for it! */ 475 /* we don't know our nick? ask for it! */
488 if (!nick) 476 if (!own_nick_get())
489 nickprompt (); 477 nickprompt ();
490 478
491 /* form login message and send it to server */ 479 /* form login message and send it to server */
492 snprintf (tmpstr, TMPSTRSIZE, ".l %s %s %d", nick, getstroption (CF_FROM), getintoption (CF_CHANNEL)); 480 snprintf (tmpstr, TMPSTRSIZE, ".l %s %s %d", own_nick_get(), getstroption (CF_FROM), getintoption (CF_CHANNEL));
493 networkoutput (tmpstr); 481 networkoutput (tmpstr);
494} 482}
495 483
@@ -497,49 +485,53 @@ anonlogin (char *message)
497 * format: 119 %s .. 485 * format: 119 %s ..
498 * vars: %s nick - a users nick */ 486 * vars: %s nick - a users nick */
499static void 487static void
500receivenicks (char *message) 488receivenicks (char *message) {
501{
502 char *str1 = NULL, *str2 = NULL; 489 char *str1 = NULL, *str2 = NULL;
503 int mychan = 0; 490 int chanflag = -1;
504 void (*ul_myfunc)(char*,int);
505 491
506 /* show message to user */ 492 /* show message to user */
507 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_USONLINE), &message[4]); 493 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_USONLINE), &message[4]);
508 writechan (tmpstr); 494 writechan (tmpstr);
509 495
510 /* search for channelnumber */ 496 /* search for channelnumber */
511 str1 = strchr (message, ' '); 497 if( !(str1 = strchr (message, ' ') ) ) return;
512 str1++; 498 str1++;
499
513 if (str1[0] == '*') { 500 if (str1[0] == '*') {
514 if (nicks) return; 501 ul_rebuild_list();
515 ul_myfunc = ul_add;
516 str1++; 502 str1++;
517 } else { 503 } else {
504 int mychan;
518 str2 = str1; 505 str2 = str1;
519 str1 = strchr(str2,' '); 506 str1 = strchr(str2,' ');
520 str1[0] = '\0'; 507 str1[0] = '\0';
521 mychan = atoi(str2); 508 mychan = atoi(str2);
522 ul_myfunc = ul_moveuser; 509 if( mychan != own_channel_get() )
510 return;
511
512 /* Kick all users from the IN_MY_CHANNEL list */
513 own_channel_set( own_channel_get() );
514 chanflag = 1;
523 } 515 }
524 str1++; 516 str1++;
525 517
526 /* while user .. */ 518 /* while user .. */
527 while (str1) 519 while (str1) {
528 { 520 /* search next user */
529 /* search next user */ 521 str2 = strchr (str1, ' ');
530 str2 = strchr (str1, ' '); 522 /* there is another user? terminate this one */
531 /* there is another user? terminate this one */ 523 if (str2) {
532 if (str2) { 524 str2[0] = '\0';
533 str2[0] = '\0'; 525 str2++;
534 str2++; 526 }
535 }
536 527
537 /* add this user via vchat-user.c */ 528 /* add this user via vchat-user.c */
538 ul_myfunc (str1,mychan); 529 ul_add(str1, chanflag);
539 530
540 /* next user .. */ 531 /* next user .. */
541 str1 = str2; 532 str1 = str2;
542 } 533 }
534 ul_clean();
543} 535}
544 536
545/* parse and handle a login message 537/* parse and handle a login message
@@ -581,11 +573,13 @@ usersignoff (char *message)
581 573
582 /* search start of message, terminate nick */ 574 /* search start of message, terminate nick */
583 msg = strchr (nick, ' '); 575 msg = strchr (nick, ' ');
584 msg[0] = '\0'; 576 if( msg ) {
585 msg++; 577 msg[0] = '\0';
578 msg++;
579 }
586 580
587 /* delete this user via vchat-user.c */ 581 /* delete this user via vchat-user.c */
588 ul_del (nick, 0); 582 ul_del (nick);
589 583
590 /* show message to user */ 584 /* show message to user */
591 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_SIGNOFF), nick, msg); 585 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_SIGNOFF), nick, msg);
@@ -620,8 +614,13 @@ userjoin (char *message)
620 /* convert channel to integer */ 614 /* convert channel to integer */
621 chan = atoi (channel); 615 chan = atoi (channel);
622 616
617 /* is it myself joining */
618 if( own_nick_check(nick) )
619 own_channel_set(chan);
620
623 /* notice channel join via vchat-user.c */ 621 /* notice channel join via vchat-user.c */
624 ul_join (nick, chan); 622 if( own_channel_get() == chan )
623 ul_enter_chan(nick);
625 624
626 /* show message to user */ 625 /* show message to user */
627 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_JOIN), nick, msg, chan); 626 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_JOIN), nick, msg, chan);
@@ -657,7 +656,7 @@ userleave (char *message)
657 chan = atoi (channel); 656 chan = atoi (channel);
658 657
659 /* notice channel leave via vchat-user.c */ 658 /* notice channel leave via vchat-user.c */
660 ul_leave (nick, chan); 659 ul_leave_chan(nick);
661 660
662 /* show message to user */ 661 /* show message to user */
663 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_LEAVE), nick, msg, chan); 662 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_LEAVE), nick, msg, chan);
@@ -689,7 +688,13 @@ usernickchange (char *message)
689 msg++; 688 msg++;
690 689
691 /* notice nickchange via vchat-user.c */ 690 /* notice nickchange via vchat-user.c */
692 ul_nickchange (oldnick, newnick); 691 ul_rename (oldnick, newnick);
692
693 if( own_nick_check(newnick) ) {
694 /* show change in console window */
695 snprintf (consolestr, CONSOLESTRSIZE, getformatstr(FS_CONSOLE), newnick, getstroption (CF_SERVERHOST), getstroption (CF_SERVERPORT));
696 consoleline (NULL);
697 }
693 698
694 /* show message to user */ 699 /* show message to user */
695 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_NICKCHANGE), oldnick, newnick, msg); 700 snprintf (tmpstr, TMPSTRSIZE, getformatstr(FS_NICKCHANGE), oldnick, newnick, msg);
@@ -710,11 +715,13 @@ parsemsg (char *message)
710 str2[0] = '\0'; 715 str2[0] = '\0';
711 str2++; 716 str2++;
712 if (str2[0] == ' ') str2++; 717 if (str2[0] == ' ') str2++;
713 if (!strncasecmp(nick,str2,strlen(nick))) 718 if (own_nick_check(str1))
714 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_MYPUBMSG),str1,str2); 719 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_MYPUBMSG),str1,str2);
715 else 720 else
716 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_RXPUBMSG),str1,str2); 721 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_RXPUBMSG),str1,str2);
717 writechan (tmpstr); 722 writechan (tmpstr);
723
724 ul_public_action(str1);
718 } 725 }
719 else if (message[0] == '[') 726 else if (message[0] == '[')
720 { 727 {
@@ -723,10 +730,11 @@ parsemsg (char *message)
723 str2[0] = '\0'; 730 str2[0] = '\0';
724 str2++; 731 str2++;
725 if (str2[0] == ' ') str2++; 732 if (str2[0] == ' ') str2++;
726 if (!strncasecmp(nick,str2,strlen(nick))) 733 if (own_nick_check( str1 ))
727 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_MYPUBURL),str1,str2); 734 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_MYPUBURL),str1,str2);
728 else 735 else
729 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_RXPUBURL),str1,str2); 736 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_RXPUBURL),str1,str2);
737 ul_public_action(str1);
730 writechan (tmpstr); 738 writechan (tmpstr);
731 } 739 }
732 /* message starts with '*'? must be private */ 740 /* message starts with '*'? must be private */
@@ -739,7 +747,7 @@ parsemsg (char *message)
739 if (str2[0] == ' ') str2++; 747 if (str2[0] == ' ') str2++;
740 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_RXPRIVMSG),str1,str2); 748 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_RXPRIVMSG),str1,str2);
741 writepriv (tmpstr, 1); 749 writepriv (tmpstr, 1);
742 ul_msgfrom(str1); 750 ul_private_action(str1);
743 } 751 }
744 /* message starts with a number? must be a servermessage */ 752 /* message starts with a number? must be a servermessage */
745 else if ((message[0] >= '0') && (message[0] <= '9')) 753 else if ((message[0] >= '0') && (message[0] <= '9'))
diff --git a/vchat-ui.c b/vchat-ui.c
index 136fdee..bb94653 100755
--- a/vchat-ui.c
+++ b/vchat-ui.c
@@ -30,9 +30,11 @@
30#include <readline/history.h> 30#include <readline/history.h>
31#include <openssl/pem.h> 31#include <openssl/pem.h>
32#include <regex.h> 32#include <regex.h>
33#include "vchat.h"
34#include <wchar.h> 33#include <wchar.h>
35 34
35#include "vchat.h"
36#include "vchat-user.h"
37
36/* version of this module */ 38/* version of this module */
37char *vchat_ui_version = "$Id$"; 39char *vchat_ui_version = "$Id$";
38 40
@@ -667,37 +669,6 @@ shrinkprivwin (void) {
667 } 669 }
668} 670}
669 671
670/* nick completion callback for readline */
671static char **
672vcccomplete (char *text, int start, int end)
673{
674 char **matches;
675 matches = (char **) NULL;
676 /* are we at start of line, with no characters typed? message completion */
677 if (start == 0 && end == 0)
678 {
679#ifdef OLDREADLINE
680 matches = completion_matches (text, (CPFunction *) ul_mnickcomp);
681#else
682 matches = rl_completion_matches (text, (rl_compentry_func_t *) ul_mnickcomp);
683#endif
684 rl_attempted_completion_over = 1;
685 }
686 /* start of line? get matches for channel! */
687 else if (start == 0)
688 {
689#ifdef OLDREADLINE
690 matches = completion_matches (text, (CPFunction *) ul_cnickcomp);
691#else
692 matches = rl_completion_matches (text, (rl_compentry_func_t *) ul_cnickcomp);
693#endif
694 /* no, we want no 'normal' completion if started typing on the beginning
695 * of the line */
696 rl_attempted_completion_over = 1;
697 }
698 return (matches);
699}
700
701/* clear message window */ 672/* clear message window */
702void 673void
703clearpriv () 674clearpriv ()
@@ -1057,10 +1028,6 @@ drawwin (WINDOW *win, struct sb_data *sb )
1057 } 1028 }
1058} 1029}
1059 1030
1060#ifdef OLDREADLINE
1061typedef int rl_command_func_t __P((int, int));
1062#endif
1063
1064/* initialize curses and display */ 1031/* initialize curses and display */
1065void 1032void
1066initui (void) 1033initui (void)
@@ -1224,9 +1191,6 @@ initui (void)
1224 rl_generic_bind (ISFUNC, "\\M-[5~", (void *)scrollup, keymap); 1191 rl_generic_bind (ISFUNC, "\\M-[5~", (void *)scrollup, keymap);
1225 rl_generic_bind (ISFUNC, "\\M-[6~", (void *)scrolldown, keymap); 1192 rl_generic_bind (ISFUNC, "\\M-[6~", (void *)scrolldown, keymap);
1226 1193
1227// rl_bind_keyseq( "\\M-[5~", (rl_command_func_t *)scrollup );
1228// rl_bind_keyseq( "\\M-[6~", (rl_command_func_t *)scrolldown );
1229
1230 /* bind TAB to menu complete from readline */ 1194 /* bind TAB to menu complete from readline */
1231 rl_bind_key ('\t', (rl_command_func_t *) rl_menu_complete); 1195 rl_bind_key ('\t', (rl_command_func_t *) rl_menu_complete);
1232 1196
@@ -1235,66 +1199,17 @@ initui (void)
1235 1199
1236 /* set up nick completion functions .. */ 1200 /* set up nick completion functions .. */
1237 rl_ignore_completion_duplicates = 0; 1201 rl_ignore_completion_duplicates = 0;
1238#ifdef OLDREADLINE 1202 rl_sort_completion_matches = 0;
1239 rl_completion_entry_function = (Function *) ul_nickcomp; 1203 rl_attempted_completion_function = (rl_completion_func_t *) ul_complete_user;
1240 rl_attempted_completion_function = vcccomplete;
1241#else
1242 rl_completion_entry_function = (rl_compentry_func_t *) ul_nickcomp;
1243 rl_attempted_completion_function = (rl_completion_func_t *) vcccomplete;
1244#endif
1245 1204
1246 /* .. and 'line completed' callback */ 1205 /* .. and 'line completed' callback */
1247#ifdef OLDREADLINE
1248 rl_callback_handler_install ("", linecomplete);
1249#else
1250 rl_callback_handler_install ("", (rl_vcpfunc_t *) linecomplete); 1206 rl_callback_handler_install ("", (rl_vcpfunc_t *) linecomplete);
1251#endif
1252
1253 1207
1254 if( getintoption(CF_PRIVCOLLAPS) ) 1208 if( getintoption(CF_PRIVCOLLAPS) )
1255 toggleprivwin(); 1209 toggleprivwin();
1256 1210
1257/* 1211 resize(0);
1258 writeout( ">> Ctrl-X <<");
1259
1260 if (errstr[0] != '\0') {
1261 writeout(errstr);
1262 writeout( " ");
1263 }
1264
1265 writeout (vchat_cl_version);
1266 writeout (vchat_ui_version);
1267 writeout (vchat_io_version);
1268 writeout (vchat_us_version);
1269 writeout (vchat_cm_version);
1270 showout( );
1271*/
1272
1273 resize(0);
1274}
1275
1276/* render colorized line to window */
1277/* DOES NOT WRAP !!!
1278 CURRENTLY UNUSED
1279 Enable, when needed
1280
1281static void
1282writecolorized( WINDOW *win, char *string) {
1283 ncurs_attr old_att, new_att;
1284 int i;
1285
1286 WATTR_GET( win, old_att );
1287 new_att = old_att;
1288 for( i = 0; string[ i ]; i++ )
1289 if( string[ i ] == 1 ) {
1290 docolorize( string[++i], &new_att, old_att);
1291 } else {
1292 WATTR_SET( win, new_att );
1293 waddch( win, string[ i ] );
1294 }
1295 WATTR_SET( win, old_att );
1296} 1212}
1297*/
1298 1213
1299/* render consoleline to screen */ 1214/* render consoleline to screen */
1300void 1215void
@@ -1403,18 +1318,18 @@ exitui (void)
1403void 1318void
1404nickprompt (void) 1319nickprompt (void)
1405{ 1320{
1406 if (nick) 1321 char * newnick = 0;
1322
1323 if (own_nick_get())
1407 return; 1324 return;
1408 1325
1409 /* prompt user for nick unless he enters one */ 1326 /* prompt user for nick unless he enters one */
1410 consoleline("Please enter your nickname:"); 1327 consoleline("Please enter your nickname:");
1411 while (!nick || !nick[0]) 1328 while (!newnick)
1412 { 1329 newnick = readline("");
1413 if (nick) 1330
1414 free (nick); 1331 own_nick_set(newnick);
1415 nick = readline(""); 1332 setstroption(CF_NICK,newnick);
1416 }
1417 setstroption(CF_NICK,nick);
1418 1333
1419 /* try to get readlines stats clean again */ 1334 /* try to get readlines stats clean again */
1420 //rl_free_line_state (); 1335 //rl_free_line_state ();
diff --git a/vchat-user.c b/vchat-user.c
index 4b44080..cd0df14 100755
--- a/vchat-user.c
+++ b/vchat-user.c
@@ -1,426 +1,364 @@
1/* 1/*
2 * vchat-client - alpha version 2 * vchat-client
3 * vchat-user.c - functions working with the userlist 3
4 * 4*/
5 * Copyright (C) 2001 Andreas Kotes <count@flatline.de> 5
6 * 6#include <stdint.h>
7 * This program is free software. It can be redistributed and/or modified,
8 * provided that this copyright notice is kept intact. This program is
9 * distributed in the hope that it will be useful, but without any warranty;
10 * without even the implied warranty of merchantability or fitness for a
11 * particular purpose. In no event shall the copyright holder be liable for
12 * any direct, indirect, incidental or special damages arising in any way out
13 * of the use of this software.
14 *
15 */
16
17/* general includes */
18#include <stdlib.h> 7#include <stdlib.h>
8#include <strings.h>
19#include <stdio.h> 9#include <stdio.h>
20#include <string.h> 10#include <sys/time.h>
21#include <sys/types.h>
22#include <regex.h> 11#include <regex.h>
23#include <time.h>
24#include <readline/readline.h> 12#include <readline/readline.h>
25#include "vchat.h"
26 13
27struct user 14#include "vchat.h"
28{ 15#include "vchat-user.h"
29 char *nick; /* nick of user */
30 int chan; /* channel user is on */
31 int chan_valid; /* are we sure he is? */
32 int client_pv; /* client protocol version */
33 int messaged; /* did we message with this user? */
34 struct user *next;/* next user in linked list */
35};
36 16
37/* version of this module */ 17/* version of this module */
38char *vchat_us_version = "$Id$"; 18char *vchat_us_version = "$Id$";
39 19
40/* externally used variables */ 20typedef struct
41/* current nick */
42char *nick = NULL;
43/* current channel */
44int chan = 0;
45/* userlist */
46user *nicks = NULL;
47
48/* add user to userlist */
49void
50ul_add (char *name, int ignored)
51{
52 user *tmp = NULL;
53
54 /* no list? create one */
55 if (!nicks)
56 {
57 nicks = malloc (sizeof (user));
58 memset(nicks,0,sizeof(user));
59 nicks->nick = strdup(name);
60 nicks->chan = 0; /* users default in channel 0 */
61 nicks->chan_valid = 0;
62 nicks->next = NULL;
63 }
64 else
65 {
66 /* travel list until end */
67 tmp = nicks;
68 while (tmp)
69 {
70 /* it is this user? return */
71 if (!strcmp (name, tmp->nick))
72 return;
73 /* is there a next user? */
74 if (tmp->next)
75 tmp = tmp->next;
76 else
77 {
78 /* create one */
79 tmp->next = malloc (sizeof (user));
80 tmp = tmp->next;
81 memset(tmp,0,sizeof(user));
82 tmp->nick = strdup(name);
83 tmp->chan = 0;
84 tmp->chan_valid = 0;
85 tmp->next = NULL;
86 tmp = NULL;
87 }
88 }
89 }
90#ifndef OLDREADLINE
91 rl_last_func = NULL;
92#endif
93}
94
95/* delete user from userlist */
96void
97ul_del (char *name, int ignored)
98{ 21{
99 user *tmp = NULL, *ltmp = NULL; 22 char *nick;
100 23 enum { UL_NONE = 0x00, UL_ME = 0x01, UL_IN_MY_CHAN = 0x02, UL_NOT_IN_LIST = 0x04 } flags;
101 /* is it this client? return */ 24 uint64_t last_public;
102 if (nick && !strcmp (nick, name)) 25 uint64_t last_private;
103 return; 26} user;
104 /* no list? return */ 27static user *g_users; //< all users, incl self
105 if (!nicks) 28static size_t g_users_count; //< number of users in list
106 return; 29static char *g_nick; //< own nick
107 /* the user on top of list? */ 30static int g_channel; //< own channel
108 if (!strcmp (name, nicks->nick)) 31int ul_case_first = 0;
109 { 32
110 /* remove user and copy next in list */ 33static int ul_nick_lookup( const char *nick, int *exact_match ) {
111 tmp = nicks->next; 34 int i;
112 free (nicks); 35
113 nicks = tmp; 36 *exact_match = 1;
114 return; 37 for( i=0; i<g_users_count; ++i )
115 } 38 if( !strcasecmp( g_users[i].nick, nick ) )
116 /* travel through list, skip first entry */ 39 return i;
117 ltmp = nicks; 40 *exact_match = 0;
118 tmp = nicks->next; 41 return i;
119 while (tmp)
120 {
121 /* is it this user? */
122 if (!strcmp (name, tmp->nick))
123 {
124 /* hook next to last, discard this */
125 ltmp->next = tmp->next;
126 free (tmp);
127 return;
128 }
129 /* advance in list */
130 ltmp = tmp;
131 tmp = tmp->next;
132 }
133#ifndef OLDREADLINE
134 rl_last_func = NULL;
135#endif
136} 42}
137 43
138/* let user join a channel */ 44static int64_t ul_now() {
139void 45 struct timeval now;
140ul_join (char *name, int channel) 46 gettimeofday(&now,(struct timezone*) 0);
141{ 47 return ((uint64_t)now.tv_sec * 1000) + ((uint64_t)now.tv_usec / 1000 );
142 /* is it this client? handle and return */
143 if (nick && !strcmp (nick, name))
144 {
145 ownjoin (channel);
146 return;
147 } else ul_moveuser(name,channel);
148#ifndef OLDREADLINE
149 rl_last_func = NULL;
150#endif
151} 48}
152 49
153user * 50/* own nick and channel setters/getters */
154ul_finduser (char *name) { 51void own_nick_set( char *nick ) {
155 user *tmp = nicks; 52 if( nick ) {
156 snprintf( tmpstr, TMPSTRSIZE, "%s:", name); 53 int base;
157 54 if( g_nick )
158 /* search user */ 55 base = ul_rename( g_nick, nick );
159 while (tmp) 56 else
160 { 57 base = ul_add( nick, 0 );
161 /* is it this user? */ 58 if( base >= 0 ) {
162 if (!strcmp (name, tmp->nick) || !strcmp(tmpstr, tmp->nick)) 59 g_users[base].flags |= UL_ME;
163 { 60 g_nick = g_users[base].nick;
164 return tmp;
165 }
166 /* advance in list */
167 tmp = tmp->next;
168 } 61 }
169 return NULL; 62 } else
170} 63 ul_del( g_nick );
171 64
172char * 65 setstroption(CF_NICK, nick);
173ul_matchuser( char *regex) { 66}
174 user *tmp = nicks;
175 char *dest = tmpstr;
176 regex_t preg;
177 67
178 *dest = 0; 68void own_channel_set( int channel ) {
179 if( !regcomp( &preg, regex, REG_ICASE | REG_EXTENDED | REG_NEWLINE)) { 69 if( channel != g_channel ) {
180 while( tmp ) { 70 /* Remove all users from my chan, will be re-set on join message */
181 /* does the username match? */ 71 int i;
182 if( !regexec( &preg, tmp->nick, 0, NULL, 0)) /* append username to list */ 72 for( i=0; i<g_users_count; ++i )
183 dest += snprintf ( dest, 256, " %s", tmp->nick); 73 g_users[i].flags &= ~UL_IN_MY_CHAN;
184 tmp = tmp->next;
185 }
186 } 74 }
187 regfree( &preg ); 75
188 return tmpstr; 76 g_channel = channel;
189} 77}
190 78
191static void 79char const *own_nick_get( ) {
192ul_usertofront( user *who ) { 80 return g_nick;
193 user *tmp = nicks; 81}
194 82
195 while( tmp->next && ( tmp->next != who ) ) 83int own_nick_check( char *nick ) {
196 tmp = tmp->next; 84 if( !g_nick ) return -1;
85 return !strncasecmp(g_nick,nick,strlen(g_nick) );
86}
197 87
198 if( tmp->next == who ) { 88int own_channel_get( ) {
199 tmp->next = tmp->next->next; 89 return g_channel;
200 who->next = nicks;
201 nicks = who;
202 }
203#ifndef OLDREADLINE
204 rl_last_func = NULL;
205#endif
206} 90}
207 91
208void 92/* Add/remove/rename */
209ul_msgto (char *name) { 93int ul_add(char *name, int in_my_chan_flag ) {
210 user *tmp = ul_finduser(name); 94
95 /* Test if user is already known */
96 int exact_match, base = ul_nick_lookup( name, &exact_match );
97 if( !exact_match ) {
98 /* Make space for new user */
99 user * new_users = realloc( g_users, sizeof( user ) * ( 1 + g_users_count ) );
100 if( !new_users ) return -1;
101
102 /* Copy the tail */
103 g_users = new_users;
104 memmove( g_users + base + 1, g_users + base, ( g_users_count - base ) * sizeof( user ) );
105 g_users[base].nick = strdup( name );
106 g_users[base].flags = UL_NONE;
107 g_users[base].last_public = 0;
108 g_users[base].last_private = 0;
109
110 g_users_count++;
111 }
211 112
212 if (tmp) { 113 g_users[base].flags &= ~UL_NOT_IN_LIST;
213 tmp->messaged |= 1; 114 switch( in_my_chan_flag ) {
214 ul_usertofront( tmp ); 115 case 1: g_users[base].flags |= UL_IN_MY_CHAN; break;
116 case 0: g_users[base].flags &= ~UL_IN_MY_CHAN; break;
117 case -1: default: break;
215 } 118 }
119
120 return base;
216} 121}
217 122
218void 123int ul_del(char *name) {
219ul_msgfrom (char *name) { 124 /* Test if user is already known */
220 user *tmp = ul_finduser(name); 125 int exact_match, base = ul_nick_lookup( name, &exact_match );
126 if( !exact_match ) return -1;
221 127
222 if (tmp) { 128 /* Release the name buffer */
223 tmp->messaged |= 2; 129 free( g_users[base].nick );
224 ul_usertofront( tmp ); 130 if( g_users[base].flags & UL_ME ) g_nick = 0;
225 }
226}
227 131
228/* set channel of user */ 132 /* Copy the tail */
229void 133 memmove( g_users + base, g_users + base + 1, ( g_users_count - base - 1 ) * sizeof( user ) );
230ul_moveuser (char *name, int channel) {
231 user *tmp = ul_finduser(name);
232 134
233 if (tmp) { 135 /* Shrink user list, realloc to a smaller size never fails */
234 /* store channel information and mark it valid */ 136 g_users = realloc( g_users, sizeof( user ) * --g_users_count );
235 tmp->chan = channel; 137 return 0;
236 tmp->chan_valid = 1;
237 }
238#ifndef OLDREADLINE
239 rl_last_func = NULL;
240#endif
241} 138}
242 139
243/* let user leave a channel */ 140int ul_rename(char *oldname, char *newname) {
244void 141 /* Ensure user */
245ul_leave (char *name, int channel) 142 int base = ul_add( oldname, -1 );
246{ 143 if( base >= 0 ) {
247 user *tmp = ul_finduser(name); 144 free( g_users[base].nick );
248 /* is it this client? handle and return */ 145 g_users[base].nick = strdup( newname );
249 if (nick && !strcmp (nick, name)) 146 if( g_users[base].flags & UL_ME )
250 { 147 g_nick = g_users[base].nick;
251 ownleave (channel); 148 if( g_users[base].flags & UL_IN_MY_CHAN )
252 return; 149 ul_public_action(newname);
253 } 150 }
151 return base;
152}
254 153
255 if (tmp) 154void ul_clear() {
256 { 155 int i;
257 /* mark channel information invalid */ 156 for( i=0; i<g_users_count; ++i )
258 tmp->chan_valid = 0; 157 free( g_users[i].nick );
259 return; 158 free( g_users );
260 } 159 g_nick = 0;
261#ifndef OLDREADLINE
262 rl_last_func = NULL;
263#endif
264} 160}
265 161
266/* let user change nick */ 162void ul_rebuild_list( ) {
267void 163 int i;
268ul_nickchange (char *oldnick, char *newnick) 164 for( i=0; i<g_users_count; ++i )
269{ 165 g_users[i].flags |= UL_NOT_IN_LIST;
270 user *tmp = ul_finduser(oldnick);
271 /* is it this client? handle and return */
272 if (nick && !strcmp (nick, oldnick))
273 {
274 ownnickchange (newnick);
275 return;
276 }
277 if (tmp)
278 {
279 /* exchange nickname */
280 free (tmp->nick);
281 tmp->nick = strdup (newnick);
282 return;
283 }
284#ifndef OLDREADLINE
285 rl_last_func = NULL;
286#endif
287} 166}
288 167
289/* clear userlist */ 168void ul_clean() {
290void 169 int i;
291ul_clear (void) 170 for( i=0; i<g_users_count; ++i ) {
292{ 171 if( g_users[i].flags & UL_NOT_IN_LIST ) {
293 user *tmp = nicks, *tmp2; 172 ul_del( g_users[i].nick );
294 /* walk list */ 173 --i;
295 while (tmp)
296 {
297 /* store next, delete this */
298 tmp2 = tmp->next;
299 free (tmp->nick);
300 free (tmp);
301 /* advance */
302 tmp = tmp2;
303 } 174 }
304 /* mark list empty */ 175 }
305 nicks = NULL;
306#ifndef OLDREADLINE
307 rl_last_func = NULL;
308#endif
309} 176}
310 177
311int ulnc_casenick(user *tmp, const char *text, int len, int value) { 178/* Seting state */
312 return (!strncmp(tmp->nick, text, len)); 179void ul_leave_chan(char *name) {
180 /* Ensure user and kick him off the channel */
181 ul_add(name, 0);
313} 182}
314 183
315int ulnc_ncasenick(user *tmp, const char *text, int len, int value) { 184void ul_enter_chan(char *name) {
316 return (!strncasecmp(tmp->nick, text, len)); 185 /* Ensure user and put him on the channel */
186 int base = ul_add(name, 1);
187 if( base >= 0 )
188 ul_public_action(name);
189
190 /* Reflect in UI */
191 if( own_nick_check( name ) )
192 ownjoin( g_channel );
317} 193}
318 194
319char * 195void ul_private_action(char *name) {
320ulnc_complete (const char *text, int state, int value, int (*checkfn)(user *,const char *,int,int)) { 196 /* Ensure user and keep channel state */
321 static int len; 197 int base = ul_add(name, -1);
322 static user *tmp; 198 if( base >= 0 )
323 char *name; 199 g_users[base].last_private = ul_now();
324 200}
325 /* first round? reset pointers! */
326 if (!state)
327 {
328 tmp = nicks;
329 len = strlen (text);
330 }
331 201
332 /* walk list .. */ 202void ul_public_action(char *name) {
333 while (tmp) 203 /* Ensure user and put him on the channel */
334 { 204 int base = ul_add(name, 1);
335 /* we found a match? */ 205 if( base >= 0 )
336 if (checkfn(tmp,text,len,value)) 206 g_users[base].last_public = ul_now();
337 {
338 /* copy nick, advance pointer for next call, return nick */
339 name = tmp->nick;
340 tmp = tmp->next;
341 return name;
342 }
343 else
344 {
345 tmp = tmp->next;
346 }
347 }
348 return NULL;
349} 207}
350 208
351/* nick completion functions for readline in vchat-ui.c */ 209/* Finding users ul_finduser? */
352char * 210char * ul_match_user(char *regex) {
353ul_nickcomp (const char *text, int state) 211 char *dest = tmpstr;
354{ 212 int i;
355 int ncasemode = 1; 213 regex_t preg;
356 char *name = NULL; 214
357 if (!state) ncasemode = 0; 215 *dest = 0;
358 if (!ncasemode) { 216 if( !regcomp( &preg, regex, REG_ICASE | REG_EXTENDED | REG_NEWLINE)) {
359 name = ulnc_complete(text,state,0,ulnc_casenick); 217
360 if (!state && !name) ncasemode = 1; 218 /* does the username match? */
219 /* XXX overflow for too many matches */
220 for( i=0; i<g_users_count; ++i )
221 if( !regexec( &preg, g_users[i].nick, 0, NULL, 0)) /* append username to list */
222 dest += snprintf ( dest, 256, " %s", g_users[i].nick);
223
361 } 224 }
362 if (ncasemode) 225 regfree( &preg );
363 name = ulnc_complete(text,state,0,ulnc_ncasenick); 226 return tmpstr;
364 if (name)
365 return strdup(name);
366 else
367 return NULL;
368} 227}
369 228
370int ulnc_casenickc(user *tmp, const char *text, int len, int value) { 229static int ul_compare_private( const void *a, const void *b ) {
371 return (!strncmp(tmp->nick, text, len) && (tmp->chan_valid) && (tmp->chan == value)); 230 const user *_a = (const user *)a, *_b = (const user *)b;
231 if( _a->last_private > _b->last_private ) return -1;
232 return 1;
372} 233}
373 234
374int ulnc_ncasenickc(user *tmp, const char *text, int len, int value) { 235static int ul_compare_begin_of_line_ncase( const void *a, const void *b ) {
375 return (!strncasecmp(tmp->nick, text, len) && (tmp->chan_valid) && (tmp->chan == value)); 236 const user *_a = (const user *)a, *_b = (const user *)b;
376} 237 size_t tmpstr_len;
238 int a_i, b_i;
377 239
378/* nick completion for channel, used by vchat-ui.c */ 240 /* First ensure that users in current channel win */
379char * 241 if( !(_a->flags & UL_IN_MY_CHAN ) ) return 1;
380ul_cnickcomp (const char *text, int state) 242 if( !(_b->flags & UL_IN_MY_CHAN ) ) return -1;
381{
382 int ncasemode = 1;
383 static char *name = NULL;
384 243
385 if (!state) ncasemode = 0; 244 tmpstr_len = strlen( tmpstr );
386 if (!ncasemode) { 245 a_i = strncasecmp( _a->nick, tmpstr, tmpstr_len );
387 name = ulnc_complete(text,state,chan,ulnc_casenickc); 246 b_i = strncasecmp( _b->nick, tmpstr, tmpstr_len );
388 if (!state && !name) ncasemode = 1; 247
389 } 248 if( a_i && b_i ) return 0; // Both nicks dont match
390 if (ncasemode) 249 if( !a_i && b_i ) return -1; // a matches insensitive, b doesnt
391 name = ulnc_complete(text,state,chan,ulnc_ncasenickc); 250 if( a_i && !b_i ) return 1; // b matches insensitive, a doesnt
392 if (name) { 251
393 snprintf(tmpstr,TMPSTRSIZE,"%s:",name); 252 /* From here both nicks match the prefix, ensure that own_nick
394 return strdup(tmpstr); 253 always appears last */
395 } else 254 if( _a->flags & UL_ME ) return 1;
396 return NULL; 255 if( _b->flags & UL_ME ) return -1;
256
257 /* Now the user with the most recent public activity wins */
258 if( _a->last_public > _b->last_public ) return -1;
259
260 return 1;
397} 261}
398 262
399int ulnc_casenickm(user *tmp, const char *text, int len, int value) { 263static int ul_compare_begin_of_line_case( const void *a, const void *b ) {
400 return (!strncmp(tmp->nick, text, len) && (tmp->messaged)); 264 const user *_a = (const user *)a, *_b = (const user *)b;
265 size_t tmpstr_len;
266 int a_i, b_i, a_s, b_s;
267
268 /* First ensure that users in current channel win */
269 if( !(_a->flags & UL_IN_MY_CHAN ) ) return 1;
270 if( !(_b->flags & UL_IN_MY_CHAN ) ) return -1;
271
272 tmpstr_len = strlen( tmpstr );
273 a_i = strncasecmp( _a->nick, tmpstr, tmpstr_len );
274 a_s = strncmp ( _a->nick, tmpstr, tmpstr_len );
275 b_i = strncasecmp( _b->nick, tmpstr, tmpstr_len );
276 b_s = strncmp ( _b->nick, tmpstr, tmpstr_len );
277
278 if( a_i && b_i ) return 0; // Both nicks dont match at all
279 if( !a_i && b_i ) return -1; // a matches insensitive, b doesnt
280 if( a_i && !b_i ) return 1; // b matches insensitive, a doesnt
281
282 if( !a_s && b_s ) return -1; // a matches sensitive, b doesnt
283 if( a_s && !b_s ) return 1; // b matches sensitive, a doesnt
284
285 /* From now we know that both match with same quality, ensure
286 that own nick always appears last */
287 if( _a->flags & UL_ME ) return 1;
288 if( _b->flags & UL_ME ) return -1;
289
290 /* Now the user with the most recent public activity wins */
291 if( _a->last_public > _b->last_public ) return -1;
292
293 return 1;
401} 294}
402 295
403int ulnc_ncasenickm(user *tmp, const char *text, int len, int value) { 296static int ul_compare_middle( const void *a, const void *b ) {
404 return (!strncasecmp(tmp->nick, text, len) && (tmp->messaged)); 297 const user *_a = (const user *)a, *_b = (const user *)b;
298 return strcasecmp( _b->nick, _a->nick );
405} 299}
406 300
407/* nick completion for channel, used by vchat-ui.c */ 301/* Nick completion function for readline */
408char * 302char **ul_complete_user(char *text, int start, int end ) {
409ul_mnickcomp (const char *text, int state) 303 char **result = 0;
410{ 304 int i, result_count = 0;
411 int ncasemode = 1; 305
412 static char *name = NULL; 306 /* Never want readline to complete filenames */
307 rl_attempted_completion_over = 1;
308
309 /* Prepare return array ... of max g_users_count (char*)
310 Plus least common prefix in [0] and null terminator
311 */
312 result = malloc( sizeof(char*) * ( 2 + g_users_count ) );
313 if( !result ) return 0;
314
315 if( start == 0 && end == 0 ) {
316 /* Completion on begin of line yields list of everyone we
317 were in private conversation, sorted by time of last .m */
318 qsort( g_users, g_users_count, sizeof(user), ul_compare_private );
319 for( i=0; i<g_users_count; ++i )
320 if( g_users[i].last_private ) {
321 snprintf( tmpstr, TMPSTRSIZE, ".m %s", g_users[i].nick );
322 result[++result_count] = strdup(tmpstr);
323 }
324 /* No common prefix */
325 if( result_count ) result[0] = strdup("");
326
327 } else if( start == 0 && end > 0 ) {
328 /* Completion on begin of line with some chars already typed yields
329 a list of everyone in channel, matching prefix, sorted by last
330 public activity */
331 snprintf( tmpstr, end + 1, "%s", text );
332 if( ul_case_first )
333 qsort( g_users, g_users_count, sizeof(user), ul_compare_begin_of_line_case );
334 else
335 qsort( g_users, g_users_count, sizeof(user), ul_compare_begin_of_line_ncase );
413 336
414 if (!state) ncasemode = 0; 337 for( i=0; i<g_users_count; ++i )
415 if (!ncasemode) { 338 if( ( g_users[i].flags & UL_IN_MY_CHAN ) && !strncasecmp( g_users[i].nick, tmpstr, end ) ) {
416 name = ulnc_complete(text,state,chan,ulnc_casenickm); 339 snprintf( tmpstr, TMPSTRSIZE, "%s:", g_users[i].nick );
417 if (!state && !name) ncasemode = 1; 340 result[++result_count] = strdup(tmpstr);
418 } 341 }
419 if (ncasemode) 342 /* Copy common prefix */
420 name = ulnc_complete(text,state,chan,ulnc_ncasenickm); 343 if( result_count ) result[0] = strndup(text, end);
421 if (name) { 344 } else if( start != end ) {
422 snprintf(tmpstr,TMPSTRSIZE,".m %s",name); 345 /* Completion in the middle of the line most likely is a .m XY<TAB>
423 return strdup(tmpstr); 346 and thus should complete all users, sorted alphabetically without
347 preferences. */
348 snprintf( tmpstr, end - start + 1, "%s", text );
349 qsort( g_users, g_users_count, sizeof(user), ul_compare_middle );
350 for( i=0; i<g_users_count; ++i )
351 if( !strncasecmp( g_users[i].nick, tmpstr, end - start ) )
352 result[++result_count] = strdup(g_users[i].nick);
353 /* Copy common prefix */
354 if( result_count ) result[0] = strndup(text, end - start);
355 } /* else: completion of an empty word in the middle yields nothing */
356
357 if( !result_count ) {
358 free( result );
359 result = 0;
424 } else 360 } else
425 return NULL; 361 result[++result_count] = 0;
362
363 return result;
426} 364}
diff --git a/vchat-user.h b/vchat-user.h
new file mode 100644
index 0000000..a731ad6
--- /dev/null
+++ b/vchat-user.h
@@ -0,0 +1,40 @@
1/*
2 * vchat-user.h
3 * User list handling
4 *
5 * Author: Dirk Engling <erdgeist@erdgeist.org>
6 * License: Beerware
7*/
8#ifndef __VCHAT_USER_H__
9#define __VCHAT_USER_H__
10
11extern char *vchat_us_version;
12
13/* own nick and channel */
14void own_channel_set( int channel );
15int own_channel_get( );
16void own_nick_set( char *nick );
17char const *own_nick_get( );
18int own_nick_check( char * nick );
19
20/* Add/remove/rename */
21int ul_add(char *name, int chan_flag); /* -1: keep, 0: notinchan, 1: inchan */
22int ul_del(char *name);
23int ul_rename(char *oldname, char *newname);
24void ul_clear();
25void ul_rebuild_list();
26void ul_clean();
27
28/* Seting state */
29void ul_leave_chan(char *name);
30void ul_enter_chan(char *name);
31void ul_private_action(char *name);
32void ul_public_action(char *name);
33
34/* Finding users ul_finduser */
35char *ul_match_user(char *regex);
36
37/* Nick completion function for readline */
38char **ul_complete_user(char *text, int start, int end );
39
40#endif
diff --git a/vchat.h b/vchat.h
index 1b29155..541fd21 100755
--- a/vchat.h
+++ b/vchat.h
@@ -14,12 +14,6 @@
14 * 14 *
15 */ 15 */
16 16
17/* user structure */
18struct user;
19typedef struct user user;
20/* userlist from vchat-user.c */
21extern user *nicks;
22
23/* servermessage types */ 17/* servermessage types */
24typedef 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;
25 19
@@ -39,7 +33,7 @@ typedef enum { CF_NIL, CF_NICK, CF_FROM, CF_SERVERHOST, CF_SERVERPORT,
39CF_CIPHERSUITE, CF_CONFIGFILE, CF_CERTFILE, CF_KEYFILE, CF_FORMFILE, CF_LOGINSCRIPT, 33CF_CIPHERSUITE, CF_CONFIGFILE, CF_CERTFILE, CF_KEYFILE, CF_FORMFILE, CF_LOGINSCRIPT,
40CF_USESSL, CF_IGNSSL, CF_USECERT, CF_PRIVHEIGHT, CF_PRIVCOLLAPS, CF_HSCROLL, CF_CHANNEL, CF_USETIME, 34CF_USESSL, CF_IGNSSL, CF_USECERT, CF_PRIVHEIGHT, CF_PRIVCOLLAPS, CF_HSCROLL, CF_CHANNEL, CF_USETIME,
41CF_USETOPIC, CF_SCROLLBPRIV, CF_SCROLLBACK, CF_SCROLLBPRIVT, CF_SCROLLBACKT, 35CF_USETOPIC, CF_SCROLLBPRIV, CF_SCROLLBACK, CF_SCROLLBPRIVT, CF_SCROLLBACKT,
42CF_ENCODING, CF_BELLPRIV, CF_AUTORECONN } confopt; 36CF_ENCODING, CF_BELLPRIV, CF_CASEFIRST, CF_AUTORECONN } confopt;
43 37
44/* format strings */ 38/* format strings */
45typedef enum { FS_PLAIN, FS_CHAN, FS_PRIV, FS_SERV, FS_GLOB, FS_DBG, FS_ERR, 39typedef enum { FS_PLAIN, FS_CHAN, FS_PRIV, FS_SERV, FS_GLOB, FS_DBG, FS_ERR,
@@ -80,9 +74,6 @@ typedef struct formatstring formatstring;
80#define TMPSTRSIZE 1024 74#define TMPSTRSIZE 1024
81static char tmpstr[TMPSTRSIZE]; 75static char tmpstr[TMPSTRSIZE];
82 76
83extern char *nick;
84extern int chan;
85
86extern unsigned int loggedin; 77extern unsigned int loggedin;
87 78
88/* vchat-client.c */ 79/* vchat-client.c */
@@ -100,38 +91,6 @@ void setstroption (confopt option, char *string);
100int getintoption (confopt option); 91int getintoption (confopt option);
101void setintoption (confopt option, int value); 92void setintoption (confopt option, int value);
102 93
103/* vchat-user.c */
104extern char *vchat_us_version;
105
106/* add / delete user */
107void ul_add (char *nick, int ignored);
108void ul_del (char *nick, int ignored);
109
110/* clear userlist */
111void ul_clear ();
112
113/* channel join / leave */
114void ul_join (char *nick, int channel);
115void ul_leave (char *nick, int channel);
116
117/* nickchange */
118void ul_nickchange (char *oldnick, char *newnick);
119
120/* place user in channel */
121void ul_moveuser (char *nick, int channel);
122
123/* message nick completion */
124void ul_msgto (char *nick);
125void ul_msgfrom (char *nick);
126
127/* nick-completion for vchat-ui.c */
128char *ul_nickcomp (const char *text, int state);
129char *ul_cnickcomp (const char *text, int state);
130char *ul_mnickcomp (const char *text, int state);
131
132/* try to find user by substring */
133char *ul_matchuser (char *substr);
134
135/* vchat-ui.c */ 94/* vchat-ui.c */
136extern char *vchat_ui_version; 95extern char *vchat_ui_version;
137 96