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