1 /* $Id: im_response.c 2860 2010-03-16 20:36:48Z kuhlmann $ */
2 /* Copyright: This file may be distributed under version 2 of the GPL licence. */
3
4 #include "climm.h"
5 #include <assert.h>
6 #include "im_response.h"
7 #include "oscar_base.h"
8 #include "util_rl.h"
9 #include "util_tabs.h"
10 #include "contact.h"
11 #include "im_request.h"
12 #include "util.h"
13 #include "conv.h"
14 #include "preferences.h"
15 #include "connection.h"
16 #include "util_otr.h"
17
18 /** LOGGING **/
cb_status_log(Contact * cont,parentmode_t pm,change_t ch,const char * text)19 static int cb_status_log (Contact *cont, parentmode_t pm, change_t ch, const char *text)
20 {
21 #if ENABLE_CONT_HIER
22 if (cont->parent)
23 return 0;
24 #endif
25 assert (cont->serv);
26 putlog (cont->serv, NOW, cont, cont->status, cont->nativestatus,
27 ch == st_on ? LOG_ONLINE : ch == st_ch ? LOG_CHANGE : LOG_OFFLINE, 0xFFFF, "");
28 return 0;
29 }
30
cb_srv_msg_log(Contact * cont,parentmode_t pm,time_t stamp,fat_srv_msg_t * msg)31 static int cb_srv_msg_log (Contact *cont, parentmode_t pm, time_t stamp, fat_srv_msg_t *msg)
32 {
33 #if ENABLE_CONT_HIER
34 if (cont->parent)
35 return 0;
36 #endif
37 putlog (cont->serv, stamp, cont, IcqToStatus (msg->nativestatus), msg->nativestatus,
38 (msg->type == MSG_AUTH_ADDED) ? LOG_ADDED : LOG_RECVD, msg->type,
39 msg->msgtext);
40 return 0;
41 }
42
43
44 /** SHELL SCRIPTING **/
45 #ifdef MSGEXEC
cb_status_exec(Contact * cont,parentmode_t pm,change_t ch,const char * text)46 static int cb_status_exec (Contact *cont, parentmode_t pm, change_t ch, const char *text)
47 {
48 if (prG->event_cmd && *prG->event_cmd)
49 EventExec (cont, prG->event_cmd, ch == st_on ? ev_on : ch == st_ch ? ev_status : ev_off, cont->nativestatus, cont->status, NULL);
50 return 0;
51 }
52
cb_srv_msg_exec(Contact * cont,parentmode_t pm,time_t stamp,fat_srv_msg_t * msg)53 static int cb_srv_msg_exec (Contact *cont, parentmode_t pm, time_t stamp, fat_srv_msg_t *msg)
54 {
55 if (prG->event_cmd && *prG->event_cmd)
56 EventExec (cont, prG->event_cmd, ev_msg, msg->type, cont->status, msg->msgtext);
57 return 0;
58 }
59 #endif /* MSGEXEC */
60
61
62 /** HISTORY **/
63 #define HISTSIZE 100
64 struct History_s
65 {
66 Server *serv;
67 Contact *cont;
68 time_t stamp;
69 char *msg;
70 UWORD inout;
71 };
72 typedef struct History_s History;
73
74 static History hist[HISTSIZE];
75
HistMsg(Server * serv,Contact * cont,time_t stamp,const char * msg,UWORD inout)76 void HistMsg (Server *serv, Contact *cont, time_t stamp, const char *msg, UWORD inout)
77 {
78 int i, j, k;
79
80 if (hist[HISTSIZE - 1].serv && hist[0].serv)
81 {
82 free (hist[0].msg);
83 for (i = 0; i < HISTSIZE - 1; i++)
84 hist[i] = hist[i + 1];
85 hist[HISTSIZE - 1].serv = NULL;
86 }
87
88 for (i = k = j = 0; j < HISTSIZE - 1 && hist[j].serv; j++)
89 if (cont == hist[j].cont)
90 {
91 if (!k)
92 i = j;
93 if (++k == 10)
94 {
95 free (hist[i].msg);
96 for ( ; i < HISTSIZE - 1; i++)
97 hist[i] = hist[i + 1];
98 hist[HISTSIZE - 1].serv = NULL;
99 j--;
100 }
101 }
102
103 hist[j].serv = serv;
104 hist[j].cont = cont;
105 hist[j].stamp = stamp;
106 hist[j].msg = strdup (msg);
107 hist[j].inout = inout;
108 }
109
HistShow(Contact * cont)110 void HistShow (Contact *cont)
111 {
112 int i;
113
114 for (i = 0; i < HISTSIZE; i++)
115 if (hist[i].serv && (!cont || hist[i].cont == cont))
116 rl_printf ("%s%s %s %s %s" COLMSGINDENT "%s\n",
117 COLDEBUG, s_time (&hist[i].stamp),
118 ReadLinePrintWidth (hist[i].cont->nick,
119 hist[i].inout == HIST_IN ? COLINCOMING : COLACK,
120 hist[i].inout == HIST_IN ? "<-" : "->",
121 &uiG.nick_len),
122 COLNONE, COLMESSAGE, hist[i].msg);
123 }
cb_int_msg_hist(Contact * cont,parentmode_t pm,time_t stamp,fat_int_msg_t * msg)124 static int cb_int_msg_hist (Contact *cont, parentmode_t pm, time_t stamp, fat_int_msg_t *msg)
125 {
126 #if ENABLE_CONT_HIER
127 if (cont->parent)
128 return 0;
129 #endif
130 HistMsg (cont->serv, cont, stamp, msg->msgtext, HIST_OUT);
131 return 0;
132 }
133
cb_srv_msg_hist(Contact * cont,parentmode_t pm,time_t stamp,fat_srv_msg_t * msg)134 static int cb_srv_msg_hist (Contact *cont, parentmode_t pm, time_t stamp, fat_srv_msg_t *msg)
135 {
136 #if ENABLE_CONT_HIER
137 if (cont->parent)
138 return 0;
139 #endif
140 switch (msg->type & ~MSGF_MASS)
141 {
142 case MSG_NORM_SUBJ:
143 if (msg->subj)
144 {
145 HistMsg (cont->serv, cont, stamp, msg->subj, HIST_IN);
146 HistMsg (cont->serv, cont, stamp, msg->msgtext, HIST_IN);
147 break;
148 }
149 case MSG_NORM:
150 default:
151 HistMsg (cont->serv, cont, stamp, msg->msgtext, HIST_IN);
152 break;
153 case MSG_FILE:
154 break;
155 case MSG_AUTO:
156 break;
157 case MSGF_GETAUTO | MSG_GET_AWAY:
158 break;
159 case MSGF_GETAUTO | MSG_GET_OCC:
160 break;
161 case MSGF_GETAUTO | MSG_GET_NA:
162 break;
163 case MSGF_GETAUTO | MSG_GET_DND:
164 break;
165 case MSGF_GETAUTO | MSG_GET_FFC:
166 break;
167 case MSGF_GETAUTO | MSG_GET_VER:
168 break;
169 case MSG_URL:
170 HistMsg (cont->serv, cont, stamp, msg->msgtext, HIST_IN);
171 break;
172 case MSG_AUTH_REQ:
173 case MSG_AUTH_DENY:
174 case MSG_AUTH_GRANT:
175 case MSG_AUTH_ADDED:
176 case MSG_AUTH_DONE:
177 break;
178 case MSG_EMAIL:
179 case MSG_WEB:
180 break;
181 case MSG_CONTACT:
182 break;
183 }
184 return 0;
185 }
186
187 /** AUTOFINGER FEATURE **/
188
cb_status_auto(Contact * cont,parentmode_t pm,change_t ch,const char * text)189 static int cb_status_auto (Contact *cont, parentmode_t pm, change_t ch, const char *text)
190 {
191 assert (cont->serv);
192 if (ch != st_off && ContactPrefVal (cont, CO_AUTOAUTO))
193 {
194 int cdata = 0;
195
196 switch (ContactClearInv (cont->status))
197 {
198 case imr_dnd: cdata = MSGF_GETAUTO | MSG_GET_DND; break;
199 case imr_occ: cdata = MSGF_GETAUTO | MSG_GET_OCC; break;
200 case imr_na: cdata = MSGF_GETAUTO | MSG_GET_NA; break;
201 case imr_away: cdata = MSGF_GETAUTO | MSG_GET_AWAY; break;
202 case imr_ffc: cdata = MSGF_GETAUTO | MSG_GET_FFC; break;
203 case imr_online:
204 case imr_offline: cdata = 0;
205 }
206
207 if (cdata)
208 IMCliMsg (cont, cdata, "\xff", NULL);
209 }
210 return 0;
211 }
212
cb_srv_msg_auto(Contact * cont,parentmode_t pm,time_t stamp,fat_srv_msg_t * msg)213 static int cb_srv_msg_auto (Contact *cont, parentmode_t pm, time_t stamp, fat_srv_msg_t *msg)
214 {
215 if (prG->flags & FLAG_AUTOFINGER && ~cont->updated & UPF_AUTOFINGER &&
216 ~cont->updated & UPF_SERVER && ~cont->updated & UPF_DISC)
217 {
218 cont->updated |= UPF_AUTOFINGER;
219 IMCliInfo (cont->serv, cont, 0);
220 }
221 return 0;
222 }
223
224
225 /** TEXT UI **/
226
227 #define MSGICQACKSTR ">>>"
228 #define MSGICQACKSTROTR "&>>"
229 #define MSGICQACKSTROTRSEC "%>>"
230 #define MSGICQ5ACKSTR "> >"
231 #define MSGICQ5ACKSTROTR "& >"
232 #define MSGICQ5ACKSTROTRSEC "% >"
233 #define MSGTCPACKSTR ConvTranslit ("\xc2\xbb\xc2\xbb\xc2\xbb", "}}}")
234 #define MSGTCPACKSTROTR ConvTranslit ("&\xc2\xbb\xc2\xbb", "&}}")
235 #define MSGTCPACKSTROTRSEC ConvTranslit ("%\xc2\xbb\xc2\xbb", "%}}")
236 #define MSGSSLACKSTR ConvTranslit ("\xc2\xbb%\xc2\xbb", "}%}")
237 #define MSGSSLACKSTROTR ConvTranslit ("&%\xc2\xbb", "&%}")
238 #define MSGSSLACKSTROTRSEC ConvTranslit ("%%\xc2\xbb", "%%}")
239 #define MSGTYPE2ACKSTR ConvTranslit (">>\xc2\xbb", ">>}")
240 #define MSGTYPE2ACKSTROTR ConvTranslit ("&>\xc2\xbb", "&>}")
241 #define MSGTYPE2ACKSTROTRSEC ConvTranslit ("%>\xc2\xbb", "%>}")
242 #define MSGICQRECSTR "<<<"
243 #define MSGICQRECSTROTR "<<&"
244 #define MSGICQRECSTROTRSEC "<<%"
245 #define MSGTCPRECSTR ConvTranslit ("\xc2\xab\xc2\xab\xc2\xab", "{{{")
246 #define MSGTCPRECSTROTR ConvTranslit ("\xc2\xab\xc2\xab&", "{{&")
247 #define MSGTCPRECSTROTRSEC ConvTranslit ("\xc2\xab\xc2\xab%", "{{%")
248 #define MSGSSLRECSTR ConvTranslit ("\xc2\xab%\xc2\xab", "{%{")
249 #define MSGSSLRECSTROTR ConvTranslit ("\xc2\xab%&", "{%&")
250 #define MSGSSLRECSTROTRSEC ConvTranslit ("\xc2\xab%%", "{%%")
251 #define MSGTYPE2RECSTR ConvTranslit ("\xc2\xab<<", "{<<")
252 #define MSGTYPE2RECSTROTR ConvTranslit ("\xc2\xab<&", "{<&")
253 #define MSGTYPE2RECSTROTRSEC ConvTranslit ("\xc2\xab<%", "{<%")
254
255 #if ENABLE_CONT_HIER
cb_tui_tail(Contact * cont)256 static void cb_tui_tail (Contact *cont)
257 {
258 if (!cont->parent)
259 return;
260 cb_tui_tail (cont->parent);
261 rl_printf (i18n (2619, " with %s%s%s"), COLCONTACT, cont->nick, COLNONE);
262 }
263 #endif
264
cb_status_tui(Contact * cont,parentmode_t pm,change_t ch,const char * text)265 static int cb_status_tui (Contact *cont, parentmode_t pm, change_t ch, const char *text)
266 {
267 Contact *pcont = cont;
268
269 #if ENABLE_CONT_HIER
270 int dotail = 0;
271 if (pm == pm_parent)
272 return 0;
273
274 for ( ; pcont->parent; pcont = pcont->parent)
275 if (pcont->parent->firstchild != pcont || pcont->parent->firstchild->next)
276 dotail = 1;
277 #endif
278 rl_log_for (pcont->nick, COLCONTACT);
279
280 if (ch == st_off)
281 rl_printf ("%s", i18n (1030, "logged off"));
282 else if (ch == st_on)
283 rl_printf (i18n (2213, "logged on (%s)"), s_status (cont->status, cont->nativestatus));
284 else
285 rl_printf (i18n (2212, "changed status to %s"), s_status (cont->status, cont->nativestatus));
286
287 if (cont->version && ch == st_on)
288 rl_printf (" [%s]", cont->version);
289
290 /* if ((cont->flags & imf_birth) && ((~oldf & imf_birth) || ch == st_on)) */
291 if (cont->flags & imf_birth && ch != st_off)
292 rl_printf (" (%s)", i18n (2033, "born today"));
293
294 #if ENABLE_CONT_HIER
295 if (dotail)
296 cb_tui_tail (cont);
297 #endif
298
299 if (text && *text)
300 {
301 rl_printf (". %s%s%s", COLQUOTE, COLSINGLE, text);
302 rl_print ("\n");
303 }
304 else
305 rl_print (".\n");
306
307 if (ch == st_on && cont->dc && prG->verbose)
308 {
309 rl_printf (" %s %s / ", i18n (1642, "IP:"), s_ip (cont->dc->ip_rem));
310 rl_printf ("%s:%ld %s %d %s (%d)\n", s_ip (cont->dc->ip_loc),
311 UD2UL (cont->dc->port), i18n (1453, "TCP version:"), cont->dc->version,
312 cont->dc->type == 4 ? i18n (1493, "Peer-to-Peer") : i18n (1494, "Server Only"),
313 cont->dc->type);
314 }
315 return 0;
316 }
317
cb_int_msg_tui(Contact * cont,parentmode_t pm,time_t stamp,fat_int_msg_t * msg)318 static int cb_int_msg_tui (Contact *cont, parentmode_t pm, time_t stamp, fat_int_msg_t *msg)
319 {
320 const char *line = "";
321 const char *col = COLCONTACT;
322 char *p, *q;
323 const char *marker = NULL;
324
325 #if ENABLE_CONT_HIER
326 int dotail = 0;
327 if (pm == pm_parent)
328 return 0;
329
330 for ( ; cont->parent; cont = cont->parent)
331 if (cont->parent->firstchild != cont || cont->parent->firstchild->next)
332 dotail = 1;
333 #endif
334
335 switch (msg->type)
336 {
337 case INT_MSGTRY_TYPE2:
338 case INT_MSGTRY_DC:
339 case INT_MSGACK_TYPE2:
340 case INT_MSGACK_DC:
341 case INT_MSGACK_SSL:
342 case INT_MSGACK_V8:
343 case INT_MSGACK_V5:
344 case INT_MSGDISPL:
345 case INT_MSGCOMP:
346 case INT_MSGNOCOMP:
347 if (ContactPrefVal (cont, CO_HIDEACK))
348 return 1;
349 break;
350 default:
351 ;
352 }
353
354 switch (msg->type)
355 {
356 case INT_FILE_ACKED:
357 line = s_sprintf (i18n (2462, "File transfer %s to port %s%ld%s."),
358 s_qquote (msg->opt_text), COLQUOTE, UD2UL (msg->port), COLNONE);
359 break;
360 case INT_FILE_REJED:
361 line = s_sprintf (i18n (2463, "File transfer %s rejected by peer: %s."),
362 s_qquote (msg->opt_text), s_wordquote (msg->msgtext));
363 break;
364 case INT_FILE_ACKING:
365 line = s_sprintf (i18n (2464, "Accepting file %s (%s%ld%s bytes)."),
366 s_qquote (msg->opt_text), COLQUOTE, UD2UL (msg->bytes), COLNONE);
367 break;
368 case INT_FILE_REJING:
369 line = s_sprintf (i18n (2465, "Refusing file request %s (%s%ld%s bytes): %s."),
370 s_qquote (msg->opt_text), COLQUOTE, UD2UL (msg->bytes), COLNONE, s_wordquote (msg->msgtext));
371 break;
372 case INT_CHAR_REJING:
373 line = s_sprintf (i18n (2466, "Refusing chat request (%s/%s) from %s%s%s."),
374 p = strdup (s_qquote (msg->opt_text)), q = strdup (s_qquote (msg->msgtext)),
375 COLCONTACT, cont->nick, COLNONE);
376 free (p);
377 free (q);
378 break;
379 case INT_MSGDISPL: marker = "<displayed>"; break;
380 case INT_MSGCOMP: marker = "<composing>"; break;
381 case INT_MSGNOCOMP: marker = "<no composing>"; break;
382 case INT_MSGOFF: marker = "<offline>"; break;
383 case INT_MSGTRY_TYPE2: marker = i18n (2293, "--="); break;
384 case INT_MSGTRY_DC: marker = i18n (2294, "==="); break;
385 case INT_MSGACK_TYPE2: marker = msg->bytes == 2 ? MSGTYPE2ACKSTROTRSEC
386 : msg->bytes == 1 ? MSGTYPE2ACKSTROTR
387 : MSGTYPE2ACKSTR; break;
388 case INT_MSGACK_DC: marker = msg->bytes == 2 ? MSGTCPACKSTROTRSEC
389 : msg->bytes == 1 ? MSGTCPACKSTROTR
390 : MSGTCPACKSTR; break;
391 #ifdef ENABLE_SSL
392 case INT_MSGACK_SSL: marker = msg->bytes == 2 ? MSGSSLACKSTROTRSEC
393 : msg->bytes == 1 ? MSGSSLACKSTROTR
394 : MSGSSLACKSTR; break;
395 #endif
396 case INT_MSGACK_V8: marker = msg->bytes == 2 ? MSGICQACKSTROTRSEC
397 : msg->bytes == 1 ? MSGICQACKSTROTR
398 : MSGICQACKSTR; break;
399 case INT_MSGACK_V5: marker = msg->bytes == 2 ? MSGICQ5ACKSTROTRSEC
400 : msg->bytes == 1 ? MSGICQ5ACKSTROTR
401 : MSGICQ5ACKSTR; break;
402 default:
403 line = "";
404 }
405
406 if (marker)
407 {
408 col = COLACK;
409 line = s_sprintf ("%s%s %s", marker, COLSINGLE, msg->msgtext);
410 }
411
412 for (p = q = strdup (line); *q; q++)
413 if (*q == (char)0xfe)
414 *q = '*';
415
416 rl_printf ("%s ", s_time (&stamp));
417 rl_printf ("%s", ReadLinePrintCont (cont->nick, col));
418
419 if (prG->verbose > 1)
420 rl_printf ("<%d> ", msg->type);
421
422 if (msg->tstatus != ims_offline && (!cont || cont->status == ims_offline || !cont->group))
423 rl_printf ("(%s) ", s_status (msg->tstatus, 0));
424
425 rl_print (p);
426 #if ENABLE_CONT_HIER
427 if (dotail)
428 cb_tui_tail (cont);
429 #endif
430 rl_print ("\n");
431 free (p);
432
433 return 0;
434 }
435
cb_srv_msg_tui(Contact * ocont,parentmode_t pm,time_t stamp,fat_srv_msg_t * msg)436 static int cb_srv_msg_tui (Contact *ocont, parentmode_t pm, time_t stamp, fat_srv_msg_t *msg)
437 {
438 UDWORD j;
439 int i, is_awaycount;
440 status_noi_t noinv;
441 const char *tmp, *tmp2, *tmp3, *carr;
442 Contact *cont = ocont;
443
444 #if ENABLE_CONT_HIER
445 int dotail = 0;
446 if (pm == pm_parent)
447 return 0;
448
449 for ( ; cont->parent; cont = cont->parent)
450 if (cont->parent->firstchild != cont || cont->parent->firstchild->next)
451 dotail = 1;
452 #endif
453
454 is_awaycount = ContactGroupPrefVal (cont->serv->contacts, CO_AWAYCOUNT);
455 noinv = ContactClearInv (cont->serv->status);
456 if ( (is_awaycount && noinv != imr_online && noinv != imr_ffc)
457 || (cont->serv->idle_flag != i_idle)
458 || uiG.idle_msgs)
459 {
460 if ((cont != uiG.last_rcvd) || !uiG.idle_uins || !uiG.idle_msgs)
461 s_repl (&uiG.idle_uins, s_sprintf ("%s %s", uiG.idle_uins && uiG.idle_msgs ? uiG.idle_uins : "", cont->nick));
462
463 uiG.idle_msgs++;
464 ReadLinePromptSet (s_sprintf ("[%s%ld%s%s]%s%s",
465 COLINCOMING, UD2UL (uiG.idle_msgs), uiG.idle_uins,
466 COLNONE, COLSERVER, i18n (2467, "climm>")));
467 }
468
469 if (!msg->otrencrypted)
470 carr = (msg->origin == CV_ORIGIN_dc) ? MSGTCPRECSTR :
471 #ifdef ENABLE_SSL
472 (msg->origin == CV_ORIGIN_ssl) ? MSGSSLRECSTR :
473 #endif
474 (msg->origin == CV_ORIGIN_v8) ? MSGTYPE2RECSTR : MSGICQRECSTR;
475 else if (msg->otrencrypted == 1)
476 carr = (msg->origin == CV_ORIGIN_dc) ? MSGTCPRECSTROTR :
477 #ifdef ENABLE_SSL
478 (msg->origin == CV_ORIGIN_ssl) ? MSGSSLRECSTROTR :
479 #endif
480 (msg->origin == CV_ORIGIN_v8) ? MSGTYPE2RECSTROTR : MSGICQRECSTROTR;
481 else
482 carr = (msg->origin == CV_ORIGIN_dc) ? MSGTCPRECSTROTRSEC :
483 #ifdef ENABLE_SSL
484 (msg->origin == CV_ORIGIN_ssl) ? MSGSSLRECSTROTRSEC :
485 #endif
486 (msg->origin == CV_ORIGIN_v8) ? MSGTYPE2RECSTROTRSEC : MSGICQRECSTROTRSEC;
487
488
489 if (uiG.nick_len < 4)
490 uiG.nick_len = 4;
491 rl_printf ("\a%s %s", s_time (&stamp), ReadLinePrintCont (cont->nick, COLINCOMING));
492
493 #if ENABLE_CONT_HIER
494 if (dotail)
495 cb_tui_tail (cont);
496 #endif
497
498 if (msg->nativestatus != -1 && (ocont->status != IcqToStatus (msg->nativestatus) || !cont->group))
499 rl_printf ("(%s) ", s_status (IcqToStatus (msg->nativestatus), msg->nativestatus));
500
501 if (prG->verbose > 1)
502 rl_printf ("<%ld> ", UD2UL (msg->type));
503
504 switch (msg->type & ~MSGF_MASS)
505 {
506 case MSGF_MASS: /* not reached here, but quiets compiler warning */
507 while (1)
508 {
509 rl_printf ("(?%lx?) %s" COLMSGINDENT "%s\n", UD2UL (msg->type), COLMESSAGE, msg->orig_data);
510 rl_printf (" '");
511 for (j = 0; j < strlen (msg->orig_data); j++)
512 rl_printf ("%c", ((msg->msgtext[j] & 0xe0) && (msg->msgtext[j] != 127)) ? msg->msgtext[j] : '.');
513 rl_print ("'\n");
514 return 1;
515
516 case MSG_NORM_SUBJ:
517 if (msg->subj)
518 {
519 rl_printf ("%s \"%s\"\n", carr, s_wordquote (msg->subj));
520 rl_printf ("%s" COLMSGINDENT "%s\n", COLMESSAGE, msg->msgtext);
521 break;
522 }
523
524 case MSG_NORM:
525 default:
526 rl_printf ("%s %s" COLMSGINDENT "%s\n", carr, COLMESSAGE, msg->msgtext);
527 break;
528
529 case MSG_FILE:
530 rl_printf (i18n (2468, "requests file transfer %s of %s%ld%s bytes (sequence %s%ld%s).\n"),
531 s_qquote (msg->msgtext), COLQUOTE, UD2UL (msg->bytes), COLNONE, COLQUOTE, UD2UL (msg->ref), COLNONE);
532 break;
533
534 case MSG_AUTO:
535 rl_printf ("<%s> %s" COLMSGINDENT "%s\n", i18n (2108, "auto"), COLMESSAGE, msg->msgtext);
536 break;
537
538 case MSGF_GETAUTO | MSG_GET_AWAY:
539 rl_printf ("<%s> %s" COLMSGINDENT "%s\n", i18n (1972, "away"), COLMESSAGE, msg->msgtext);
540 break;
541
542 case MSGF_GETAUTO | MSG_GET_OCC:
543 rl_printf ("<%s> %s" COLMSGINDENT "%s\n", i18n (1973, "occupied"), COLMESSAGE, msg->msgtext);
544 break;
545
546 case MSGF_GETAUTO | MSG_GET_NA:
547 rl_printf ("<%s> %s" COLMSGINDENT "%s\n", i18n (1974, "not available"), COLMESSAGE, msg->msgtext);
548 break;
549
550 case MSGF_GETAUTO | MSG_GET_DND:
551 rl_printf ("<%s> %s" COLMSGINDENT "%s\n", i18n (1971, "do not disturb"), COLMESSAGE, msg->msgtext);
552 break;
553
554 case MSGF_GETAUTO | MSG_GET_FFC:
555 rl_printf ("<%s> %s" COLMSGINDENT "%s\n", i18n (1976, "free for chat"), COLMESSAGE, msg->msgtext);
556 break;
557
558 case MSGF_GETAUTO | MSG_GET_VER:
559 rl_printf ("<%s> %s" COLMSGINDENT "%s\n", i18n (2109, "version"), COLMESSAGE, msg->msgtext);
560 break;
561
562 case MSG_URL:
563 if (!msg->tmp[1]) continue;
564 rl_printf ("%s %s\n%s %*s", carr, s_msgquote (msg->tmp[0]), s_now, uiG.nick_len - 4, "");
565 rl_printf ("%s %s %s\n", i18n (2469, "URL:"), carr, s_wordquote (msg->tmp[1]));
566 break;
567
568 case MSG_AUTH_REQ:
569 if (msg->tmp[1])
570 {
571 if (!msg->tmp[5]) continue;
572 }
573 else
574 {
575 msg->tmp[5] = msg->tmp[0];
576 msg->tmp[0] = NULL;
577 }
578 if (msg->tmp[5] && *msg->tmp[5])
579 rl_printf (i18n (2470, "requests authorization: %s\n"), s_msgquote (msg->tmp[5]));
580 else
581 rl_printf (i18n (2758, "requests authorization.\n"));
582
583 if (msg->tmp[0] && *msg->tmp[0])
584 rl_printf ("%-15s %s\n", "???1:", s_wordquote (msg->tmp[0]));
585 if (msg->tmp[1] && *msg->tmp[1])
586 rl_printf ("%-15s %s\n", i18n (1564, "First name:"), s_wordquote (msg->tmp[1]));
587 if (msg->tmp[2] && *msg->tmp[2])
588 rl_printf ("%-15s %s\n", i18n (1565, "Last name:"), s_wordquote (msg->tmp[2]));
589 if (msg->tmp[3] && *msg->tmp[3])
590 rl_printf ("%-15s %s\n", i18n (1566, "Email address:"), s_wordquote (msg->tmp[3]));
591 if (msg->tmp[4] && *msg->tmp[4])
592 rl_printf ("%-15s %s\n", "???5:", s_wordquote (msg->tmp[4]));
593 break;
594
595 case MSG_AUTH_DENY:
596 if (msg->msgtext)
597 rl_printf (i18n (2233, "refused authorization: %s%s%s\n"), COLMESSAGE, COLMSGINDENT, msg->msgtext);
598 else
599 rl_printf (i18n (2759, "refused authorization.\n"));
600 break;
601
602 case MSG_AUTH_GRANT:
603 rl_print (i18n (1901, "has authorized you to add them to your contact list.\n"));
604 break;
605
606 case MSG_AUTH_ADDED:
607 if (!msg->tmp[0])
608 {
609 rl_print (i18n (1755, "has added you to their contact list.\n"));
610 break;
611 }
612 if (!msg->tmp[3]) continue;
613 rl_printf ("%s ", s_cquote (msg->tmp[0], COLCONTACT));
614 rl_print (i18n (1755, "has added you to their contact list.\n"));
615 rl_printf ("%-15s %s\n", i18n (1564, "First name:"), s_wordquote (msg->tmp[1]));
616 rl_printf ("%-15s %s\n", i18n (1565, "Last name:"), s_wordquote (msg->tmp[2]));
617 rl_printf ("%-15s %s\n", i18n (1566, "Email address:"), s_wordquote (msg->tmp[3]));
618 break;
619
620 case MSG_AUTH_DONE:
621 rl_print (i18n (2760, "has removed you from his contact list.\n"));
622 break;
623
624 case MSG_EMAIL:
625 case MSG_WEB:
626 if (!msg->tmp[5]) continue;
627 if (msg->type == MSG_EMAIL)
628 {
629 rl_printf (i18n (2571, "\"%s\" <%s> emailed you a message [%s]: %s\n"),
630 s_cquote (msg->tmp[0], COLCONTACT), s_cquote (msg->tmp[3], COLCONTACT),
631 s_cquote (msg->tmp[4], COLCONTACT), s_msgquote (msg->tmp[5]));
632 }
633 else
634 {
635 rl_printf (i18n (2572, "\"%s\" <%s> sent you a web message [%s]: %s\n"),
636 s_cquote (msg->tmp[0], COLCONTACT), s_cquote (msg->tmp[3], COLCONTACT),
637 s_cquote (msg->tmp[4], COLCONTACT), s_msgquote (msg->tmp[5]));
638 }
639 break;
640
641 case MSG_CONTACT:
642 {
643 tmp = s_msgtok (msg->msgtext); if (!tmp) continue;
644
645 rl_printf (i18n (1595, "\nContact List.\n============================================\n%d Contacts\n"),
646 i = atoi (tmp));
647
648 while (i--)
649 {
650 tmp2 = s_msgtok (NULL); if (!tmp2) continue;
651 tmp3 = s_msgtok (NULL); if (!tmp3) continue;
652
653 rl_print (s_cquote (tmp2, COLCONTACT));
654 rl_printf ("\t\t\t%s\n", s_msgquote (tmp3));
655 }
656 }
657 break;
658 }
659 }
660 return 0;
661 }
662
663 /** INTERNAL FUNCTIONS **/
664
665 #define hide_noleaf 4
666 #define hide_cont 2
667 #define hide_hide 1
668
__IMOnline(Contact * cont,status_t status,statusflag_t flags,UDWORD nativestatus,const char * text,int hide)669 static int __IMOnline (Contact *cont, status_t status, statusflag_t flags, UDWORD nativestatus, const char *text, int hide)
670 {
671 status_t old;
672 statusflag_t oldf;
673 #if ENABLE_CONT_HIER
674 parentmode_t pm = hide & hide_noleaf ? pm_parent : pm_leaf;
675 #else
676 #define pm pm_leaf
677 #endif
678 change_t ch = status == ims_offline ? st_off : cont->status == ims_offline ? st_on : st_ch;
679
680 if (cont->group)
681 hide |= hide_cont;
682
683 OptSetVal (&cont->copts, CO_TIMESEEN, time (NULL));
684 old = cont->status;
685 oldf = cont->flags;
686 cont->status = status;
687 if (status != ims_offline)
688 cont->flags = flags;
689 cont->nativestatus = nativestatus;
690 cont->oldflags &= ~CONT_SEENAUTO;
691 s_repl (&cont->status_message, text);
692
693 cb_status_log (cont, ch, pm, text);
694
695 if (ContactPrefVal (cont, CO_IGNORE)
696 || (!ContactPrefVal (cont, CO_SHOWONOFF) && (old == ims_offline || status == ims_offline))
697 || (!ContactPrefVal (cont, CO_SHOWCHANGE) && old != ims_offline && status != ims_offline)
698 || (cont->serv && ~cont->serv->conn->connect & CONNECT_OK))
699 hide |= hide_hide;
700
701 #if ENABLE_CONT_HIER
702 if (cont->parent)
703 {
704 Contact *pcont = cont;
705
706 assert (cont->parent->firstchild);
707
708 #if 0
709 if (status == ims_offline && !cont->group)
710 {
711 Contact **t;
712 for (t = &(cont->parent->firstchild); *t; t=&((*t)->next))
713 if (*t == cont)
714 {
715 *t = cont->next;
716 cont->next = NULL;
717 if (!*t)
718 break;
719 }
720 }
721 #endif
722
723 if (ContactStatusCmp (status, cont->parent->status) >= 0)
724 {
725 Contact *tcont;
726 for (tcont = cont->parent->firstchild; tcont; tcont = tcont->next)
727 {
728 assert (tcont->parent == cont->parent);
729 if (ContactStatusCmp (tcont->status, pcont->status) < 0)
730 pcont = tcont;
731 }
732 }
733 s_repl (&cont->parent->version, pcont->version);
734 s_repl (&cont->parent->cap_string, pcont->cap_string);
735 hide |= __IMOnline (cont->parent, pcont->status, pcont->flags, pcont->nativestatus, pcont->status_message, hide | hide_noleaf);
736 }
737 #endif
738
739 if (hide & hide_hide || ~hide & hide_cont)
740 return hide_hide;
741
742 #ifdef MSGEXEC
743 cb_status_exec (cont, pm, ch, text);
744 #endif
745 cb_status_tui (cont, pm, ch, text);
746 cb_status_auto (cont, pm, ch, text);
747 #ifdef ENABLE_TCL
748 cb_status_tcl (cont, pm, ch, text);
749 #endif
750 return hide;
751 }
752 #undef pm
753
754
__IMIntMsg(Contact * cont,time_t stamp,fat_int_msg_t * msg,int hide)755 int __IMIntMsg (Contact *cont, time_t stamp, fat_int_msg_t *msg, int hide)
756 {
757 int noerr = 0;
758 #if ENABLE_CONT_HIER
759 parentmode_t pm = hide & hide_noleaf ? pm_parent : pm_leaf;
760 #else
761 #define pm pm_leaf
762 #endif
763 /* cb_int_msg_log (cont, pm, stamp, msg); */
764
765 if (ContactPrefVal (cont, CO_IGNORE))
766 return hide_hide;
767
768 #if ENABLE_CONT_HIER
769 if (cont->parent)
770 {
771 assert (cont->parent->firstchild);
772 hide |= __IMIntMsg (cont->parent, stamp, msg, hide | hide_noleaf);
773 }
774 #endif
775 if (hide & hide_hide)
776 return hide_hide;
777
778 #ifdef MSGEXEC
779 /* if (!cb_int_msg_exec (cont, pm, stamp, msg)) */
780 #endif
781 if (!cb_int_msg_tui (cont, pm, stamp, msg))
782 /* if (!cb_int_msg_auto (cont, pm, stamp, msg)) */
783 if (!cb_int_msg_hist (cont, pm, stamp, msg))
784 #ifdef ENABLE_TCL
785 if (!cb_int_msg_tcl (cont, pm, stamp, msg))
786 #endif
787 noerr = 1;
788 if (!noerr)
789 hide |= hide_hide;
790
791 return hide;
792 }
793
__IMSrvMsg(Contact * cont,time_t stamp,fat_srv_msg_t * msg,int hide)794 int __IMSrvMsg (Contact *cont, time_t stamp, fat_srv_msg_t *msg, int hide)
795 {
796 int noerr = 0;
797 #if ENABLE_CONT_HIER
798 parentmode_t pm = hide & hide_noleaf ? pm_parent : pm_leaf;
799 #else
800 #define pm pm_leaf
801 #endif
802 cb_srv_msg_log (cont, pm, stamp, msg);
803
804 if (ContactPrefVal (cont, CO_IGNORE))
805 return hide_hide;
806
807 #if ENABLE_CONT_HIER
808 if (cont->parent)
809 {
810 assert (cont->parent->firstchild);
811 hide |= __IMSrvMsg (cont->parent, stamp, msg, hide | hide_noleaf);
812 }
813 #endif
814 if (hide & hide_hide)
815 return hide_hide;
816
817 s_repl (&cont->last_message, msg->msgtext);
818 cont->last_time = stamp;
819
820 if (!cb_srv_msg_exec (cont, pm, stamp, msg))
821 if (!cb_srv_msg_tui (cont, pm, stamp, msg))
822 if (!cb_srv_msg_auto (cont, pm, stamp, msg))
823 if (!cb_srv_msg_hist (cont, pm, stamp, msg))
824 #ifdef ENABLE_TCL
825 if (!cb_srv_msg_tcl (cont, pm, stamp, msg))
826 #endif
827 noerr = 1;
828 if (!noerr)
829 hide |= hide_hide;
830
831 #if ENABLE_CONT_HIER
832 while (cont->parent)
833 cont = cont->parent;
834 if (pm == pm_leaf)
835 #endif
836 uiG.last_rcvd = cont;
837 TabAddIn (cont);
838 return hide;
839 }
840
841 /** FUNCTIONS TO BE CALLED FROM EXTERN **/
842
843 /*
844 * Inform that a user went offline
845 */
IMOffline(Contact * cont)846 void IMOffline (Contact *cont)
847 {
848 IMOnline (cont, ims_offline, 0, -1, "");
849 }
850
851 /*
852 * Inform that a user went online
853 */
IMOnline(Contact * cont,status_t status,statusflag_t flags,UDWORD nativestatus,const char * text)854 void IMOnline (Contact *cont, status_t status, statusflag_t flags, UDWORD nativestatus, const char *text)
855 {
856 Event *egevent;
857 int hide = 0;
858
859 if (!cont)
860 return;
861
862 if ((egevent = QueueDequeue2 (cont->serv->conn, QUEUE_DEP_WAITLOGIN, 0, 0)))
863 {
864 egevent->due = time (NULL) + 3;
865 QueueEnqueue (egevent);
866 hide = hide_hide;
867 }
868
869 if (status == cont->status && (status == ims_offline || flags == cont->flags) && (!text || !*text))
870 return;
871
872 if (cont->status_message && text && !strcmp (cont->status_message, text))
873 return;
874
875 __IMOnline (cont, status, flags, nativestatus, text, hide);
876 }
877
878
879 /*
880 * Central entry point for protocol triggered output.
881 */
IMIntMsg(Contact * cont,time_t stamp,status_t tstatus,int_msg_t type,const char * text)882 void IMIntMsg (Contact *cont, time_t stamp, status_t tstatus, int_msg_t type, const char *text)
883 {
884 IMIntMsgFat (cont, stamp, tstatus, type, text, "", 0, 0);
885 }
886
IMIntMsgMsg(Message * msg,time_t stamp,status_t tstatus)887 void IMIntMsgMsg (Message *msg, time_t stamp, status_t tstatus)
888 {
889 IMIntMsgFat (msg->cont, stamp, tstatus, msg->type, msg->plain_message ? msg->plain_message : msg->send_message,
890 NULL, 0, !msg->otrencrypted ? 0 : msg->otrencrypted ? 1 : 2);
891 }
892
IMIntMsgFat(Contact * cont,time_t stamp,status_t tstatus,int_msg_t type,const char * text,const char * opt_text,UDWORD port,UDWORD bytes)893 void IMIntMsgFat (Contact *cont, time_t stamp, status_t tstatus, int_msg_t type,
894 const char *text, const char *opt_text, UDWORD port, UDWORD bytes)
895 {
896 fat_int_msg_t msg;
897 char *deleteme = NULL;
898
899 if (!cont)
900 return;
901
902 memset (&msg, 0, sizeof msg);
903 if (stamp == NOW)
904 stamp = time (NULL);
905
906 msg.orig_data = text;
907 msg.msgtext = text;
908 msg.type = type;
909 msg.tstatus = tstatus;
910 msg.opt_text = opt_text ? opt_text : "";
911 msg.port = port;
912 msg.bytes = bytes;
913
914 if (!strncasecmp (msg.orig_data, "<font ", 6))
915 {
916 char *t = deleteme = strdup (msg.orig_data);
917 while (*t && *t != '>')
918 t++;
919 if (*t)
920 {
921 size_t l = strlen (++t);
922 if (!strcasecmp (t + l - 7, "</font>"))
923 t[l - 7] = 0;
924 msg.msgtext = t;
925 }
926 }
927
928 __IMIntMsg (cont, stamp, &msg, 0);
929
930 if (deleteme)
931 s_free (deleteme);
932 }
933
934 /*
935 * Central entry point for incoming messages.
936 */
IMSrvMsg(Contact * cont,time_t stamp,UDWORD opt_origin,UDWORD opt_type,const char * text)937 void IMSrvMsg (Contact *cont, time_t stamp, UDWORD opt_origin, UDWORD opt_type, const char *text)
938 {
939 IMSrvMsgFat (cont, stamp, OptSetVals (NULL, CO_ORIGIN, opt_origin, CO_MSGTYPE, opt_type, CO_MSGTEXT, text, 0));
940 }
941
IMSrvMsgFat(Contact * cont,time_t stamp,Opt * opt)942 void IMSrvMsgFat (Contact *cont, time_t stamp, Opt *opt)
943 {
944 fat_srv_msg_t msg;
945 int max_0xff = 0, i;
946
947 if (!cont)
948 {
949 OptD (opt);
950 return;
951 }
952
953 memset (&msg, 0, sizeof msg);
954
955 if (stamp == NOW)
956 stamp = time (NULL);
957
958 if (!OptGetVal (opt, CO_MSGTYPE, &msg.type))
959 msg.type = MSG_NORM;
960 if (!OptGetVal (opt, CO_ORIGIN, &msg.origin))
961 msg.origin = CV_ORIGIN_v5;
962 if (!OptGetVal (opt, CO_STATUS, &msg.nativestatus))
963 msg.nativestatus = -1;
964 if (!OptGetVal (opt, CO_BYTES, &msg.bytes))
965 msg.bytes = 0;
966 if (OptGetVal (opt, CO_SAMEHTML, &msg.ref))
967 msg.samehtml = 1;
968 else
969 msg.samehtml = 0;
970 if (!OptGetVal (opt, CO_REF, &msg.ref))
971 msg.ref = 0;
972 if (!OptGetStr (opt, CO_SUBJECT, &msg.subj))
973 msg.subj = NULL;
974
975 if (!OptGetStr (opt, CO_MSGTEXT, &msg.orig_data))
976 msg.orig_data = "";
977 msg.msgtext = strdup (msg.orig_data);
978
979 OptD (opt);
980 opt = NULL;
981
982 #ifdef ENABLE_OTR
983 /* process incomming messages for OTR decryption */
984 if (msg.type == MSG_NORM && libotr_is_present)
985 if (OTRMsgIn (cont, &msg))
986 {
987 free (msg.msgtext);
988 return; /* no msg ack/logging? */
989 }
990 #endif /* ENABLE_OTR */
991 while (*msg.msgtext && strchr ("\n\r \t", msg.msgtext[strlen (msg.msgtext) - 1]))
992 msg.msgtext[strlen (msg.msgtext) - 1] = '\0';
993
994 max_0xff = 0;
995 switch (msg.type & ~MSGF_MASS)
996 {
997 default:
998 break;
999 case MSG_URL:
1000 max_0xff = 2;
1001 break;
1002 case MSG_AUTH_ADDED:
1003 max_0xff = 4;
1004 break;
1005 case MSG_AUTH_REQ:
1006 case MSG_EMAIL:
1007 case MSG_WEB:
1008 max_0xff = 6;
1009 break;
1010 }
1011 for (i = 0; i < max_0xff; i++)
1012 msg.tmp[i] = s_msgtok (i ? NULL : msg.msgtext);
1013
1014 if (!strncasecmp (msg.msgtext, "<font ", 6))
1015 {
1016 char *t = msg.msgtext;
1017 while (*t && *t != '>')
1018 t++;
1019 if (*t)
1020 {
1021 size_t l = strlen (++t);
1022 if (!strcasecmp (t + l - 7, "</font>"))
1023 t[l - 7] = 0;
1024 t = strdup (t);
1025 free (msg.msgtext);
1026 msg.msgtext = t;
1027 }
1028 }
1029
1030 __IMSrvMsg (cont, stamp, &msg, 0);
1031
1032 free (msg.msgtext);
1033 }
1034