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