1 /*
2 * This file is part of Licq, an instant messaging client for UNIX.
3 * Copyright (C) 2003-2005 Martin Maurer (martinmaurer@gmx.at)
4 * Copyright (C) 2007-2014 Licq developers <licq-dev@googlegroups.com>
5 *
6 * Licq is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * Licq is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Licq; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "licq-osd.h"
22
23 #include <cerrno>
24 #include <cstdio>
25 #include <cstring>
26 #include <ctime>
27 #include <iconv.h>
28 #include <iostream>
29 #include <langinfo.h>
30 #include <libintl.h>
31 #include <locale.h>
32 #include <unistd.h>
33
34 #include <licq/logging/log.h>
35 #include <licq/contactlist/owner.h>
36 #include <licq/contactlist/user.h>
37 #include <licq/contactlist/usermanager.h>
38 #include <licq/daemon.h>
39 #include <licq/event.h>
40 #include <licq/inifile.h>
41 #include <licq/pluginsignal.h>
42 #include <licq/userevents.h>
43
44 #include "my_xosd.h"
45 #include "licq_osd.conf.h"
46
47 using Licq::User;
48 using Licq::UserId;
49 using Licq::gLog;
50 using Licq::gUserManager;
51 using std::string;
52
53 #define _(String) gettext (String)
54
55 // if you don't want to use codepage translation, comment out this
56 #define CP_TRANSLATE
57
58 struct Config {
59 unsigned long Showmessages; //=SHOWLOGON;
60 unsigned long Showlogon; //=SHOWLOGON;
61 unsigned long ShowStatusChange; //=SHOWSTATUSCHANGE;
62 unsigned long ShowAutoResponseCheck; //=SHOWAUTORESPONSECHECK;
63 unsigned long quiettimeout; //=QUIETTIMEOUT;
64 string pluginfont;
65 unsigned showInModes;
66 unsigned showMsgsInModes;
67 string colour;
68 string controlcolour;
69 bool osd_wait;
70 unsigned long timeout;
71 unsigned long hoffset;
72 unsigned long voffset;
73 unsigned long linelen, lines;
74 unsigned long shadowoffset;
75 unsigned long outlineoffset;
76 unsigned long DelayPerCharacter;
77 string vpos;
78 string hpos;
79 string shadowcolour;
80 string outlinecolour;
81 string localencoding;
82 bool marksecuremessages;
83 } config;
84
85
86 // some forward declarations
87 void ProcessSignal(const Licq::PluginSignal* s);
88 #ifdef CP_TRANSLATE
89 const char *get_iconv_encoding_name(const char *licq_encoding_name);
90 string my_translate(const UserId& userId, const string& msg, const char* userenc);
91 #endif
92
93 // some variables representing the internal state
94 time_t disabletimer=0;
95 bool Online;
96 bool Enabled;
97 bool Configured=false; // is the xosd display initialized?
98
OsdPlugin()99 OsdPlugin::OsdPlugin()
100 {
101 // Empty
102 }
103
104 // status of plugin - so they can be deactivated
105 // not implemented for this plugin
isEnabled() const106 bool OsdPlugin::isEnabled() const
107 {
108 return Enabled;
109 }
110
111 // a wrapper so we can log from my_xosd.cpp to standard licq log
log(int mode,const char * message)112 void log(int mode, const char *message)
113 {
114 if (mode==0) // warn/info
115 gLog.warning("%s", message);
116 if (mode==1) // error
117 gLog.error("%s", message);
118 }
119
120 // issue a few warnings for wrong config values.
verifyconfig(string pluginfont,unsigned long,unsigned long hoffset,unsigned long voffset,string vpos,string hpos,unsigned long lines,unsigned long linelen,unsigned long quiettimeout,string colour,bool,unsigned long showmessages,unsigned long showlogon,unsigned long shadowoffset,unsigned long outlineoffset,string shadowcolour,string outlinecolour,string localencoding)121 void verifyconfig(string pluginfont, unsigned long /* timeout */,
122 unsigned long hoffset, unsigned long voffset, string vpos, string hpos,
123 unsigned long lines, unsigned long linelen, unsigned long quiettimeout,
124 string colour, bool /* wait */, unsigned long showmessages,
125 unsigned long showlogon, unsigned long shadowoffset,
126 unsigned long outlineoffset, string shadowcolour, string outlinecolour,
127 string localencoding)
128 {
129 try {
130 if ((pluginfont=="") || (pluginfont.at(0)=='"') || (pluginfont.at(0)=='\''))
131 gLog.error("CONFIG: Invalid pluginfont %s. This will fail", pluginfont.c_str());
132 if (hoffset>10000)
133 gLog.warning("CONFIG: Very high horizontal offset %lu. This might fail", hoffset);
134 if (voffset>10000)
135 gLog.warning("CONFIG: Very high vertical offset %lu. This might fail", voffset);
136 if ((vpos!="top") && (vpos!="bottom") && (vpos!="middle"))
137 gLog.error("CONFIG: Invalid vertical position %s. Should be \"top\" or \"bottom\" or \"middle\". This will fail.", vpos.c_str());
138 if ((hpos!="left") && (hpos!="right") && (hpos!="center"))
139 gLog.error("CONFIG: Invalid horizontal position %s. Should be \"left\" or \"right\" or \"center\". This will fail.", hpos.c_str());
140 if (lines>50)
141 gLog.error("CONFIG: More than 50 lines not allowed. You used %lu", lines);
142 if (linelen>500)
143 gLog.error("CONFIG: More than 500 characters per line not allowed. You used %lu", linelen);
144 if (quiettimeout>500)
145 gLog.warning("CONFIG: Your quiettimeout %lu is higher than 500. Do you really want this?", quiettimeout);
146 if (colour=="")
147 gLog.error("CONFIG: Invalid colour %s. For possible values look at rgb.txt from your Xfree86 distribution", colour.c_str());
148 if (showmessages>4)
149 gLog.error("CONFIG: Invalid value for showmessages %lu", showmessages);
150 if (showlogon>2)
151 gLog.error("CONFIG: Invalid value for showlogon %lu", showlogon);
152 if (shadowoffset>200)
153 gLog.warning("CONFIG: Very high Shadowoffset value %lu", shadowoffset);
154 if (outlineoffset>200)
155 gLog.warning("CONFIG: Very high Outlineoffset value %lu", outlineoffset);
156 if (shadowcolour=="")
157 gLog.error("CONFIG: Invalid shadow colour %s. For possible values look at rgb.txt from your Xfree86 distribution", shadowcolour.c_str());
158 if (outlinecolour=="")
159 gLog.error("CONFIG: Invalid outline colour %s. For possible values look at rgb.txt from your Xfree86 distribution", outlinecolour.c_str());
160 if (localencoding=="")
161 gLog.warning("Localencoding could not be determined from your locale");
162 }
163 catch (...)
164 {
165 gLog.error("CONFIG: Exception while verifying config values");
166 }
167 }
168
parseShowInModesStr(const char * ShowInModesStr)169 unsigned parseShowInModesStr(const char* ShowInModesStr)
170 {
171 unsigned showInModes = 0;
172 if (strstr(ShowInModesStr, "Online"))
173 showInModes |= User::OnlineStatus;
174 if (strstr(ShowInModesStr, "FreeForChat"))
175 showInModes |= User::FreeForChatStatus;
176 if (strstr(ShowInModesStr, "Away"))
177 showInModes |= User::AwayStatus;
178 if (strstr(ShowInModesStr, "NA"))
179 showInModes |= User::NotAvailableStatus;
180 if (strstr(ShowInModesStr, "Occupied"))
181 showInModes |= User::OccupiedStatus;
182 if (strstr(ShowInModesStr, "DND"))
183 showInModes |= User::DoNotDisturbStatus;
184 if (strstr(ShowInModesStr, "Invisible"))
185 showInModes |= User::InvisibleStatus;
186 return showInModes;
187 }
188
189 // called once on Load of the plugin
init(int,char **)190 bool OsdPlugin::init(int /* argc */, char** /* argv */)
191 {
192 string showInModes;
193 string showMsgsInModes;
194 try {
195 Configured=false;
196 gLog.info("OSD Plugin initializing\n");
197
198 string filename = "licq_osd.conf";
199 Licq::IniFile conf(filename);
200 if (!conf.loadFile()) // no configfile found
201 {
202 filename = Licq::gDaemon.baseDir() + filename;
203 FILE *f = fopen(filename.c_str(), "w");
204 if (f) // create config file
205 {
206 fprintf(f, "%s", OSD_CONF);
207 fclose(f);
208 }
209 else // configfile cannot be created
210 {
211 gLog.error("Configfile can not be created. Check the permissions on %s", filename.c_str());
212 return 0;
213 }
214 if (!conf.loadFile()) // configfile cannot be read after creating it - this should not happen
215 {
216 gLog.error("Configfile created but cannot be loaded. This should not happen");
217 return 0;
218 }
219 }
220 conf.setSection("Main");
221 conf.get("Wait", config.osd_wait, WAIT);
222 conf.get("Font", config.pluginfont, FONT);
223 conf.get("Timeout", config.timeout, DISPLAYTIMEOUT);
224 conf.get("HOffset", config.hoffset, HORIZONTAL_OFFSET);
225 conf.get("VOffset", config.voffset, VERTICAL_OFFSET);
226 conf.get("VPos", config.vpos, VPOS);
227 conf.get("HPos", config.hpos, HPOS);
228 conf.get("Lines", config.lines, LINES);
229 conf.get("Linelen", config.linelen, LINELEN);
230 conf.get("Quiettimeout", config.quiettimeout, QUIETTIMEOUT);
231 conf.get("Colour", config.colour, COLOUR);
232 conf.get("ControlColour", config.controlcolour, CONTROLCOLOUR);
233 conf.get("Showmessages", config.Showmessages, SHOWMESSAGES);
234 conf.get("ShowAutoResponseCheck", config.ShowAutoResponseCheck, SHOWAUTORESPONSECHECK);
235 conf.get("Showlogon", config.Showlogon, SHOWLOGON);
236 conf.get("DelayPerCharacter", config.DelayPerCharacter, DELAYPERCHARACTER);
237 conf.get("ShowStatusChange", config.ShowStatusChange, SHOWSTATUSCHANGE);
238 conf.get("ShadowOffset", config.shadowoffset, SHADOW_OFFSET);
239 conf.get("OutlineOffset", config.outlineoffset, OUTLINE_OFFSET);
240 conf.get("MarkSecureMessages", config.marksecuremessages, MARKSECUREMESSAGES);
241 conf.get("ShadowColour", config.shadowcolour, SHADOW_COLOUR);
242 conf.get("OutlineColour", config.outlinecolour, OUTLINE_COLOUR);
243 conf.get("ShowInModes", showInModes, SHOWINMODESSTR);
244 conf.get("ShowMsgsInModes", showMsgsInModes, SHOWMSGSINMODESSTR);
245
246 config.showInModes = parseShowInModesStr(showInModes.c_str());
247 config.showMsgsInModes = parseShowInModesStr(showMsgsInModes.c_str());
248
249 setlocale(LC_ALL, "");
250
251 config.localencoding=nl_langinfo(CODESET);
252 bindtextdomain (PACKAGE, LOCALEDIR);
253 bind_textdomain_codeset(PACKAGE, config.localencoding.c_str());
254 textdomain (PACKAGE);
255 // check config values for validity
256 verifyconfig(config.pluginfont, config.timeout, config.hoffset, config.voffset, config.vpos, config.hpos, config.lines, config.linelen, config.quiettimeout,
257 config.colour, config.osd_wait, config.Showmessages, config.Showlogon, config.shadowoffset, config.outlineoffset, config.shadowcolour,
258 config.outlinecolour, config.localencoding);
259
260 return 1;
261 }
262 catch (...)
263 {
264 return 0;
265 }
266 }
267
268
269 // run method of plugin
run()270 int OsdPlugin::run()
271 {
272 // register plugin at the licq daemon
273 int nPipe = getReadPipe();
274 setSignalMask(Licq::PluginSignal::SignalUser |
275 Licq::PluginSignal::SignalLogon | Licq::PluginSignal::SignalLogoff);
276 bool Exit=false; // exit plugin?
277 char buf[16];
278
279 if (nPipe==-1)
280 {
281 gLog.warning("Invalid Pipe received");
282 return 1;
283 }
284
285 disabletimer=time(0);
286 Enabled=true;
287 Online=false;
288 // as long as no shutdown command from licq daemon received
289 while (!Exit)
290 {
291 read(nPipe, buf, 1); // Information about a new signal is sent through pipe
292 if (!Configured)
293 {
294 if (!my_xosd_init(config.pluginfont, config.colour, config.hoffset, config.voffset, config.vpos, config.hpos, config.timeout, config.DelayPerCharacter, config.lines, config.linelen, config.osd_wait, config.shadowoffset, config.outlineoffset, config.shadowcolour, config.outlinecolour))
295 return 0;
296 Configured=true;
297 }
298
299 switch (buf[0])
300 {
301 case PipeSignal:
302 {
303 // read the actual signal from the daemon
304 ProcessSignal(popSignal().get());
305 break;
306 }
307
308 // An event is pending - skip it - shouldnt happen
309 // events are responses to some requests to the licq daemon
310 // like send a message - we never do such a thing
311 case PipeEvent:
312 {
313 gLog.warning("Event received - should not happen in this plugin");
314 popEvent();
315 break;
316 }
317 // shutdown command from daemon
318 // every plugin has to implement this command
319 case PipeShutdown:
320 {
321 Exit = true;
322 gLog.info("OSD Plugin shutting down");
323 break;
324 }
325
326 case PipeDisable:
327 Enabled=false;
328 gLog.info("OSD Plugin disabled");
329 break;
330 case PipeEnable:
331 Enabled=true;
332 gLog.info("OSD Plugin enabled");
333 break;
334 default:
335 gLog.warning("Unknown message type %d", buf[0]);
336 }
337 }
338
339 if (Configured)
340 {
341 my_xosd_exit();
342 Configured=false;
343 }
344
345 return 0;
346 }
347
ProcessSignal(const Licq::PluginSignal * s)348 void ProcessSignal(const Licq::PluginSignal* s)
349 {
350 string username;
351 bool notify=false;
352 bool ignore=false;
353 bool want_osd = true; // if we are in DND,... we maybe don't want OSD
354 bool want_osd_msgs_only=false; // though we don't want OSD we want msgs
355 bool secure=false;
356 unsigned status = User::OnlineStatus;
357 const Licq::UserEvent* e = NULL;
358
359 switch (s->signal()) // signaltype
360 {
361 case Licq::PluginSignal::SignalUser:
362 {
363 // FIX: we seem to get others logged on messages before
364 // our own one - so start quiettimeout in this case too
365 if (!Online)
366 {
367 Online=true;
368 disabletimer=time(0);
369 }
370 if (disabletimer) // no time() calls when timeout has been done
371 {
372 if (time(0)-disabletimer>=(time_t)config.quiettimeout)
373 disabletimer=0;
374 else
375 want_osd=false;
376 }
377
378 if (want_osd)
379 {
380 Licq::OwnerReadGuard o(s->userId().ownerId());
381 if (o.isLocked())
382 {
383 status = o->status();
384 //want_osd=true;
385
386 if ((status & User::DoNotDisturbStatus) && (!(config.showInModes & User::DoNotDisturbStatus)))
387 want_osd=false;
388 else if ((status & User::OccupiedStatus) && (!(config.showInModes & User::OccupiedStatus)))
389 want_osd=false;
390 else if ((status & User::NotAvailableStatus) && (!(config.showInModes & User::NotAvailableStatus)))
391 want_osd=false;
392 else if ((status & User::AwayStatus) && (!(config.showInModes & User::AwayStatus)))
393 want_osd=false;
394 else if ((status & User::FreeForChatStatus) && (!(config.showInModes & User::FreeForChatStatus)))
395 want_osd=false;
396 else if ((status & User::InvisibleStatus) && (!(config.showInModes & User::InvisibleStatus)))
397 want_osd=false;
398 else if (!(config.showInModes & User::OnlineStatus))
399 want_osd = false;
400
401 if (!want_osd) {
402 if ((status & User::DoNotDisturbStatus) && (config.showMsgsInModes & User::DoNotDisturbStatus))
403 want_osd_msgs_only=true;
404 else if ((status & User::OccupiedStatus) && (config.showMsgsInModes & User::OccupiedStatus))
405 want_osd_msgs_only=true;
406 else if ((status & User::NotAvailableStatus) && (config.showMsgsInModes & User::NotAvailableStatus))
407 want_osd_msgs_only=true;
408 else if ((status & User::AwayStatus) && (config.showMsgsInModes & User::AwayStatus))
409 want_osd_msgs_only=true;
410 else if ((status & User::FreeForChatStatus) && (config.showMsgsInModes & User::FreeForChatStatus))
411 want_osd_msgs_only=true;
412 else if ((status & User::InvisibleStatus) && (config.showMsgsInModes & User::InvisibleStatus))
413 want_osd_msgs_only=true;
414 else if (config.showMsgsInModes & User::OnlineStatus)
415 want_osd_msgs_only = true;
416
417 if (want_osd_msgs_only) {
418 want_osd=true;
419 }
420 }
421 }
422 }
423
424 if (want_osd)
425 {
426 Licq::UserReadGuard u(s->userId());
427 if (u.isLocked())
428 {
429 // user alias as displayed in licq -
430 // (if no alias known, ICQ number as string returned)
431 username = u->getAlias();
432 notify=u->OnlineNotify();
433 ignore=u->InvisibleList() || u->IgnoreList();
434 status = u->status();
435 secure=u->Secure();
436
437 username = my_translate(s->userId(), username, "UTF-8");
438
439 if (s->subSignal() == Licq::PluginSignal::UserEvents && s->argument() > 0) // message
440 {
441 // get the user event whose ID we got as the signal argument
442 e = u->EventPeekId(s->argument());
443
444 if (e == NULL) // event not found
445 {
446 gLog.warning("Event for user %s not found", s->userId().toString().c_str());
447 want_osd=false;
448 }
449 }
450 }
451 else
452 {
453 gLog.warning("User %s not found", s->userId().toString().c_str());
454 want_osd=false;
455 }
456 }
457
458 if (!Enabled)
459 want_osd=false;
460 if (ignore)
461 want_osd=false;
462 if (s->userId().isOwner()) // no messages for our own actions
463 want_osd=false;
464
465 // user checked our auto-response
466 // this is some evil functionality - most users don't know
467 // that you realize when they check your auto-response
468 // i implemented this just for fun :)
469 if ((want_osd) && (!want_osd_msgs_only) && // not ignored or disabled
470 (s->subSignal() == Licq::PluginSignal::UserEvents) &&
471 (s->argument() == 0) // auto response
472 )
473 {
474 if (
475 (config.ShowAutoResponseCheck==1) || // display auto_reponse checks
476 ((config.ShowAutoResponseCheck==2)&&(notify))
477 )
478 {
479 string msg(username);
480 msg+=_(" checked your auto-response");
481 my_xosd_display("autoresponse", msg, config.controlcolour);
482 }
483 }
484
485 // messages that are not sent by myself
486 if ((want_osd) && // not ignored or disabled
487 (s->subSignal() == Licq::PluginSignal::UserEvents) &&
488 (s->argument() > 0) // message
489 )
490 {
491 if (
492 (config.Showmessages==1) || // display messages on screen if configured in config file
493 ((config.Showmessages==2)&&(notify))
494 )
495 {
496 string msg="";
497 if (secure && config.marksecuremessages)
498 msg="(S) ";
499 msg += my_translate(s->userId(), e->text(), "UTF-8");
500 my_xosd_display(username.c_str(), msg.c_str(), config.colour);
501 }
502 if (
503 (config.Showmessages==3) || // only display information about message on screen
504 ((config.Showmessages==4)&&(notify))
505 )
506 {
507 string msg=_("Message from ");
508 msg += username;
509 my_xosd_display("", msg, config.colour);
510 }
511 }
512 if (want_osd && (!want_osd_msgs_only) && (s->subSignal() == Licq::PluginSignal::UserStatus)) // logon/logoff or status change
513 {
514 string msg = username;
515 if (s->argument()!=0) // logon/logoff
516 {
517 if (
518 (config.Showlogon==1) ||
519 ((notify)&&(config.Showlogon==2))
520 )
521 {
522 if (s->argument() > 0)
523 msg+=_(" logged on");
524 else
525 msg+=_(" logged off");
526 // my_xosd_settimeout(config.timeout);
527 my_xosd_display("", msg, config.controlcolour);
528 }
529 }
530 else // status change
531 {
532 if (
533 (config.ShowStatusChange==1) ||
534 ((notify)&&(config.ShowStatusChange==2))
535 )
536 {
537 string msg = username;
538 msg+=_(" changed status to: ");
539 if (status == User::OfflineStatus)
540 msg += _("offline");
541 else if (status & User::DoNotDisturbStatus)
542 msg+=_("do not disturb");
543 else if (status & User::OccupiedStatus)
544 msg+=_("occupied");
545 else if (status & User::NotAvailableStatus)
546 msg+=_("not available");
547 else if (status & User::AwayStatus)
548 msg+=_("away");
549 else if (status & User::FreeForChatStatus)
550 msg+=_("free for chat");
551 else if (status & User::InvisibleStatus)
552 msg+=_("invisible");
553 else if (status & User::IdleStatus)
554 msg += _("idle");
555 else
556 msg += _("online");
557 // my_xosd_settimeout(config.timeout);
558 my_xosd_display("", msg, config.controlcolour);
559 }
560 }
561
562 }
563 }
564 break;
565 case Licq::PluginSignal::SignalLogoff:
566 gLog.info("OSD Plugin received logoff");
567 disabletimer=time(0);
568 Online=false;
569 break;
570 case Licq::PluginSignal::SignalLogon:
571 gLog.info("OSD Plugin received logon");
572 disabletimer=time(0);
573 Online=true;
574 break;
575 // we are not interested in those
576 case Licq::PluginSignal::SignalAddedToServer:
577 case Licq::PluginSignal::SignalPluginEvent:
578 break;
579 default: // shouldnt happen
580 gLog.warning("Unknown signal %d", s->signal());
581 break;
582 }
583 }
584
585 #ifdef CP_TRANSLATE
586 // this function maps the licq character encoding names to the iconv ones.
587 // this is a mess and should be replaced
588 // FIXME !!!
get_iconv_encoding_name(const char * licq_encoding_name)589 const char *get_iconv_encoding_name(const char *licq_encoding_name)
590 {
591 static const char iso8859_1[] = "ISO-8859-1";
592 static const char iso8859_2[] = "ISO-8859-2";
593 static const char iso8859_3[] = "ISO-8859-3";
594 static const char iso8859_5[] = "ISO-8859-5";
595 static const char iso8859_6[] = "ISO-8859-6";
596 static const char iso8859_7[] = "ISO-8859-7";
597 static const char iso8859_8_i[] = "ISO-8859-8";
598 static const char iso8859_9[] = "ISO-8859-9";
599 static const char iso8859_15[] = "ISO-8859-15";
600
601 static const char cp_1250[] = "CP1250";
602 static const char cp_1251[] = "CP1251";
603 static const char cp_1252[] = "CP1252";
604 static const char cp_1253[] = "CP1253";
605 static const char cp_1254[] = "CP1254";
606 static const char cp_1255[] = "CP1255";
607 static const char cp_1256[] = "CP1256";
608 static const char cp_1257[] = "CP1257";
609
610 static const char gbk[] = "GBK";
611 static const char big5[] = "BIG-5";
612 static const char koi8_r[] = "KOI8R";
613 static const char shift_jis[] = "SHIFT-JIS";
614 static const char jis7[] = ""; // no idea
615 static const char eucjp[] = "EUCJP";
616 static const char euckr[] = "EUCKR";
617 static const char tscii[] = "TSCII";
618 static const char tis_620[] = "TIS620";
619 static const char koi8_u[] = "KOI8U";
620 static const char utf_8[] = "UTF-8";
621
622 if (strcasecmp(licq_encoding_name, "ISO 8859-1")==0)
623 return iso8859_1;
624 if (strcasecmp(licq_encoding_name, "ISO 8859-2")==0)
625 return iso8859_2;
626 if (strcasecmp(licq_encoding_name, "ISO 8859-3")==0)
627 return iso8859_3;
628 if (strcasecmp(licq_encoding_name, "ISO 8859-5")==0)
629 return iso8859_5;
630 if (strcasecmp(licq_encoding_name, "ISO 8859-6")==0)
631 return iso8859_6;
632 if (strcasecmp(licq_encoding_name, "ISO 8859-7")==0)
633 return iso8859_7;
634 if (strcasecmp(licq_encoding_name, "ISO 8859-8-I")==0)
635 return iso8859_8_i;
636 if (strcasecmp(licq_encoding_name, "ISO 8859-9")==0)
637 return iso8859_9;
638 if (strcasecmp(licq_encoding_name, "ISO 8859-15")==0)
639 return iso8859_15;
640
641 if (strcasecmp(licq_encoding_name, "CP 1250")==0)
642 return cp_1250;
643 if (strcasecmp(licq_encoding_name, "CP 1251")==0)
644 return cp_1251;
645 if (strcasecmp(licq_encoding_name, "CP 1252")==0)
646 return cp_1252;
647 if (strcasecmp(licq_encoding_name, "CP 1253")==0)
648 return cp_1253;
649 if (strcasecmp(licq_encoding_name, "CP 1254")==0)
650 return cp_1254;
651 if (strcasecmp(licq_encoding_name, "CP 1255")==0)
652 return cp_1255;
653 if (strcasecmp(licq_encoding_name, "CP 1256")==0)
654 return cp_1256;
655 if (strcasecmp(licq_encoding_name, "CP 1257")==0)
656 return cp_1257;
657
658 if (strcasecmp(licq_encoding_name, "GBK")==0)
659 return gbk;
660 if (strcasecmp(licq_encoding_name, "BIG5")==0)
661 return big5;
662 if (strcasecmp(licq_encoding_name, "KOI8-R")==0)
663 return koi8_r;
664 if (strcasecmp(licq_encoding_name, "Shift-JIS")==0)
665 return shift_jis;
666 if (strcasecmp(licq_encoding_name, "JIS7")==0)
667 return jis7;
668 if (strcasecmp(licq_encoding_name, "eucJP")==0)
669 return eucjp;
670 if (strcasecmp(licq_encoding_name, "eucKR")==0)
671 return euckr;
672 if (strcasecmp(licq_encoding_name, "TSCII")==0)
673 return tscii;
674 if (strcasecmp(licq_encoding_name, "TIS-620")==0)
675 return tis_620;
676 if (strcasecmp(licq_encoding_name, "KOI8-U")==0)
677 return koi8_u;
678 if (strcasecmp(licq_encoding_name, "UTF-8")==0)
679 return utf_8;
680 return licq_encoding_name;
681 }
682
683
684 //translates incoming messages or user names to our codepage.
685 // this works only if it is convertable by iconv
686 // the codepage of the other user is determined by the UserEncoding property of
687 // the other user. (change it for example via the qt-gui message window)
688 // Licq:PluginSignal is needed to get the User for this message -
689 // some day i will do this more elegant
my_translate(const UserId &,const string & msg,const char * userenc)690 string my_translate(const UserId& /* userId */, const string& msg, const char* userenc)
691 {
692 iconv_t conv;
693 size_t fromsize, tosize, ressize;
694 const char *msgptr;
695 char *resptr;
696
697 if (config.localencoding == "") {
698 gLog.warning("Didn't get our local encoding");
699 return msg;
700 }
701
702 if ((userenc == 0) || (*userenc == 0))
703 {
704 gLog.info("No translation needs to be done");
705 return msg;
706 }
707 conv = iconv_open((config.localencoding + "//IGNORE").c_str(), get_iconv_encoding_name(userenc));
708
709 // no translation possible?
710 if (conv==(iconv_t)-1)
711 {
712 gLog.warning("Error initializing iconv");
713 return msg;
714 }
715
716 fromsize = msg.size();
717 tosize=fromsize;
718 ressize=tosize;
719 msgptr = msg.c_str();
720
721 char* result = (char*)malloc(msg.size() + 1);
722 resptr=result;
723
724 while ((fromsize>0) && (tosize>0))
725 {
726 if ((int)iconv(conv, (ICONV_CONST char **)&msgptr, &fromsize, &resptr, &tosize)==-1)
727 {
728 // array is not enough
729 if (errno == E2BIG)
730 {
731 // add fromsize + 4 more characters to array
732 result = (char*) realloc(result,ressize + fromsize + 4);
733 resptr = result + ressize;
734 ressize += fromsize + 4;
735 tosize += fromsize + 4;
736 continue;
737 }
738 gLog.warning("Error in my_translate - stopping translation, error on %ld. char",
739 (long int)(msgptr - msg.c_str() + 1));
740 free(result);
741 return msg;
742 }
743 }
744 *resptr = 0;
745 iconv_close(conv);
746
747 string ret(result);
748 free(result);
749 return ret;
750 }
751 #else
752 // a dummy function which helps me to remove the #ifdef CP_TRANSLATEs in a lot of my code
my_translate(const UserId &,const string & msg,Licq::PluginSignal *)753 string my_translate(const UserId& /* userId */, const string& msg, Licq::PluginSignal* /* s */)
754 {
755 return strdup(msg.c_str());
756 }
757
758 #endif
759