1 /*
2  *      dxutils.cpp
3  *
4  *      Copyright 2014 David Vachulka <arch_dvx@users.sourceforge.net>
5  *
6  *      This program 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 3 of the License, or
9  *      (at your option) any later version.
10  *
11  *      This program 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 this program; if not, write to the Free Software
18  *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *      MA 02110-1301, USA.
20  */
21 
22 #ifdef WIN32
23  #define WIN32_LEAN_AND_MEAN
24  #include <windows.h>
25  #include <mmsystem.h>
26  #include <ctime>
27  #include <shellapi.h>
28 #endif
29 #include <QApplication>
30 #include <QColor>
31 #include <QBuffer>
32 #include <QFile>
33 #include <QDebug>
34 #include <QTime>
35 #include <QDir>
36 #include <QRegularExpression>
37 #include <QProcessEnvironment>
38 #include <QSettings>
39 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
40 #include <QSound>
41 #endif
42 #include <string>
43 #include <random>
44 #include "preferences.h"
45 #include "dxutils.h"
46 #include "notify/notifywindow.h"
47 #include "i18n.h"
48 #ifdef HAVE_ENCHANT
49 #include <enchant++.h>
50 #endif
51 #ifdef Q_OS_DARWIN
52  #include "widgets/macspellcheck.h"
53  #include "notify/macnotify.h"
54 #endif
55 
56 #ifdef HAVE_ENCHANT
57 static enchant::Broker *ebroker;
58 typedef std::pair<Checkers*,QStringList*> CheckerPair;
enumerateDicts(const char * const lang_tag,const char * const,const char * const,const char * const,void * user_data)59 void enumerateDicts (const char * const lang_tag,
60          const char * const /*provider_name*/,
61          const char * const /*provider_desc*/,
62          const char * const /*provider_file*/,
63          void * user_data)
64 {
65     CheckerPair *chpair = (CheckerPair*)user_data;
66     const Checkers &checkers = *chpair->first;
67     QStringList &spellLang = *(chpair->second);
68     if(checkers.find(lang_tag) == checkers.end())
69         spellLang.append(lang_tag);
70 }
71 #endif
72 
73 #ifdef Q_OS_DARWIN
74 static MacSpellCheck *_instance;
75 #endif
76 
caseInsensitiveLessThan(const QString & s1,const QString & s2)77 bool caseInsensitiveLessThan(const QString &s1, const QString &s2)
78 {
79     return s1.toLower() < s2.toLower();
80 }
81 
dxutils()82 dxutils::dxutils()
83 {
84     m_notifiesHeight = 0;
85     m_notifyPosition = -1;
86     m_firstNotify = false;
87     m_haveNotify = false;
88 #ifndef WIN32
89     QDir dir;
90     QStringList paths = QString(getenv("PATH")).split(':');
91     foreach(QString path, paths)
92     {
93         if(dir.exists(path+"/notify-send"))
94         {
95             m_haveNotify = true;
96             break;
97         }
98     }
99 #endif // WIN32
100 #ifdef Q_OS_DARWIN
101     m_haveNotify = false;  //I think notifywindow is better than native notify
102 #endif
103 #ifdef HAVE_ENCHANT
104 #ifdef HAVE_ENCHANT2
105     ebroker = new enchant::Broker();
106 #else
107     ebroker = enchant::Broker::instance();
108 #endif //HAVE_ENCHANT2
109 #endif //HAVE_ENCHANT
110 }
111 
~dxutils()112 dxutils::~dxutils()
113 {
114 #ifdef HAVE_ENCHANT
115     Checkers::const_iterator it = m_checkers.begin();
116     for(; it != m_checkers.end(); it++)
117     {
118         delete (*it).second;
119     }
120 #endif
121 #ifdef HAVE_ENCHANT2
122     delete ebroker;
123 #endif
124 }
125 
instance()126 dxutils &dxutils::instance()
127 {
128     static dxutils idxutils;
129     return idxutils;
130 }
131 
isBadchar(char c)132 bool dxutils::isBadchar(char c)
133 {
134     switch(c) {
135         case ' ':
136         case ',':
137         case '\0':
138         case '\02':
139         case '\03':
140         case '\017':
141         case '\021':
142         case '\026':
143         case '\035':
144         case '\037':
145         case '\n':
146         case '\r':
147         case '<':
148         case '>':
149         case '"':
150         case '\'':
151             return true;
152         default:
153             return false;
154     }
155 }
156 
157 // checks is char nick/word delimiter
isDelimiter(char c)158 bool dxutils::isDelimiter(char c)
159 {
160     switch(c) {
161         case ' ':
162         case '.':
163         case ',':
164         case '/':
165         case '\\':
166         case '`':
167         case '\'':
168         case '!':
169         case '(':
170         case ')':
171         case '{':
172         case '}':
173         case '|':
174         case '[':
175         case ']':
176         case '\"':
177         case ':':
178         case ';':
179         case '<':
180         case '>':
181         case '?':
182             return true;
183         default:
184             return false;
185     }
186 }
187 
188 //Return file size in human readable form
getFileSize(quint64 size)189 QString dxutils::getFileSize(quint64 size)
190 {
191     double fsize = 0.0;
192     if(size > 1000000000)
193     {
194         fsize = size/1073741824.0;
195         return QString("%1 %2").arg(fsize, 0, 'f', 2).arg(_("GB"));
196     }
197     if(size > 100000)
198     {
199         fsize = size/1048576.0;
200         return QString("%1 %2").arg(fsize, 0, 'f', 2).arg(_("MB"));
201     }
202     if(size > 1000)
203     {
204         fsize = size/1024.0;
205         return QString("%1 %2").arg(fsize, 0, 'f', 2).arg(_("KB"));
206     }
207     return QString("%1 %2").arg(size).arg(_("bytes"));
208 }
209 
getFileSize(const QString & ssize)210 QString dxutils::getFileSize(const QString& ssize)
211 {
212     return getFileSize(ssize.toLongLong());
213 }
214 
215 //std::string to QString
fromStdString(const std::string & str)216 QString dxutils::fromStdString(const std::string &str)
217 {
218     return QString::fromUtf8(str.c_str());
219 }
220 
221 //QString to std::string
toStdString(const QString & str)222 std::string dxutils::toStdString(const QString &str)
223 {
224     return str.toUtf8().constData();
225 }
226 
getNickColor(const QString & nick)227 QString dxutils::getNickColor(const QString &nick)
228 {
229     int len = nick.length();
230     quint32 h = 0;
231     for(int i=0; i<len; i++)
232         h = ((h << 5) + h) ^ nick[i].toLatin1();
233     switch(h%8)
234     {
235         case 0: return QColor(196,160,0).name();
236         case 1: return QColor(206,92,0).name();
237         case 2: return QColor(143,89,2).name();
238         case 3: return QColor(78,154,6).name();
239         case 4: return QColor(32,74,135).name();
240         case 5: return QColor(117,80,123).name();
241         case 6: return QColor(164,0,0).name();
242         default: return QColor(85,87,83).name();
243     }
244 }
245 
246 /*Return download/send speed in human readable form
247  * speed = difference between two position during 1 second
248  */
getSpeed(quint64 speed)249 QString dxutils::getSpeed(quint64 speed)
250 {
251     double fspeed = 0.0;
252     if(speed > 100000)
253     {
254         fspeed = speed/(1048576.0);
255         return _("%1 MB/s").arg(fspeed, 0, 'f', 2);
256     }
257     fspeed = speed/(1024.0);
258     return _("%1 KB/s").arg(fspeed, 0, 'f', 2);
259 }
260 
261 //Return remaining time of download/send
getRemaining(quint64 size,quint64 speed)262 QString dxutils::getRemaining(quint64 size, quint64 speed)
263 {
264     if(!speed) return "?";
265     quint64 remainingTime = size/speed;
266     if(remainingTime <= 0 || remainingTime > 54000) return "?";
267     else
268     {
269         quint64 secs = remainingTime;
270         quint64 hours = remainingTime/3600;
271         secs -= hours*3600;
272         quint64 mins = secs/60;
273         secs -= mins*60;
274         return QString("%1:%2:%3").arg(hours).arg(mins, 2, 10, QLatin1Char('0')).arg(secs, 2, 10, QLatin1Char('0'));
275     }
276 }
277 
278 #ifdef Q_OS_DARWIN
showNotify(QString text,int position)279 void dxutils::showNotify(QString text, int position)
280 {
281       //I think notifywindow is better than native notify
282 //    MacNotify::instance()->showNotify(text);
283     text.replace("\n", "<br>");
284     if(!m_firstNotify || position!=m_notifyPosition)
285     {
286         m_firstNotify = true;
287         m_notifiesHeight = 0;
288         m_notifyPosition = position;
289     }
290     NotifyWindow *notify = new NotifyWindow(text, m_notifiesHeight, 5);
291     notify->showNotify(position);
292     m_notifiesHeight += notify->height()+4;
293 }
294 #else
showNotify(QString text,int position)295 void dxutils::showNotify(QString text, int position)
296 {
297     if(m_haveNotify)
298     {
299         QString exec = QString("notify-send -i %1 dxirc '%2'").arg(dxutils::getDataPath()+"/icons/big_dxirc.png").arg(text);
300         system(exec.toUtf8().constData());
301     }
302     else
303     {
304         text.replace("\n", "<br>");
305         if(!m_firstNotify || position!=m_notifyPosition)
306         {
307             m_firstNotify = true;
308             m_notifiesHeight = 0;
309             m_notifyPosition = position;
310         }
311         NotifyWindow *notify = new NotifyWindow(text, m_notifiesHeight, 5);
312         notify->showNotify(position);
313         m_notifiesHeight += notify->height()+4;
314     }
315 }
316 #endif
317 
removeNotify()318 void dxutils::removeNotify()
319 {
320     if(m_firstNotify)
321         m_firstNotify = !m_firstNotify;
322 }
323 
debugLine(const QString & line)324 void dxutils::debugLine(const QString &line)
325 {
326 #ifdef DEBUG
327     qDebug() << QTime::currentTime().toString("[hh:mm:ss] ") << line;
328 #endif
329 }
330 
331 //is file with name on path right dxirc log file?
isRightLogFile(const QString & path,const QString & name)332 bool dxutils::isRightLogFile(const QString& path, const QString& name)
333 {
334     if(QRegularExpression("^\\d\\d\\d\\d-\\d\\d-\\d\\d+$").match(name).hasMatch())
335     {
336         QFile file(path);
337         if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
338             return false;
339         char buf[22];
340         qint64 lineLength = file.readLine(buf, sizeof(buf));
341         if(lineLength != -1)
342         {
343             QRegularExpression ex("^\\[\\d\\d:\\d\\d:\\d\\d\\] ");
344             if(ex.match(QString(buf)).hasMatch())
345                 return true;
346             else
347                 return false;
348         }
349         else
350             return false;
351     }
352     return false;
353 }
354 
355 //get month string
getMonth(int month)356 QString dxutils::getMonth(int month)
357 {
358     switch(month) {
359         case 1: return _("January");
360         case 2: return _("February");
361         case 3: return _("March");
362         case 4: return _("April");
363         case 5: return _("May");
364         case 6: return _("June");
365         case 7: return _("July");
366         case 8: return _("August");
367         case 9: return _("September");
368         case 10: return _("October");
369         case 11: return _("November");
370         case 12: return _("December");
371         default: return "Rok ma jen 12 mesicu:)";
372     }
373 }
374 
375 //get month string-number for name
getMonthNumber(const QString & month)376 QString dxutils::getMonthNumber(const QString& month)
377 {
378     if(month==_("January")) return "01";
379     else if(month==_("February")) return "02";
380     else if(month==_("March")) return "03";
381     else if(month==_("April")) return "04";
382     else if(month==_("May")) return "05";
383     else if(month==_("June")) return "06";
384     else if(month==_("July")) return "07";
385     else if(month==_("August")) return "08";
386     else if(month==_("September")) return "09";
387     else if(month==_("October")) return "10";
388     else if(month==_("November")) return "11";
389     else if(month==_("December")) return "12";
390     return "00";
391 }
392 
playFile(const QString & file)393 void dxutils::playFile(const QString &file)
394 {
395     QDir dir;
396     if(dir.exists(file))
397     {
398 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
399 #ifdef _WIN32
400         PlaySoundA((LPCSTR)file.toUtf8().constData(), NULL, SND_FILENAME | SND_ASYNC);
401 #else
402         static const char * players[]={"aplay","play","esdplay","artsplay","ossplay",NULL};
403         QString exec;
404         QStringList paths = QString(getenv("PATH")).split(':');
405         foreach(QString path, paths)
406         {
407             for(int i=0; players[i]!=NULL; i++)
408             {
409                 if(dir.exists(path+"/"+players[i]))
410                 {
411                     exec = path+"/"+players[i];
412                     break;
413                 }
414             }
415         }
416         if(exec.isEmpty()) return;
417         if(exec.contains("aplay")) exec += " -q";
418         exec += " "+enquote(file)+" &";
419         system(exec.toUtf8().constData());
420 #endif
421 #else
422         QSound::play(file);
423 #endif
424     }
425 }
426 
createSmileys(QString text)427 QString dxutils::createSmileys(QString text)
428 {
429     for(QMap<QString,QString>::const_iterator it=preferences.m_smileysMap.constBegin(); it!=preferences.m_smileysMap.constEnd(); it++)
430     {
431         if(text.contains(it.key()))
432         {
433             text.replace(it.key(), "<img src='"+it.value()+"'>");
434         }
435     }
436     return text;
437 }
438 
439 //check path for nick icons
checkThemePath(const QString & path)440 QString dxutils::checkThemePath(const QString &path)
441 {
442     if(path == "internal") return path;
443     QString themeDefaultPath = "internal";
444     if(QFileInfo(path+"/irc_normal.png").exists()) return path;
445     return themeDefaultPath;
446 }
447 
448 //check path list for nick icons
checkThemesList(const QString & list)449 QString dxutils::checkThemesList(const QString &list)
450 {
451     QString themeDefaultPath = "internal;";
452     QString themes;
453 #if QT_VERSION < QT_VERSION_CHECK(5,15,0)
454     QStringList pathes = list.split(';', QString::SkipEmptyParts);
455 #else
456     QStringList pathes = list.split(';', Qt::SkipEmptyParts);
457 #endif
458     for(int i=0; i<pathes.size(); ++i)
459     {
460         if(QFileInfo(pathes[i]+"/irc_normal.png").exists()) themes.append(pathes[i]+";");
461     }
462     if(!themes.contains(themeDefaultPath)) themes.prepend(themeDefaultPath);
463     if(!themes.isEmpty()) return themes;
464     return themeDefaultPath;
465 }
466 
haveNotify()467 bool dxutils::haveNotify()
468 {
469     return m_haveNotify;
470 }
471 
encrypt(const QString & text)472 QString dxutils::encrypt(const QString &text)
473 {
474     QString result = "";
475     const std::string CHARACTERS = "0123456789!@#$%^&*ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
476     std::random_device random_device;
477     std::mt19937 generator(random_device());
478     std::uniform_int_distribution<> distribution(0, CHARACTERS.size() - 1);
479     for(int i=0; i<text.length(); i++)
480     {
481         result += text[i];
482         result += CHARACTERS[distribution(generator)];
483     }
484     return result;
485 }
486 
decrypt(const QString & text)487 QString dxutils::decrypt(const QString &text)
488 {
489     QString result = "";
490     for(int i=0; i<text.length(); i++)
491     {
492         if((i+1)%2) result += text[i];
493     }
494     return result;
495 }
496 
getParam(QString toParse,int n,bool toEnd)497 QString dxutils::getParam(QString toParse, int n, bool toEnd)
498 {
499     return getParam(toParse, n, toEnd, ' ');
500 }
501 
getParam(QString toParse,int n,bool toEnd,const char & separator)502 QString dxutils::getParam(QString toParse, int n, bool toEnd, const char &separator)
503 {
504     if(toEnd)
505     {
506         return toParse.section(separator, n-1);
507     }
508     else
509     {
510         QString result = toParse.section(separator, n-1, n-1);
511         if(result.isEmpty()) return toParse.section(separator, -1);
512         else return result;
513     }
514 }
515 
removeSpaces(const QString & text)516 QString dxutils::removeSpaces(const QString &text)
517 {
518     if(text.contains(' '))
519     {
520         QString removed;
521         for(int i=0; i<=text.length(); i++)
522         {
523             if(text[i].toLatin1() != 32)
524                 removed += text[i];
525         }
526         return removed;
527     }
528     else
529         return text;
530 }
531 
removeNonalphanumeric(const QString & text)532 QString dxutils::removeNonalphanumeric(const QString &text)
533 {
534     QString result;
535     for(int i=0; i<text.length(); i++)
536     {
537         if((47<text[i].toLatin1()&&text[i].toLatin1()<58) ||
538                 (64<text[i].toLatin1()&&text[i].toLatin1()<91) ||
539                 (96<text[i].toLatin1()&&text[i].toLatin1()<123))
540             result += text[i];
541         else
542             result += '0';
543     }
544     return result;
545 }
546 
createModes(char sign,char mode,QString nicks)547 QString dxutils::createModes(char sign, char mode, QString nicks)
548 {
549     QString modes;
550     modes += sign;
551     QString tomode;
552     if(!nicks.contains(' ')) return modes+mode+" "+nicks;
553     if(nicks.right(1) != " ") nicks.append(" ");
554     while(nicks.contains(' '))
555     {
556         modes += mode;
557         tomode += nicks.section(' ',0,0)+" ";
558         nicks = nicks.section(' ',1);
559     }
560     return modes+" "+tomode;
561 }
562 
563 //from kde source, thx
isUtf8(const char * buf)564 bool dxutils::isUtf8(const char *buf)
565 {
566     int i, n;
567     unsigned char c;
568     bool gotone = false;
569     if (!buf)
570     return true; // whatever, just don't crash
571 
572     #define F 0   /* character never appears in text */
573     #define T 1   /* character appears in plain ASCII text */
574     #define I 2   /* character appears in ISO-8859 text */
575     #define X 3   /* character appears in non-ISO extended ASCII (Mac, IBM PC) */
576 
577     static const unsigned char text_chars[256] = {
578         /*                  BEL BS HT LF    FF CR    */
579         F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F,  /* 0x0X */
580         /*                              ESC          */
581         F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F,  /* 0x1X */
582         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x2X */
583         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x3X */
584         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x4X */
585         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x5X */
586         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x6X */
587         T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F,  /* 0x7X */
588         /*            NEL                            */
589         X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X,  /* 0x8X */
590         X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,  /* 0x9X */
591         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xaX */
592         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xbX */
593         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xcX */
594         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xdX */
595         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xeX */
596         I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I   /* 0xfX */
597     };
598 
599     /* *ulen = 0; */
600     for (i = 0; (c = buf[i]); i++)
601     {
602         if ((c & 0x80) == 0) /* 0xxxxxxx is plain ASCII */
603         {
604         /*
605         * Even if the whole file is valid UTF-8 sequences,
606         * still reject it if it uses weird control characters.
607         */
608 
609         if (text_chars[c] != T)
610             return false;
611 
612         }
613         else if ((c & 0x40) == 0) /* 10xxxxxx never 1st byte */
614         {
615         return false;
616         }
617         else /* 11xxxxxx begins UTF-8 */
618         {
619             int following;
620 
621             if ((c & 0x20) == 0) {             /* 110xxxxx */
622             following = 1;
623             }
624             else if ((c & 0x10) == 0) {      /* 1110xxxx */
625             following = 2;
626             }
627             else if ((c & 0x08) == 0) {      /* 11110xxx */
628             following = 3;
629             }
630             else if ((c & 0x04) == 0) {      /* 111110xx */
631             following = 4;
632             }
633             else if ((c & 0x02) == 0) {      /* 1111110x */
634             following = 5;
635             }
636             else
637                 return false;
638 
639             for (n = 0; n < following; n++) {
640                 i++;
641                 if (!(c = buf[i]))
642                 goto done;
643 
644                 if ((c & 0x80) == 0 || (c & 0x40))
645                 return false;
646             }
647             gotone = true;
648         }
649     }
650     done:
651     return gotone;   /* don't claim it's UTF-8 if it's all 7-bit */
652 }
653 
654 //get default spellchecking language
655 #ifdef HAVE_ENCHANT
getDefaultLang()656 QString dxutils::getDefaultLang()
657 {
658     if(m_locale.isEmpty()) getLocale();
659     if(m_checkers.find(m_locale) != m_checkers.end())
660         return m_locale;
661     Checkers::const_iterator it = m_checkers.begin();
662     QString language = m_locale.section('_',0,0);
663     for(; it != m_checkers.end(); it++)
664     {
665         if(QString::compare((*it).first.section('_',0,0),language)==0) return language;
666     }
667     if(m_availableSpellLangs.size()) return m_availableSpellLangs[0];
668     else return "";
669 }
670 #else
getDefaultLang()671 QString dxutils::getDefaultLang()
672 {
673     if(m_locale.isEmpty()) getLocale();
674     return m_locale;
675 }
676 #endif
677 
678 //return locale, e.g cs_CZ etc.
getLocale()679 QString dxutils::getLocale()
680 {
681     if(!m_locale.isEmpty())
682         return m_locale;
683 #ifdef WIN32
684     LCID lcid = GetUserDefaultLCID();
685     if(lcid!=0)
686     {
687         quint32 localeid = LANGIDFROMLCID(lcid);
688         /* locale code from this page
689          * http://msdn.microsoft.com/en-us/library/dd318693%28v=VS.85%29.aspx
690          * not fully implemented
691          */
692         switch(localeid){
693             case 0x0436: m_locale = "af_ZA";break; // Afrikaans
694             case 0x041c: m_locale = "sq_AL";break; // Albanian
695             case 0x0401: m_locale = "ar_SA";break; // Arabic - Saudi Arabia
696             case 0x0801: m_locale = "ar_IQ";break; // Arabic - Iraq
697             case 0x0c01: m_locale = "ar_EG";break; // Arabic - Egypt
698             case 0x1001: m_locale = "ar_LY";break; // Arabic - Libya
699             case 0x1401: m_locale = "ar_DZ";break; // Arabic - Algeria
700             case 0x1801: m_locale = "ar_MA";break; // Arabic - Morocco
701             case 0x1c01: m_locale = "ar_TN";break; // Arabic - Tunisia
702             case 0x2001: m_locale = "ar_OM";break; // Arabic - Oman
703             case 0x2401: m_locale = "ar_YE";break; // Arabic - Yemen
704             case 0x2801: m_locale = "ar_SY";break; // Arabic - Syria
705             case 0x2c01: m_locale = "ar_JO";break; // Arabic - Jordan
706             case 0x3001: m_locale = "ar_LB";break; // Arabic - Lebanon
707             case 0x3401: m_locale = "ar_KW";break; // Arabic - Kuwait
708             case 0x3801: m_locale = "ar_AE";break; // Arabic - United Arab Emirates
709             case 0x3c01: m_locale = "ar_BH";break; // Arabic - Bahrain
710             case 0x4001: m_locale = "ar_QA";break; // Arabic - Qatar
711             case 0x042b: m_locale = "hy_AM";break; // Armenian
712             case 0x042c: m_locale = "az_AZ";break; // Azeri Latin
713             case 0x082c: m_locale = "az_AZ";break; // Azeri - Cyrillic
714             case 0x042d: m_locale = "eu_ES";break; // Basque
715             case 0x0423: m_locale = "be_BY";break; // Belarusian
716             case 0x0445: m_locale = "bn_IN";break; // Begali
717             case 0x201a: m_locale = "bs_BA";break; // Bosnian
718             case 0x141a: m_locale = "bs_BA";break; // Bosnian - Cyrillic
719             case 0x047e: m_locale = "br_FR";break; // Breton - France
720             case 0x0402: m_locale = "bg_BG";break; // Bulgarian
721             case 0x0403: m_locale = "ca_ES";break; // Catalan
722             case 0x0004: m_locale = "zh_CHS";break; // Chinese - Simplified
723             case 0x0404: m_locale = "zh_TW";break; // Chinese - Taiwan
724             case 0x0804: m_locale = "zh_CN";break; // Chinese - PRC
725             case 0x0c04: m_locale = "zh_HK";break; // Chinese - Hong Kong S.A.R.
726             case 0x1004: m_locale = "zh_SG";break; // Chinese - Singapore
727             case 0x1404: m_locale = "zh_MO";break; // Chinese - Macao S.A.R.
728             case 0x7c04: m_locale = "zh_CHT";break; // Chinese - Traditional
729             case 0x041a: m_locale = "hr_HR";break; // Croatian
730             case 0x101a: m_locale = "hr_BA";break; // Croatian - Bosnia
731             case 0x0405: m_locale = "cs_CZ";break; // Czech
732             case 0x0406: m_locale = "da_DK";break; // Danish
733             case 0x048c: m_locale = "gbz_AF";break; // Dari - Afghanistan
734             case 0x0465: m_locale = "div_MV";break; // Divehi - Maldives
735             case 0x0413: m_locale = "nl_NL";break; // Dutch - The Netherlands
736             case 0x0813: m_locale = "nl_BE";break; // Dutch - Belgium
737             case 0x0409: m_locale = "en_US";break; // English - United States
738             case 0x0809: m_locale = "en_GB";break; // English - United Kingdom
739             case 0x0c09: m_locale = "en_AU";break; // English - Australia
740             case 0x1009: m_locale = "en_CA";break; // English - Canada
741             case 0x1409: m_locale = "en_NZ";break; // English - New Zealand
742             case 0x1809: m_locale = "en_IE";break; // English - Ireland
743             case 0x1c09: m_locale = "en_ZA";break; // English - South Africa
744             case 0x2009: m_locale = "en_JA";break; // English - Jamaica
745             case 0x2409: m_locale = "en_CB";break; // English - Carribbean
746             case 0x2809: m_locale = "en_BZ";break; // English - Belize
747             case 0x2c09: m_locale = "en_TT";break; // English - Trinidad
748             case 0x3009: m_locale = "en_ZW";break; // English - Zimbabwe
749             case 0x3409: m_locale = "en_PH";break; // English - Phillippines
750             case 0x0425: m_locale = "et_EE";break; // Estonian
751             case 0x0438: m_locale = "fo_FO";break; // Faroese
752             case 0x0464: m_locale = "fil_PH";break; // Filipino
753             case 0x040b: m_locale = "fi_FI";break; // Finnish
754             case 0x040c: m_locale = "fr_FR";break; // French - France
755             case 0x080c: m_locale = "fr_BE";break; // French - Belgium
756             case 0x0c0c: m_locale = "fr_CA";break; // French - Canada
757             case 0x100c: m_locale = "fr_CH";break; // French - Switzerland
758             case 0x140c: m_locale = "fr_LU";break; // French - Luxembourg
759             case 0x180c: m_locale = "fr_MC";break; // French - Monaco
760             case 0x0462: m_locale = "fy_NL";break; // Frisian - Netherlands
761             case 0x0456: m_locale = "gl_ES";break; // Galician
762             case 0x0437: m_locale = "ka_GE";break; // Georgian
763             case 0x0407: m_locale = "de_DE";break; // German - Germany
764             case 0x0807: m_locale = "de_CH";break; // German - Switzerland
765             case 0x0c07: m_locale = "de_AT";break; // German - Austria
766             case 0x1007: m_locale = "de_LU";break; // German - Luxembourg
767             case 0x1407: m_locale = "de_LI";break; // German - Liechtenstein
768             case 0x0408: m_locale = "el_GR";break; // Greek
769             case 0x0447: m_locale = "gu_IN";break; // Gujarati
770             case 0x040d: m_locale = "he_IL";break; // Hebrew
771             case 0x0439: m_locale = "hi_IN";break; // Hindi
772             case 0x040e: m_locale = "hu_HU";break; // Hungarian
773             case 0x040f: m_locale = "is_IS";break; // Icelandic
774             case 0x0421: m_locale = "id_ID";break; // Indonesian
775             case 0x045d: m_locale = "iu_CA";break; // Inuktitut
776             case 0x085d: m_locale = "iu_CA";break; // Inuktitut - Latin
777             case 0x083c: m_locale = "ga_IE";break; // Irish - Ireland
778             case 0x0434: m_locale = "xh_ZA";break; // Xhosa - South Africa
779             case 0x0435: m_locale = "zu_ZA";break; // Zulu
780             case 0x0410: m_locale = "it_IT";break; // Italian - Italy
781             case 0x0810: m_locale = "it_CH";break; // Italian - Switzerland
782             case 0x0411: m_locale = "ja_JP";break; // Japanese
783             case 0x044b: m_locale = "kn_IN";break; // Kannada - India
784             case 0x043f: m_locale = "kk_KZ";break; // Kazakh
785             case 0x0457: m_locale = "kok_IN";break; // Konkani
786             case 0x0412: m_locale = "ko_KR";break; // Korean
787             case 0x0440: m_locale = "ky_KG";break; // Kyrgyz
788             case 0x0426: m_locale = "lv_LV";break; // Latvian
789             case 0x0427: m_locale = "lt_LT";break; // Lithuanian
790             case 0x046e: m_locale = "lb_LU";break; // Luxembourgish
791             case 0x042f: m_locale = "mk_MK";break; // FYRO Macedonian
792             case 0x043e: m_locale = "ms_MY";break; // Malay - Malaysia
793             case 0x083e: m_locale = "ms_BN";break; // Malay - Brunei
794             case 0x044c: m_locale = "ml_IN";break; // Malayalam - India
795             case 0x043a: m_locale = "mt_MT";break; // Maltese
796             case 0x0481: m_locale = "mi_NZ";break; // Maori
797             case 0x047a: m_locale = "arn_CL";break; // Mapudungun
798             case 0x044e: m_locale = "mr_IN";break; // Marathi
799             case 0x047c: m_locale = "moh_CA";break; // Mohawk - Canada
800             case 0x0450: m_locale = "mn_MN";break; // Mongolian
801             case 0x0461: m_locale = "ne_NP";break; // Nepali
802             case 0x0414: m_locale = "nb_NO";break; // Norwegian - Bokmal
803             case 0x0814: m_locale = "nn_NO";break; // Norwegian - Nynorsk
804             case 0x0482: m_locale = "oc_FR";break; // Occitan - France
805             case 0x0448: m_locale = "or_IN";break; // Oriya - India
806             case 0x0463: m_locale = "ps_AF";break; // Pashto - Afghanistan
807             case 0x0429: m_locale = "fa_IR";break; // Persian
808             case 0x0415: m_locale = "pl_PL";break; // Polish
809             case 0x0416: m_locale = "pt_BR";break; // Portuguese - Brazil
810             case 0x0816: m_locale = "pt_PT";break; // Portuguese - Portugal
811             case 0x0446: m_locale = "pa_IN";break; // Punjabi
812             case 0x046b: m_locale = "quz_BO";break; // Quechua (Bolivia)
813             case 0x086b: m_locale = "quz_EC";break; // Quechua (Ecuador)
814             case 0x0c6b: m_locale = "quz_PE";break; // Quechua (Peru)
815             case 0x0418: m_locale = "ro_RO";break; // Romanian - Romania
816             case 0x0417: m_locale = "rm_CH";break; // Raeto-Romanese
817             case 0x0419: m_locale = "ru_RU";break; // Russian
818             case 0x243b: m_locale = "smn_FI";break; // Sami Finland
819             case 0x103b: m_locale = "smj_NO";break; // Sami Norway
820             case 0x143b: m_locale = "smj_SE";break; // Sami Sweden
821             case 0x043b: m_locale = "se_NO";break; // Sami Northern Norway
822             case 0x083b: m_locale = "se_SE";break; // Sami Northern Sweden
823             case 0x0c3b: m_locale = "se_FI";break; // Sami Northern Finland
824             case 0x203b: m_locale = "sms_FI";break; // Sami Skolt
825             case 0x183b: m_locale = "sma_NO";break; // Sami Southern Norway
826             case 0x1c3b: m_locale = "sma_SE";break; // Sami Southern Sweden
827             case 0x044f: m_locale = "sa_IN";break; // Sanskrit
828             case 0x0c1a: m_locale = "sr_SP";break; // Serbian - Cyrillic
829             case 0x1c1a: m_locale = "sr_BA";break; // Serbian - Bosnia Cyrillic
830             case 0x081a: m_locale = "sr_SP";break; // Serbian - Latin
831             case 0x181a: m_locale = "sr_BA";break; // Serbian - Bosnia Latin
832             case 0x046c: m_locale = "ns_ZA";break; // Northern Sotho
833             case 0x0432: m_locale = "tn_ZA";break; // Setswana - Southern Africa
834             case 0x041b: m_locale = "sk_SK";break; // Slovak
835             case 0x0424: m_locale = "sl_SI";break; // Slovenian
836             case 0x040a: m_locale = "es_ES";break; // Spanish - Spain
837             case 0x080a: m_locale = "es_MX";break; // Spanish - Mexico
838             case 0x0c0a: m_locale = "es_ES";break; // Spanish - Spain (Modern)
839             case 0x100a: m_locale = "es_GT";break; // Spanish - Guatemala
840             case 0x140a: m_locale = "es_CR";break; // Spanish - Costa Rica
841             case 0x180a: m_locale = "es_PA";break; // Spanish - Panama
842             case 0x1c0a: m_locale = "es_DO";break; // Spanish - Dominican Republic
843             case 0x200a: m_locale = "es_VE";break; // Spanish - Venezuela
844             case 0x240a: m_locale = "es_CO";break; // Spanish - Colombia
845             case 0x280a: m_locale = "es_PE";break; // Spanish - Peru
846             case 0x2c0a: m_locale = "es_AR";break; // Spanish - Argentina
847             case 0x300a: m_locale = "es_EC";break; // Spanish - Ecuador
848             case 0x340a: m_locale = "es_CL";break; // Spanish - Chile
849             case 0x380a: m_locale = "es_UR";break; // Spanish - Uruguay
850             case 0x3c0a: m_locale = "es_PY";break; // Spanish - Paraguay
851             case 0x400a: m_locale = "es_BO";break; // Spanish - Bolivia
852             case 0x440a: m_locale = "es_SV";break; // Spanish - El Salvador
853             case 0x480a: m_locale = "es_HN";break; // Spanish - Honduras
854             case 0x4c0a: m_locale = "es_NI";break; // Spanish - Nicaragua
855             case 0x500a: m_locale = "es_PR";break; // Spanish - Puerto Rico
856             case 0x0441: m_locale = "sw_KE";break; // Swahili
857             case 0x041d: m_locale = "sv_SE";break; // Swedish - Sweden
858             case 0x081d: m_locale = "sv_FI";break; // Swedish - Finland
859             case 0x045a: m_locale = "syr_SY";break; // Syriac
860             case 0x0449: m_locale = "ta_IN";break; // Tamil
861             case 0x0444: m_locale = "tt_RU";break; // Tatar
862             case 0x044a: m_locale = "te_IN";break; // Telugu
863             case 0x041e: m_locale = "th_TH";break; // Thai
864             case 0x041f: m_locale = "tr_TR";break; // Turkish
865             case 0x0422: m_locale = "uk_UA";break; // Ukrainian
866             case 0x0420: m_locale = "ur_PK";break; // Urdu
867             case 0x0820: m_locale = "ur_IN";break; // Urdu - India
868             case 0x0443: m_locale = "uz_UZ";break; // Uzbek - Latin
869             case 0x0843: m_locale = "uz_UZ";break; // Uzbek - Cyrillic
870             case 0x042a: m_locale = "vi_VN";break; // Vietnamese
871             case 0x0452: m_locale = "cy_GB";break; // Welsh
872             default: m_locale = "en_US";
873         }
874     }
875     else m_locale = "en_US";
876 #else
877     if(!QProcessEnvironment::systemEnvironment().value("LANG").isEmpty()) m_locale = QProcessEnvironment::systemEnvironment().value("LANG");
878     else if(!QProcessEnvironment::systemEnvironment().value("LC_ALL").isEmpty()) m_locale = QProcessEnvironment::systemEnvironment().value("LC_ALL");
879     else if(!QProcessEnvironment::systemEnvironment().value("LC_MESSAGES").isEmpty()) m_locale = QProcessEnvironment::systemEnvironment().value("LC_MESSAGES");
880     else m_locale = "en_US";
881     if(m_locale == "C" || m_locale == "POSIX")
882     {
883         m_locale = "en_US";
884     }
885     m_locale = m_locale.section('.',0,0).section('@',0,0);
886 #endif
887     return m_locale;
888 }
889 
loadAlias()890 void dxutils::loadAlias()
891 {
892     QSettings set(preferences.getIniFile(), QSettings::IniFormat);
893     set.beginGroup("ALIASES");
894     int num = set.value("number", 0).toInt();
895     m_aliases.clear();
896     if(num)
897     {
898         for(int i=0; i<num; i++)
899         {
900             QString key, value;
901             key = set.value(QString("key%1").arg(i), "").toString();
902             value = set.value(QString("value%1").arg(i), "").toString();
903             if(!key.isEmpty() && !value.isEmpty())
904                 m_aliases.insert(key, value);
905         }
906     }
907     set.endGroup();
908     fillCommands();
909 }
910 
setAliases(QMap<QString,QString> a)911 void dxutils::setAliases(QMap<QString,QString> a)
912 {
913     m_aliases = a;
914     fillCommands();
915 }
916 
getAlias(QString key)917 QString dxutils::getAlias(QString key)
918 {
919     if(m_aliases.count(key.toLower())>0)
920         return m_aliases.find(key).value();
921     return "";
922 }
923 
getAliases()924 QMap<QString,QString> dxutils::getAliases()
925 {
926     return m_aliases;
927 }
928 
fillCommands()929 void dxutils::fillCommands()
930 {
931     m_commands.clear();
932     m_dcccommands.clear();
933     m_commands.append("ADMIN");
934     m_commands.append("AWAY");
935     m_commands.append("BANLIST");
936     m_commands.append("BOATS");
937     m_commands.append("CONNECT");
938     m_commands.append("COMMANDS");
939     m_dcccommands.append("COMMANDS");
940     m_commands.append("CTCP");
941     m_commands.append("CYCLE");
942     m_commands.append("DCC");
943     m_commands.append("DEOP");
944     m_commands.append("DEVOICE");
945     m_commands.append("DISCONNECT");
946     m_commands.append("EXEC");
947     m_dcccommands.append("EXEC");
948     m_commands.append("HELP");
949     m_dcccommands.append("HELP");
950     m_commands.append("IGNORE");
951     m_commands.append("INVITE");
952     m_commands.append("JOIN");
953     m_commands.append("KICK");
954     m_commands.append("KILL");
955     m_commands.append("LIST");
956     m_commands.append("LOG");
957     m_dcccommands.append("LOG");
958 #ifdef HAVE_LUA
959     m_commands.append("LUA");
960     m_dcccommands.append("LUA");
961 #endif
962     m_commands.append("ME");
963     m_dcccommands.append("ME");
964     m_commands.append("MODE");
965     m_commands.append("MSG");
966     m_commands.append("NAMES");
967     m_commands.append("NICK");
968     m_commands.append("NOTICE");
969     m_commands.append("OP");
970     m_commands.append("OPER");
971     m_commands.append("PART");
972     m_commands.append("QUERY");
973     m_commands.append("QUIT");
974     m_commands.append("QUOTE");
975     m_commands.append("SAY");
976     m_dcccommands.append("SAY");
977     m_commands.append("STATS");
978     m_commands.append("TIME");
979     m_commands.append("TOPIC");
980     m_commands.append("VOICE");
981     m_commands.append("WALLOPS");
982     m_commands.append("WHO");
983     m_commands.append("WHOAMI");
984     m_commands.append("WHOIS");
985     m_commands.append("WHOWAS");
986     QMap<QString,QString>::iterator it;
987     for(it=m_aliases.begin(); it!=m_aliases.end(); it++)
988     {
989         m_commands.append(it.key().section('/',1));
990     }
991     for(int i=0; i<m_scriptCommands.size(); i++)
992     {
993         m_commands.append(m_scriptCommands[i].name);
994         m_dcccommands.append(m_scriptCommands[i].name);
995     }
996     std::sort(m_commands.begin(), m_commands.end(), caseInsensitiveLessThan);
997     std::sort(m_dcccommands.begin(), m_dcccommands.end(), caseInsensitiveLessThan);
998 }
999 
commandsNo()1000 int dxutils::commandsNo()
1001 {
1002     return m_commands.size();
1003 }
1004 
commandsAt(int i)1005 QString dxutils::commandsAt(int i)
1006 {
1007     return m_commands.at(i);
1008 }
1009 
isCommand(const QString & command)1010 bool dxutils::isCommand(const QString &command)
1011 {
1012     if(!m_commands.size()) return false;
1013     for(int i=0; i<m_commands.size(); i++)
1014     {
1015         if(QString::compare(command, m_commands.at(i)) == 0) return true;
1016     }
1017     return false;
1018 }
1019 
dcccommandsNo()1020 int dxutils::dcccommandsNo()
1021 {
1022     return m_dcccommands.size();
1023 }
1024 
dcccommandsAt(int i)1025 QString dxutils::dcccommandsAt(int i)
1026 {
1027     return m_dcccommands.at(i);
1028 }
1029 
isDccCommand(const QString & command)1030 bool dxutils::isDccCommand(const QString &command)
1031 {
1032     if(!m_dcccommands.size()) return false;
1033     for(int i=0; i<m_dcccommands.size(); i++)
1034     {
1035         if(QString::compare(command, m_dcccommands.at(i)) == 0) return true;
1036     }
1037     return false;
1038 }
1039 
addScriptCommand(LuaScriptCommand command)1040 void dxutils::addScriptCommand(LuaScriptCommand command)
1041 {
1042     m_scriptCommands.append(command);
1043     fillCommands();
1044 }
1045 
1046 //Remove one command for lua script
removeScriptCommand(const QString & command)1047 bool dxutils::removeScriptCommand(const QString &command)
1048 {
1049     for(int i=m_scriptCommands.size()-1; i>-1; i--)
1050     {
1051         if(QString::compare(command, m_scriptCommands[i].name) == 0)
1052         {
1053             m_scriptCommands.removeAt(i);
1054             fillCommands();
1055             return true;
1056         }
1057     }
1058     return false;
1059 }
1060 
1061 //Remove all commands for lua script
removeScriptCommands(const QString & script)1062 bool dxutils::removeScriptCommands(const QString& script)
1063 {
1064     bool result = false;
1065     for(int i=m_scriptCommands.size()-1; i>-1; i--)
1066     {
1067         if(QString::compare(script, m_scriptCommands[i].script) == 0)
1068         {
1069             m_scriptCommands.removeAt(i);
1070             result = true;
1071         }
1072     }
1073     fillCommands();
1074     return result;
1075 }
1076 
isScriptCommand(const QString & command)1077 bool dxutils::isScriptCommand(const QString &command)
1078 {
1079     for(int i=0; i<m_scriptCommands.size(); i++)
1080     {
1081         if(QString::compare(command, m_scriptCommands[i].name) == 0) return true;
1082     }
1083     return false;
1084 }
1085 
availableCommands()1086 QString dxutils::availableCommands()
1087 {
1088     QString commandstr = _("Available commands: ");
1089     for(int i=0; i < m_commands.size(); i++)
1090     {
1091         if(m_commands[i] != "commands") commandstr += m_commands[i].toUpper()+(i != m_commands.size() - 1? ", " : "");
1092     }
1093     return commandstr;
1094 }
1095 
availableDccCommands()1096 QString dxutils::availableDccCommands()
1097 {
1098     QString commandstr = _("Available commands: ");
1099     for(int i=0; i < m_dcccommands.size(); i++)
1100     {
1101         if(m_dcccommands[i] != "commands") commandstr += m_dcccommands[i].toUpper()+(i != m_dcccommands.size() - 1? ", " : "");
1102     }
1103     return commandstr;
1104 }
1105 
availableScriptsCommands()1106 QString dxutils::availableScriptsCommands()
1107 {
1108     QString commandstr = _("Available commands: ");
1109     for(int i=0; i < m_scriptCommands.size(); i++)
1110     {
1111         commandstr += m_scriptCommands[i].name.toUpper()+(i != m_scriptCommands.size() - 1? ", " : "");
1112     }
1113     return commandstr;
1114 }
1115 
availableScriptCommands(const QString & script)1116 QString dxutils::availableScriptCommands(const QString& script)
1117 {
1118     bool result = false;
1119     QString commandstr = _("Script commands: ");
1120     for(int i=m_scriptCommands.size()-1; i>-1; i--)
1121     {
1122         if(QString::compare(script, m_scriptCommands[i].script) == 0)
1123         {
1124             if(result) commandstr += ", ";
1125             commandstr += m_scriptCommands[i].name.toUpper();
1126             result = true;
1127         }
1128     }
1129     if(result) return commandstr;
1130     else return _("Script hasn't commands");
1131 }
1132 
getHelpText(const QString & command)1133 QString dxutils::getHelpText(const QString &command)
1134 {
1135     for(int i=0; i<m_scriptCommands.size(); i++)
1136     {
1137         if(QString::compare(command, m_scriptCommands[i].name) == 0) return m_scriptCommands[i].helptext;
1138     }
1139     return _("Command %1 doesn't exists").arg(command);
1140 }
1141 
getFuncname(const QString & command)1142 QString dxutils::getFuncname(const QString &command)
1143 {
1144     for(int i=0; i<m_scriptCommands.size(); i++)
1145     {
1146         if(QString::compare(command, m_scriptCommands[i].name) == 0) return m_scriptCommands[i].funcname;
1147     }
1148     return _("Command %1 doesn't exists").arg(command);
1149 }
1150 
getScriptName(const QString & command)1151 QString dxutils::getScriptName(const QString &command)
1152 {
1153     for(int i=0; i<m_scriptCommands.size(); i++)
1154     {
1155         if(QString::compare(command, m_scriptCommands[i].name) == 0) return m_scriptCommands[i].script;
1156     }
1157     return _("Command %1 doesn't exists").arg(command);
1158 }
1159 
getStringIniEntry(const QString & section,const QString & key,const QString & def)1160 QString dxutils::getStringIniEntry(const QString &section, const QString &key, const QString &def)
1161 {
1162     QSettings set(preferences.getIniFile(), QSettings::IniFormat);
1163     set.beginGroup(section);
1164     return set.value(key, def).toString();
1165 }
1166 
getIntIniEntry(const QString & section,const QString & key,int def)1167 int dxutils::getIntIniEntry(const QString &section, const QString &key, int def)
1168 {
1169     QSettings set(preferences.getIniFile(), QSettings::IniFormat);
1170     set.beginGroup(section);
1171     return set.value(key, def).toInt();
1172 }
1173 
1174 //return bool entry in inifile
getBoolIniEntry(const QString & section,const QString & key,bool def)1175 bool dxutils::getBoolIniEntry(const QString &section, const QString &key, bool def)
1176 {
1177     QSettings set(preferences.getIniFile(), QSettings::IniFormat);
1178     set.beginGroup(section);
1179     return set.value(key, def).toBool();
1180 }
1181 
1182 // return color entry in inifile
getColorIniEntry(const QString & section,const QString & key,QColor def)1183 QColor dxutils::getColorIniEntry(const QString &section, const QString &key, QColor def)
1184 {
1185     QSettings set(preferences.getIniFile(), QSettings::IniFormat);
1186     set.beginGroup(section);
1187     return set.value(key, def).value<QColor>();
1188 }
1189 
1190 //true if word right
1191 #ifdef HAVE_ENCHANT
checkWord(QString word,QString lang)1192 bool dxutils::checkWord(QString word, QString lang)
1193 {
1194     Checkers::const_iterator it = m_checkers.find(lang);
1195     if(it != m_checkers.end())
1196         return (*it).second->check(toStdString(word));
1197     return true;
1198 }
1199 #else
1200 #ifdef Q_OS_DARWIN
checkWord(QString word,QString)1201 bool dxutils::checkWord(QString word, QString)
1202 {
1203     if(_instance) _instance = new MacSpellCheck;
1204     return _instance->checkWord(word);
1205 }
1206 #else
checkWord(QString,QString)1207 bool dxutils::checkWord(QString, QString)
1208 {
1209     return true;
1210 }
1211 #endif //Q_OS_DARWIN
1212 #endif //HAVE_ENCHANT
1213 
1214 //fill available langs
1215 #ifdef HAVE_ENCHANT
loadAvailableSpellLangs()1216 void dxutils::loadAvailableSpellLangs()
1217 {
1218     CheckerPair chpair(&m_checkers, &m_availableSpellLangs);
1219     ebroker->list_dicts(enumerateDicts, &chpair);
1220     if(m_availableSpellLangs.size())
1221     {
1222         m_availableSpellLangs.sort();
1223     }
1224     for(int i=0; i<m_availableSpellLangs.size(); i++)
1225     {
1226         if(m_checkers.find(m_availableSpellLangs[i]) != m_checkers.end())
1227             return;
1228         try
1229         {
1230             m_checkers[m_availableSpellLangs[i]] = ebroker->request_dict(toStdString(m_availableSpellLangs[i]));
1231         }
1232         catch(enchant::Exception &/*e*/)
1233         {
1234         }
1235     }
1236 }
1237 #else
loadAvailableSpellLangs()1238 void dxutils::loadAvailableSpellLangs()
1239 {
1240     m_availableSpellLangs.clear();
1241 }
1242 #endif
1243 
1244 //get number of spellchecking language
1245 #ifdef HAVE_ENCHANT
getAvailableSpellLangsNum()1246 int dxutils::getAvailableSpellLangsNum()
1247 {
1248     return m_availableSpellLangs.size();
1249 }
1250 #else
getAvailableSpellLangsNum()1251 int dxutils::getAvailableSpellLangsNum()
1252 {
1253     return 0;
1254 }
1255 #endif
1256 
1257 //return array of spellchecking language
getAvailableSpellLangs()1258 QStringList dxutils::getAvailableSpellLangs()
1259 {
1260     return m_availableSpellLangs;
1261 }
1262 
1263 //time stamp to human readable string
stamp2string(QString datestr,QString timestr)1264 QString dxutils::stamp2string(QString datestr, QString timestr)
1265 {
1266 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
1267     QString format = QLocale::system().dateTimeFormat(QLocale::ShortFormat);
1268 #else
1269     Qt::DateFormat format = Qt::SystemLocaleShortDate;
1270 #endif
1271     return QString("["+QDate(datestr.section('-',0,0).toInt(), datestr.section('-',1,1).toInt(), datestr.section('-',2).toInt()).toString(format)+" "+timestr+"]");
1272 }
1273 
1274 //normalize log line
normalizeLogLine(QString datestr,std::string line)1275 QString dxutils::normalizeLogLine(QString datestr, std::string line)
1276 {
1277     QString nline = fromStdString(line);
1278     QString date = stamp2string(datestr, nline.section(']',0,0).section('[',1));
1279     nline = date+nline.section(']',1);
1280     return nline;
1281 }
1282 
1283 //Remove ircmark from text
stripColors(const QString & text,const bool stripOther)1284 QString dxutils::stripColors(const QString &text, const bool stripOther)
1285 {
1286     QString newstr;
1287     bool color = false;
1288     int numbers = 0;
1289     for(int i=0; i < text.length(); i++) {
1290         if(text[i] == '\017') //reset
1291         {
1292             color = false;
1293         }
1294         else if(stripOther && text[i] == '\002')
1295         {
1296             //remove bold mark
1297         }
1298         else if(stripOther && text[i] == '\037')
1299         {
1300             //remove underline mark
1301         }
1302         else if(text[i] == '\035')
1303         {
1304             //remove italic mark
1305         }
1306         else if(text[i] == '\021')
1307         {
1308             //remove fixed mark
1309         }
1310         else if(text[i] == '\026')
1311         {
1312             //remove reverse mark
1313         }
1314         else if(text[i] == '\003') //color
1315         {
1316             color = true;
1317         }
1318         else if(text[i] == '\004') //hex color
1319         {
1320             color = true;
1321         }
1322         else if(color && isdigit(text[i].toLatin1()) && numbers < 2)
1323         {
1324             numbers++;
1325         }
1326         else if(color && text[i] == ',' && numbers < 3)
1327         {
1328             numbers = 0;
1329         }
1330         else
1331         {
1332             numbers = 0;
1333             color = false;
1334             newstr += text[i];
1335         }
1336     }
1337     return newstr;
1338 }
1339 
1340 //Return color for ircolor code
getIrcColor(int code,bool foreground)1341 QColor dxutils::getIrcColor(int code, bool foreground)
1342 {
1343     switch(code){
1344         case 0:
1345             return QColor("white");
1346         case 1:
1347             return QColor("black");
1348         case 2:
1349             return QColor(0,0,128); //blue
1350         case 3:
1351             return QColor(0,128,0); //green
1352         case 4:
1353             return QColor(255,0,0); //lightred
1354         case 5:
1355             return QColor(128,0,64); //brown
1356         case 6:
1357             return QColor(128,0,128); //purple
1358         case 7:
1359             return QColor(255,128,64); //orange
1360         case 8:
1361             return QColor(255,255,0); //yellow
1362         case 9:
1363             return QColor(128,255,0); //lightgreen
1364         case 10:
1365             return QColor(0,128,128); //cyan
1366         case 11:
1367             return QColor(0,255,255); //lightcyan
1368         case 12:
1369             return QColor(0,0,255); //lightblue
1370         case 13:
1371             return QColor(255,0,255); //pink
1372         case 14:
1373             return QColor(128,128,128); //grey
1374         case 15:
1375             return QColor(192,192,192); //lightgrey
1376         case 16:
1377             return QColor("#470000");
1378         case 17:
1379             return QColor("#472100");
1380         case 18:
1381             return QColor("#474700");
1382         case 19:
1383             return QColor("#324700");
1384         case 20:
1385             return QColor("#004700");
1386         case 21:
1387             return QColor("#00472c");
1388         case 22:
1389             return QColor("#004747");
1390         case 23:
1391             return QColor("#002747");
1392         case 24:
1393             return QColor("#000047");
1394         case 25:
1395             return QColor("#2e0047");
1396         case 26:
1397             return QColor("#470047");
1398         case 27:
1399             return QColor("#47002a");
1400         case 28:
1401             return QColor("#740000");
1402         case 29:
1403             return QColor("#743a00");
1404         case 30:
1405             return QColor("#747400");
1406         case 31:
1407             return QColor("#517400");
1408         case 32:
1409             return QColor("#007400");
1410         case 33:
1411             return QColor("#007449");
1412         case 34:
1413             return QColor("#007474");
1414         case 35:
1415             return QColor("#004074");
1416         case 36:
1417             return QColor("#000074");
1418         case 37:
1419             return QColor("#4b0074");
1420         case 38:
1421             return QColor("#740074");
1422         case 39:
1423             return QColor("#740045");
1424         case 40:
1425             return QColor("#b50000");
1426         case 41:
1427             return QColor("#b56300");
1428         case 42:
1429             return QColor("#b5b500");
1430         case 43:
1431             return QColor("#7db500");
1432         case 44:
1433             return QColor("#00b500");
1434         case 45:
1435             return QColor("#00b571");
1436         case 46:
1437             return QColor("#00b5b5");
1438         case 47:
1439             return QColor("#0063b5");
1440         case 48:
1441             return QColor("#0000b5");
1442         case 49:
1443             return QColor("#7500b5");
1444         case 50:
1445             return QColor("#b500b5");
1446         case 51:
1447             return QColor("#b5006b");
1448         case 52:
1449             return QColor("#ff0000");
1450         case 53:
1451             return QColor("#ff8c00");
1452         case 54:
1453             return QColor("#ffff00");
1454         case 55:
1455             return QColor("#b2ff00");
1456         case 56:
1457             return QColor("#00ff00");
1458         case 57:
1459             return QColor("#00ffa0");
1460         case 58:
1461             return QColor("#00ffff");
1462         case 59:
1463             return QColor("#008cff");
1464         case 60:
1465             return QColor("#0000ff");
1466         case 61:
1467             return QColor("#a500ff");
1468         case 62:
1469             return QColor("#ff00ff");
1470         case 63:
1471             return QColor("#ff0098");
1472         case 64:
1473             return QColor("#ff5959");
1474         case 65:
1475             return QColor("#ffb459");
1476         case 66:
1477             return QColor("#ffff71");
1478         case 67:
1479             return QColor("#cfff60");
1480         case 68:
1481             return QColor("#6fff6f");
1482         case 69:
1483             return QColor("#65ffc9");
1484         case 70:
1485             return QColor("#6dffff");
1486         case 71:
1487             return QColor("#59b4ff");
1488         case 72:
1489             return QColor("#5959ff");
1490         case 73:
1491             return QColor("#c459ff");
1492         case 74:
1493             return QColor("#ff66ff");
1494         case 75:
1495             return QColor("#ff59bc");
1496         case 76:
1497             return QColor("#ff9c9c");
1498         case 77:
1499             return QColor("#ffd39c");
1500         case 78:
1501             return QColor("#ffff9c");
1502         case 79:
1503             return QColor("#e2ff9c");
1504         case 80:
1505             return QColor("#9cff9c");
1506         case 81:
1507             return QColor("#9cffdb");
1508         case 82:
1509             return QColor("#9cffff");
1510         case 83:
1511             return QColor("#9cd3ff");
1512         case 84:
1513             return QColor("#9c9cff");
1514         case 85:
1515             return QColor("#dc9cff");
1516         case 86:
1517             return QColor("#ff9cff");
1518         case 87:
1519             return QColor("#ff94d3");
1520         case 88:
1521             return QColor("#000000");
1522         case 89:
1523             return QColor("#131313");
1524         case 90:
1525             return QColor("#282828");
1526         case 91:
1527             return QColor("#363636");
1528         case 92:
1529             return QColor("#4d4d4d");
1530         case 93:
1531             return QColor("#656565");
1532         case 94:
1533             return QColor("#818181");
1534         case 95:
1535             return QColor("#9f9f9f");
1536         case 96:
1537             return QColor("#bcbcbc");
1538         case 97:
1539             return QColor("#e2e2e2");
1540         case 98:
1541             return QColor("#ffffff");
1542         default:
1543             return foreground?preferences.m_colors.text:preferences.m_colors.back;
1544     }
1545 }
1546 
1547 //Remove ircmark from text
stripLogMark(const QString & text)1548 QString dxutils::stripLogMark(const QString &text)
1549 {
1550     QString newstr;
1551     bool mark = false;
1552     int numbers = 0;
1553     int i = 0;
1554     while(text[i] != '\0') {
1555         if(text[i] == '\014') //log mark
1556         {
1557             if(!mark) mark = true; //first mark
1558             else mark = false; //last mark
1559         }
1560         else if(mark && isdigit(text[i].toLatin1()) && numbers < 2)
1561         {
1562             numbers++;
1563         }
1564         else
1565         {
1566             numbers = 0;
1567             mark = false;
1568             newstr += text[i];
1569         }
1570         i++;
1571     }
1572     return newstr;
1573 }
1574 
getColorForStyle(int style)1575 QColor dxutils::getColorForStyle(int style)
1576 {
1577     switch (style) {
1578         //gray text - user commands
1579         case 1: return preferences.m_colors.user;
1580         //orange text - Actions
1581         case 2: return preferences.m_colors.action;
1582         //blue text - Notice
1583         case 3: return preferences.m_colors.notice;
1584         //red text - Errors
1585         case 4: return preferences.m_colors.error;
1586         //highlight text
1587         case 8: return preferences.m_colors.hilight;
1588         //mymsg style
1589         case 10: return preferences.m_colors.mymsg;
1590         //log line style
1591         case 11: return preferences.m_colors.log;
1592         default: return preferences.m_colors.text;
1593     }
1594 }
1595 
1596 //get spellchecking language for channel
1597 #ifdef HAVE_ENCHANT
getChannelLang(const QString & channel)1598 QString dxutils::getChannelLang(const QString &channel)
1599 {
1600     if(channel.isEmpty()) return getDefaultLang();
1601     QMap<QString,QString>::iterator it = preferences.m_langs.find(channel);
1602     QString lang = "";
1603     if(it != preferences.m_langs.end())
1604         lang = it.value();
1605     if(m_checkers.find(lang) != m_checkers.end())
1606         return lang;
1607     else return getDefaultLang();
1608 }
1609 #else
getChannelLang(const QString &)1610 QString dxutils::getChannelLang(const QString&)
1611 {
1612     return "";
1613 }
1614 #endif
1615 
createLinks(const QString & txt,bool removeThan)1616 QString dxutils::createLinks(const QString &txt, bool removeThan)
1617 {
1618     QString line = "";
1619     int i = 0;
1620     int linkLength = 0;
1621     int length = txt.length();
1622     while(i<length)
1623     {
1624         if(txt[i]=='<' && removeThan)
1625         {
1626             line.append("&lt;");
1627         }
1628         else if(txt[i]=='>' && removeThan)
1629         {
1630             line.append("&gt;");
1631         }
1632         else if(txt[i]=='h' && !QString::compare(txt.mid(i,7),"http://",Qt::CaseInsensitive))
1633         {
1634             for(int j=i; j<length; j++)
1635             {
1636                 if(isBadchar(txt[j].toLatin1()))
1637                 {
1638                     break;
1639                 }
1640                 linkLength++;
1641             }
1642             if(linkLength>7)
1643                 line.append(QString("<a href=\"%1\">%1</a>").arg(txt.mid(i, linkLength)));
1644             else
1645                 line.append(txt.mid(i, linkLength));
1646             i+=linkLength-1;
1647             linkLength=0;
1648         }
1649         else if(txt[i]=='h' && !QString::compare(txt.mid(i,8),"https://",Qt::CaseInsensitive))
1650         {
1651             for(int j=i; j<length; j++)
1652             {
1653                 if(isBadchar(txt[j].toLatin1()))
1654                 {
1655                     break;
1656                 }
1657                 linkLength++;
1658             }
1659             if(linkLength>8)
1660                 line.append(QString("<a href=\"%1\">%1</a>").arg(txt.mid(i, linkLength)));
1661             else
1662                 line.append(txt.mid(i, linkLength));
1663             i+=linkLength-1;
1664             linkLength=0;
1665         }
1666         else if(txt[i]=='f' && !QString::compare(txt.mid(i,6),"ftp://",Qt::CaseInsensitive))
1667         {
1668             for(int j=i; j<length; j++)
1669             {
1670                 if(isBadchar(txt[j].toLatin1()))
1671                 {
1672                     break;
1673                 }
1674                 linkLength++;
1675             }
1676             if(linkLength>6)
1677                 line.append(QString("<a href=\"%1\">%1</a>").arg(txt.mid(i, linkLength)));
1678             else
1679                 line.append(txt.mid(i, linkLength));
1680             i+=linkLength-1;
1681             linkLength=0;
1682         }
1683         else if(txt[i]=='w' && !QString::compare(txt.mid(i,4),"www.",Qt::CaseInsensitive))
1684         {
1685             for(int j=i; j<length; j++)
1686             {
1687                 if(isBadchar(txt[j].toLatin1()))
1688                 {
1689                     break;
1690                 }
1691                 linkLength++;
1692             }
1693             if(linkLength>4)
1694                 line.append(QString("<a href=\"%1\">%1</a>").arg(txt.mid(i, linkLength)));
1695             else
1696                 line.append(txt.mid(i, linkLength));
1697             i+=linkLength-1;
1698             linkLength=0;
1699         }
1700         else
1701         {
1702             line.append(txt[i]);
1703         }
1704         i++;
1705     }
1706     return line;
1707 }
1708 
closeTags(QList<QString> tags)1709 static QString closeTags(QList<QString> tags)
1710 {
1711     QString result;
1712     for(int i=tags.size()-1; i>-1; i--)
1713     {
1714         result.append("</");
1715         if(tags[i].contains(' ')) result.append(tags[i].section('<',1).section(' ',0,0));
1716         else result.append(tags[i].section('<',1).section('>',0,0));
1717         result.append('>');
1718     }
1719     return result;
1720 }
1721 
openTags(bool color,QColor foreColor,bool bgcolor,QColor backColor,bool bold,bool under,bool italic)1722 static QList<QString> openTags(bool color, QColor foreColor, bool bgcolor, QColor backColor, bool bold, bool under, bool italic)
1723 {
1724     QList<QString> result;
1725     if(color) result.append(QString("<font color=\"%1\">").arg(foreColor.name()));
1726     if(bgcolor) result.append(QString("<span style=\"background-color:%1\">").arg(backColor.name()));
1727     if(bold) result.append("<b>");
1728     if(under) result.append("<u>");
1729     if(italic) result.append("<i>");
1730     return result;
1731 }
1732 
1733 //removeThan is remove < and >
parseText(const QString & txt,int stylenum,bool removeThan)1734 QString dxutils::parseText(const QString &txt, int stylenum, bool removeThan)
1735 {
1736     const QString linked = createLinks(txt, removeThan);
1737     QString line = "";
1738     if(stylenum == 5) //bold text
1739     {
1740         line.prepend("<b>");
1741     }
1742     if(stylenum == 6) //underline style
1743     {
1744         line.prepend("<u>");
1745     }
1746     if(stylenum == 7) //bold & underline
1747     {
1748         line.prepend("<b><u>");
1749     }
1750     int i = 0;
1751     bool bold = false;
1752     bool under = false;
1753     bool italic = false;
1754     bool color = false;
1755     bool bgcolor = false;
1756     int length = linked.length();
1757     QList<QString> tags;
1758     QColor foreColor = dxutils::getColorForStyle(stylenum);
1759     QColor backColor = preferences.m_colors.back;
1760     if(dxutils::getColorForStyle(stylenum)!=preferences.m_colors.text) line.prepend(QString("<font color=\"%1\">").arg(foreColor.name()));
1761     while(i<length)
1762     {
1763         if(linked[i] == '\002') //bold
1764         {
1765             if(!tags.empty())
1766             {
1767                 line.append(closeTags(tags));
1768             }
1769             bold = !bold;
1770             tags = openTags(color, foreColor, bgcolor, backColor, bold, under, italic);
1771             foreach(QString tag, tags)
1772                 line.append(tag);
1773         }
1774         else if(linked[i] == '\026') //reverse
1775         {
1776             if(!tags.empty())
1777             {
1778                 line.append(closeTags(tags));
1779             }
1780             bgcolor = true;
1781             color = true;
1782             QColor tempColor = foreColor;
1783             foreColor = backColor;
1784             backColor = tempColor;
1785             tags = openTags(color, foreColor, bgcolor, backColor, bold, under, italic);
1786             foreach(QString tag, tags)
1787                 line.append(tag);
1788         }
1789         else if(linked[i] == '\037') //underline
1790         {
1791             if(!tags.empty())
1792             {
1793                 line.append(closeTags(tags));
1794             }
1795             under = !under;
1796             tags = openTags(color, foreColor, bgcolor, backColor, bold, under, italic);
1797             foreach(QString tag, tags)
1798                 line.append(tag);
1799         }
1800         else if(linked[i] == '\021') //fixed
1801         {
1802             dxutils::debugLine("Poslan fixed styl");
1803         }
1804         else if(linked[i] == '\035') //italic
1805         {
1806             if(!tags.empty())
1807             {
1808                 line.append(closeTags(tags));
1809             }
1810             italic = !italic;
1811             tags = openTags(color, foreColor, bgcolor, backColor, bold, under, italic);
1812             foreach(QString tag, tags)
1813                 line.append(tag);
1814         }
1815         else if(linked[i] == '\003') //color
1816         {
1817             if(!tags.empty())
1818             {
1819                 line.append(closeTags(tags));
1820             }
1821             int colorLength = 0;
1822             foreColor = preferences.m_colors.text;
1823             backColor = preferences.m_colors.back;
1824             bool isHexColor = false;
1825             if(i+1<length)
1826             {
1827                 if(linked[i+1] == '#') isHexColor = true;
1828             }
1829             if(isHexColor)
1830             {
1831                 if(QRegularExpression("[0-9a-fA-F]{6}").match(linked.mid(i+2,6)).hasMatch())
1832                 {
1833                     color = true;
1834                     foreColor = QColor(linked.mid(i+1,7));
1835                     colorLength +=7;
1836                 }
1837                 if(i+8 < length && linked[i+8] == ',' && QRegularExpression("[0-9a-fA-F]{6}").match(linked.mid(i+10,6)).hasMatch())
1838                 {
1839                     bgcolor = true;
1840                     backColor = QColor(linked.mid(i+9,7));
1841                     colorLength +=8;
1842                 }
1843             }
1844             else
1845             {
1846                 if(i+2<length)
1847                 {
1848                     int code = -1;
1849                     if(isdigit(linked[i+1].toLatin1()))
1850                     {
1851                         if(isdigit(linked[i+2].toLatin1()))
1852                         {
1853                             code = (linked[i+1].toLatin1()-48)*10+linked[i+2].toLatin1()-48;
1854                             colorLength +=2;
1855                         }
1856                         else
1857                         {
1858                             code = linked[i+1].toLatin1()-48;
1859                             colorLength ++;
1860                         }
1861                     }
1862                     if(code!=-1)
1863                     {
1864                         color = true;
1865                         foreColor = dxutils::getIrcColor(code, true);
1866                     }
1867                 }
1868                 if(i+colorLength+1 < length && linked[i+colorLength+1] == ',')
1869                 {
1870                     int code = -1;
1871                     if(isdigit(linked[i+colorLength+2].toLatin1()))
1872                     {
1873                         if(isdigit(linked[i+colorLength+3].toLatin1()))
1874                         {
1875                             code = (linked[i+colorLength+2].toLatin1()-48)*10+linked[i+colorLength+3].toLatin1()-48;
1876                             colorLength +=3;
1877                         }
1878                         else
1879                         {
1880                             code = linked[i+colorLength+2].toLatin1()-48;
1881                             colorLength +=2;
1882                         }
1883                     }
1884                     if(code!=-1)
1885                     {
1886                         bgcolor = true;
1887                         backColor = dxutils::getIrcColor(code, false);
1888                     }
1889                 }
1890             }
1891             tags = openTags(color, foreColor, bgcolor, backColor, bold, under, italic);
1892             foreach(QString tag, tags)
1893                 line.append(tag);
1894             i +=colorLength;
1895         }
1896         else if(linked[i] == '\004') //hex color
1897         {
1898             if(!tags.empty())
1899             {
1900                 line.append(closeTags(tags));
1901             }
1902             int colorLength = 0;
1903             foreColor = preferences.m_colors.text;
1904             backColor = preferences.m_colors.back;
1905             if(QRegularExpression("[0-9a-fA-F]{6}").match(linked.mid(i+1,6)).hasMatch())
1906             {
1907                 color = true;
1908                 foreColor = QColor(QString("#")+linked.mid(i+1,6));
1909                 colorLength +=6;
1910             }
1911             if(i+7 < length && linked[i+7] == ',' && QRegularExpression("[0-9a-fA-F]{6}").match(linked.mid(i+8,6)).hasMatch())
1912             {
1913                 bgcolor = true;
1914                 backColor = QColor(QString("#")+linked.mid(i+8,6));
1915                 colorLength +=7;
1916             }
1917             tags = openTags(color, foreColor, bgcolor, backColor, bold, under, italic);
1918             foreach(QString tag, tags)
1919                 line.append(tag);
1920             i +=colorLength;
1921         }
1922         else if(linked[i] == '\017') //reset
1923         {
1924             if(!tags.empty())
1925             {
1926                 line.append(closeTags(tags));
1927             }
1928             bold = false;
1929             under = false;
1930             italic = false;
1931             bgcolor = false;
1932             color = false;
1933             foreColor = preferences.m_colors.text;
1934             backColor = preferences.m_colors.back;
1935         }
1936         else
1937         {
1938             line.append(linked[i]);
1939         }
1940         i++;
1941     }
1942     if(!tags.empty())
1943     {
1944         line.append(closeTags(tags));
1945     }
1946     if(stylenum == 5) //bold text
1947     {
1948         line.append("</b>");
1949     }
1950     if(stylenum == 6) //underline style
1951     {
1952         line.append("</u>");
1953     }
1954     if(stylenum == 7) //bold & underline
1955     {
1956         line.append("</u></b>");
1957     }
1958     if(dxutils::getColorForStyle(stylenum)!=preferences.m_colors.text) line.append("</font>");
1959     if(preferences.m_useSmileys) return createSmileys(line);
1960     return line;
1961 }
1962 
1963 //logstyle = true for IrcTabItem::loadLogLines()
parseLogline(const QString & line,bool logstyle)1964 QString dxutils::parseLogline(const QString& line, bool logstyle)
1965 {
1966     if(line.section(']',1)[1].toLatin1()=='\014') //log style mark
1967     {
1968         int style = logstyle?11:line.section('\014',1).section('\014',0,0).toInt();
1969         QString time = line.section('\014',0,0);
1970         if(line.section('\014',2)[0].toLatin1()=='<') //has nick
1971         {
1972             QString nick = line.section('<',1).section('>',0,0);
1973             QString msg = line.section('>',1);
1974             if(logstyle)
1975             {
1976                 QString nickStyled = "";
1977                 if(preferences.m_coloredNick) nickStyled = QString("<font color=\"%1\">%2: </font>").arg(getNickColor(nick)).arg(nick);
1978                 else nickStyled = QString("<b>%1: </b>").arg(nick);
1979                 return parseText(time+nickStyled+msg, style, false);
1980             }
1981             else
1982             {
1983                 return time+parseText(nick+":"+msg, style);
1984             }
1985         }
1986         else
1987         {
1988             if(logstyle) return parseText(time+line.section('\014',2), style, false);
1989             else return time+parseText(line.section('\014',2), style);
1990         }
1991     }
1992     else
1993     {
1994         if(line.section(']',1)[1].toLatin1()=='<') //line with nick
1995         {
1996             QString time = line.section('<',0,0);
1997             QString nick = line.section('<',1).section('>',0,0);
1998             QString nickStyled = "";
1999             if(preferences.m_coloredNick) nickStyled = QString("<font color=\"%1\">%2: </font>").arg(getNickColor(nick)).arg(nick);
2000             else nickStyled = QString("<b>%1: </b>").arg(nick);
2001             QString msg = line.section('>',1).trimmed();
2002             if(logstyle) return parseText(time+nickStyled+msg, 11, false);
2003             else return time+nickStyled+parseText(msg, 0);
2004         }
2005         else
2006         {
2007             if(logstyle) return parseText(line, 11, false);
2008             else return parseText(line, 0);
2009         }
2010     }
2011 }
2012 
2013 //Get away color
makeAwayColor(QColor clr)2014 QColor dxutils::makeAwayColor(QColor clr)
2015 {
2016     int r,g,b;
2017     r=clr.red();
2018     g=clr.green();
2019     b=clr.blue();
2020     if(r==g && r==b && !r)
2021     {
2022         r=255;
2023         g=255;
2024         b=255;
2025     }
2026     r=(50*r)/100;
2027     g=(50*g)/100;
2028     b=(50*b)/100;
2029     return QColor(r,g,b);
2030 }
2031 
2032 //UserMode to QIcon
modeToIcon(UserMode mode)2033 QString dxutils::modeToIcon(UserMode mode)
2034 {
2035     switch(mode) {
2036     case OWNER:
2037     {
2038         return preferences.m_themePath+"/irc_owner.png";
2039     }
2040     case ADMIN:
2041     {
2042         return preferences.m_themePath+"/irc_admin.png";
2043     }
2044     case OP:
2045     {
2046         return preferences.m_themePath+"/irc_op.png";
2047     }
2048     case VOICE:
2049     {
2050         return preferences.m_themePath+"/irc_voice.png";
2051     }
2052     case HALFOP:
2053     {
2054         return preferences.m_themePath+"/irc_halfop.png";
2055     }
2056     default:
2057     {
2058         return preferences.m_themePath+"/irc_normal.png";
2059     }
2060     }
2061 }
2062 
getUsername()2063 QString dxutils::getUsername()
2064 {
2065 #ifdef Q_OS_WIN
2066     return QProcessEnvironment::systemEnvironment().value("USERNAME");
2067 #else
2068     return QProcessEnvironment::systemEnvironment().value("USER");
2069 #endif
2070 }
2071 
getIconForType(TYPE type)2072 QString dxutils::getIconForType(TYPE type)
2073 {
2074     switch(type){
2075         case SERVER: return getDataPath()+"/icons/world.png";
2076         case CHANNEL: return getDataPath()+"/icons/channel.png";
2077         case QUERY: return getDataPath()+"/icons/user.png";
2078         case OTHER: return getDataPath()+"/icons/logs.png";
2079         case DCC: return getDataPath()+"/icons/dcc.png";
2080         case BOATS: return "";
2081         default: return "";
2082     }
2083 }
2084 
removeDir(const QString & dirName)2085 bool dxutils::removeDir(const QString &dirName)
2086 {
2087     bool result = true;
2088     QDir dir(dirName);
2089     if(dir.exists(dirName))
2090     {
2091         Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden  | QDir::AllDirs | QDir::Files, QDir::DirsFirst))
2092         {
2093             if(info.isDir())
2094             {
2095                 result = removeDir(info.absoluteFilePath());
2096             }
2097             else
2098             {
2099                 result = QFile::remove(info.absoluteFilePath());
2100             }
2101             if(!result)
2102             {
2103                 return result;
2104             }
2105         }
2106         result = dir.rmdir(dirName);
2107     }
2108     return result;
2109 }
2110 
getLocalePath()2111 QString dxutils::getLocalePath()
2112 {
2113 #if defined(Q_OS_WIN)
2114     QString path = QApplication::applicationFilePath();
2115     int ii = path.lastIndexOf('/');
2116     if(ii > 0)
2117         path.remove(ii, path.length());
2118     return path.append("/locale");
2119 #elif defined(Q_OS_DARWIN)
2120 #ifdef ENABLE_OSX_BUNDLE
2121     QString path = QApplication::applicationFilePath();
2122     int ii = path.lastIndexOf('/');
2123     if(ii > 0)
2124         path.remove(ii, path.length());
2125     return path.append("/locale");
2126 #else
2127     return QString(LOCALEDIR);
2128 #endif
2129 #else
2130     return QString(LOCALEDIR);
2131 #endif
2132 }
2133 
getDataPath()2134 QString dxutils::getDataPath()
2135 {
2136 #if defined(Q_OS_WIN)
2137     QString path = QApplication::applicationFilePath();
2138     int ii = path.lastIndexOf('/');
2139     if(ii > 0)
2140         path.remove(ii, path.length());
2141     return path;
2142 #elif defined(Q_OS_DARWIN)
2143 #ifdef ENABLE_OSX_BUNDLE
2144     QString path = QApplication::applicationFilePath();
2145     int ii = path.lastIndexOf('/');
2146     if(ii > 0)
2147         path.remove(ii, path.length());
2148     return path.append("/../Resources");
2149 #else
2150     return QString(DXIRC_DATADIR);
2151 #endif
2152 #else
2153     return QString(DXIRC_DATADIR);
2154 #endif
2155 }
2156 
getKeybinding(QKeyEvent * e)2157 QKeySequence dxutils::getKeybinding(QKeyEvent *e)
2158 {
2159     int keyInt = e->key();
2160     Qt::Key key = static_cast<Qt::Key>(keyInt);
2161     if(key == Qt::Key_unknown)
2162     {
2163         return QKeySequence(Qt::Key_unknown);
2164     }
2165     // the user have clicked just and only the special keys Ctrl, Shift, Alt, Meta.
2166     if(key == Qt::Key_Control ||
2167         key == Qt::Key_Shift ||
2168         key == Qt::Key_Alt ||
2169         key == Qt::Key_Meta)
2170     {
2171         return QKeySequence(keyInt);
2172     }
2173     // check for a combination of user clicks
2174     Qt::KeyboardModifiers modifiers = e->modifiers();
2175     if(modifiers & Qt::ShiftModifier)
2176         keyInt += Qt::SHIFT;
2177     if(modifiers & Qt::ControlModifier)
2178         keyInt += Qt::CTRL;
2179     if(modifiers & Qt::AltModifier)
2180         keyInt += Qt::ALT;
2181     if(modifiers & Qt::MetaModifier)
2182         keyInt += Qt::META;
2183     return QKeySequence(keyInt);
2184 }
2185 
wrapText(QString text,int width,char wrap)2186 QString dxutils::wrapText(QString text, int width, char wrap)
2187 {
2188     QFontMetrics fnt(preferences.m_ircFont);
2189     int tw = 0;
2190     int cw;
2191     int s = -1;
2192     for(int i=0; i<text.length(); i++)
2193     {
2194 #if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))
2195         cw = fnt.width(text[i]);
2196 #else
2197         cw = fnt.horizontalAdvance(text[i]);
2198 #endif
2199         if(text[i]==wrap) s = i;
2200         if(tw+cw>width)
2201         {
2202             if(s!=-1)
2203             {
2204                 text.replace(s,1,'\n');
2205                 i=s+1;
2206                 s=-1;
2207             }
2208             tw=0;
2209         }
2210         tw+=cw;
2211     }
2212     return text;
2213 }
2214 
enquote(const QString & string)2215 QString dxutils::enquote(const QString &string)
2216 {
2217     QString s = string;
2218     return QString("\"%1\"").arg(s.replace(QLatin1Char('\\'),QLatin1String("\\\\"))).replace(QLatin1Char('"'),QLatin1String("\\\""));
2219 }
2220 
2221 
2222