~ubuntu-branches/ubuntu/breezy/psi/breezy

« back to all changes in this revision

Viewing changes to src/common.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2004-06-15 00:10:41 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040615001041-enywb6pcpe4sjsw6
Tags: 0.9.2-1
* New upstream release
* Set KDEDIR for ./configure so kde specific files get installed
* Don't install libpsiwidgets.so. It got installed in /usr/share
  where it doesn't belong. May be included (at a better location)
  later.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/****************************************************************************
2
 
** common.cpp - contains all the common variables and functions for Psi
3
 
** Copyright (C) 2001, 2002  Justin Karneges
4
 
**
5
 
** This program is free software; you can redistribute it and/or
6
 
** modify it under the terms of the GNU General Public License
7
 
** as published by the Free Software Foundation; either version 2
8
 
** of the License, or (at your option) any later version.
9
 
**
10
 
** This program is distributed in the hope that it will be useful,
11
 
** but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
** GNU General Public License for more details.
14
 
**
15
 
** You should have received a copy of the GNU General Public License
16
 
** along with this program; if not, write to the Free Software
17
 
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 
**
19
 
****************************************************************************/
 
1
/*
 
2
 * common.cpp - contains all the common variables and functions for Psi
 
3
 * Copyright (C) 2001-2003  Justin Karneges
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public License
 
7
 * as published by the Free Software Foundation; either version 2
 
8
 * of the License, or (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this library; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
 *
 
19
 */
20
20
 
21
21
#include"common.h"
 
22
 
22
23
#include"profiles.h"
 
24
#include"rtparse.h"
 
25
 
 
26
#include"psievent.h"
23
27
 
24
28
QString PROG_NAME = "Psi";
25
 
QString PROG_VERSION = "0.8.5";
 
29
QString PROG_VERSION = "0.9.2";
 
30
 
 
31
#ifdef HAVE_CONFIG
 
32
#include"config.h"
 
33
#endif
 
34
 
 
35
#ifndef LIBDIR
 
36
#define LIBDIR "/usr/local/share/psi"
 
37
#endif
26
38
 
27
39
#include<qregexp.h>
28
40
#include<qdir.h>
29
41
#include<qfile.h>
30
42
#include<qapplication.h>
 
43
#include<qsound.h>
 
44
#include<qobjectlist.h>
 
45
#include<qlibrary.h>
31
46
 
32
47
#include<stdio.h>
33
48
 
34
49
#ifdef Q_WS_X11
35
50
#include<sys/types.h>
36
51
#include<sys/stat.h>
 
52
#include<sys/wait.h>
37
53
#endif
38
54
 
39
55
#ifdef Q_WS_WIN
41
57
#endif
42
58
 
43
59
#ifdef Q_WS_MAC
 
60
#include<sys/types.h>
 
61
#include<sys/stat.h>
44
62
#include <Carbon/Carbon.h> // for HIToolbox/InternetConfig
45
63
#include <CoreServices/CoreServices.h>
46
64
#endif
47
65
 
 
66
#include <sys/wait.h>
 
67
 
48
68
QString activeProfile;
49
69
 
50
 
TransportIconSet tic[5];
51
 
 
52
 
QPixmap *pix_online,
53
 
        *pix_offline,
54
 
        *pix_away,
55
 
        *pix_xa,
56
 
        *pix_dnd,
57
 
        *pix_blank,
58
 
        *pix_arrow[3],
59
 
        *pix_add,
60
 
        *pix_remove,
61
 
        *pix_send,
62
 
        *pix_history,
63
 
        *pix_info,
64
 
        *pix_url,
65
 
        *pix_ssl_yes,
66
 
        *pix_ssl_no,
67
 
        *pix_logo,
68
 
        *pix_changeacc,
69
 
        *pix_main,
70
 
        *pix_bigIcon,
71
 
        *pix_chatsend1,
72
 
        *pix_chatsend2,
73
 
        *pix_chatclear,
74
 
        *pix_account,
75
 
        *pix_icon_48,
76
 
        *pix_ft_back,
77
 
        *pix_ft_file,
78
 
        *pix_ft_folder;
79
 
 
80
 
QImage  *qim_online,
81
 
        *qim_offline,
82
 
        *qim_away,
83
 
        *qim_xa,
84
 
        *qim_dnd;
 
70
QStringList dtcp_hostList;
 
71
int dtcp_port;
 
72
QString dtcp_proxy;
 
73
bool link_test = false;
 
74
bool use_gpg = true;
 
75
bool no_gpg_agent = false;
 
76
uint psi_dialog_flags = (Qt::WStyle_SysMenu | Qt::WStyle_MinMax);
 
77
//uint psi_dialog_flags = (Qt::WStyle_Customize | Qt::WStyle_DialogBorder | Qt::WStyle_Title | Qt::WStyle_SysMenu | Qt::WStyle_MinMax);
85
78
 
86
79
char *pixdat_ft_back, *pixdat_ft_file, *pixdat_ft_folder;
87
80
int pixlen_ft_back, pixlen_ft_file, pixlen_ft_folder;
88
81
 
89
 
Anim *anim_message, *anim_system, *anim_chat, *anim_headline;
90
82
 
91
 
LogWindow *debug_window = 0;
92
 
Jabber *debug_jabber = 0;
 
83
XMPP::Client *debug_jabber = 0;
93
84
Options option;
94
85
PsiGlobal g;
 
86
PsiIconset *is;
95
87
bool useSound;
96
88
 
97
89
 
145
137
        return QString("%1: %2").arg(PROG_NAME).arg(str);
146
138
}
147
139
 
148
 
void pdb(int depth, const QString &str)
149
 
{
150
 
        //fprintf(stderr, "%s", str.latin1());
151
 
 
152
 
        if(debug_window)
153
 
                debug_window->append(depth, str);
154
 
}
155
 
 
156
 
 
157
140
QString eatptag(QString txt)
158
141
{
159
142
        if(txt.left(3) == "<p>")
162
145
        return txt;
163
146
}
164
147
 
 
148
QString qstrquote(const QString &toquote, int width, bool quoteEmpty)
 
149
{
 
150
        int ql = 0, col = 0, atstart = 1, ls=0;
 
151
 
 
152
        QString quoted = "> "+toquote;  // quote first line
 
153
        QString rxs  = quoteEmpty ? "\n" : "\n(?!\\s*\n)";
 
154
        QRegExp rx(rxs);                // quote following lines
 
155
        quoted.replace(rx, "\n> ");
 
156
        rx.setPattern("> +>");          // compress > > > > quotes to >>>>
 
157
        quoted.replace(rx, ">>");
 
158
        quoted.replace(rx, ">>");
 
159
        quoted.replace(QRegExp(" +\n"), "\n");  // remove trailing spaces
 
160
 
 
161
        if (!quoteEmpty)
 
162
        {
 
163
                quoted.replace(QRegExp("^>+\n"), "\n\n");  // unquote empty lines
 
164
                quoted.replace(QRegExp("\n>+\n"), "\n\n");
 
165
        }
 
166
 
 
167
 
 
168
        for (int i=0;i<(int) quoted.length();i++)
 
169
        {
 
170
                col++;
 
171
                if (atstart && quoted[i] == '>') ql++; else atstart=0;
 
172
 
 
173
                switch(quoted[i].latin1())
 
174
                {
 
175
                        case '\n': ql = col = 0; atstart = 1; break;
 
176
                        case ' ':
 
177
                        case '\t': ls = i; break;
 
178
 
 
179
                }
 
180
                if (quoted[i]=='\n') { ql=0; atstart = 1; }
 
181
 
 
182
                if (col > width)
 
183
                {
 
184
                        if ((ls+width) < i)
 
185
                        {
 
186
                                ls = i; i = quoted.length();
 
187
                                while ((ls<i) && !quoted[ls].isSpace()) ls++;
 
188
                                i = ls;
 
189
                        }
 
190
                        if ((i<(int)quoted.length()) && (quoted[ls] != '\n'))
 
191
                        {
 
192
                                quoted.insert(ls, '\n');
 
193
                                ++ls;
 
194
                                quoted.insert(ls, QString().fill('>', ql));
 
195
                                i += ql+1;
 
196
                                col = 0;
 
197
                        }
 
198
                }
 
199
        }
 
200
        quoted += "\n\n";// add two empty lines to quoted text - the cursor
 
201
                        // will be positioned at the end of those.
 
202
        return quoted;
 
203
}
 
204
 
165
205
QString plain2rich(const QString &plain)
166
206
{
167
207
        QString rich;
169
209
 
170
210
        for(int i = 0; i < (int)plain.length(); ++i) {
171
211
                if(plain[i] == '\n') {
172
 
                        rich += "<br>\n";
 
212
                        rich += "<br>";
173
213
                        col = 0;
174
214
                }
175
215
                else if(plain[i] == '\t') {
203
243
        return rich;
204
244
}
205
245
 
 
246
QString rich2plain(const QString &in)
 
247
{
 
248
        QString out;
 
249
 
 
250
        for(int i = 0; i < (int)in.length(); ++i) {
 
251
                // tag?
 
252
                if(in[i] == '<') {
 
253
                        // find end of tag
 
254
                        ++i;
 
255
                        int n = in.find('>', i);
 
256
                        if(n == -1)
 
257
                                break;
 
258
                        QString str = in.mid(i, (n-i));
 
259
                        i = n;
 
260
 
 
261
                        QString tagName;
 
262
                        n = str.find(' ');
 
263
                        if(n != -1)
 
264
                                tagName = str.mid(0, n);
 
265
                        else
 
266
                                tagName = str;
 
267
 
 
268
                        if(tagName == "br")
 
269
                                out += '\n';
 
270
                }
 
271
                // entity?
 
272
                else if(in[i] == '&') {
 
273
                        // find a semicolon
 
274
                        ++i;
 
275
                        int n = in.find(';', i);
 
276
                        if(n == -1)
 
277
                                break;
 
278
                        QString type = in.mid(i, (n-i));
 
279
                        i = n; // should be n+1, but we'll let the loop increment do it
 
280
 
 
281
                        if(type == "amp")
 
282
                                out += '&';
 
283
                        else if(type == "lt")
 
284
                                out += '<';
 
285
                        else if(type == "gt")
 
286
                                out += '>';
 
287
                        else if(type == "quot")
 
288
                                out += '\"';
 
289
                        else if(type == "apos")
 
290
                                out += '\'';
 
291
                }
 
292
                else if(in[i].isSpace()) {
 
293
                        if(in[i] == QChar::nbsp)
 
294
                                out += ' ';
 
295
                        else if(in[i] != '\n') {
 
296
                                if(i == 0)
 
297
                                        out += ' ';
 
298
                                else {
 
299
                                        QChar last = out.at(out.length()-1);
 
300
                                        bool ok = TRUE;
 
301
                                        if(last.isSpace() && last != '\n')
 
302
                                                ok = FALSE;
 
303
                                        if(ok)
 
304
                                                out += ' ';
 
305
                                }
 
306
                        }
 
307
                }
 
308
                else {
 
309
                        out += in[i];
 
310
                }
 
311
        }
 
312
 
 
313
        return out;
 
314
}
 
315
 
 
316
 
206
317
// clips plain text
207
318
QString clipStatus(const QString &str, int width, int height)
208
319
{
216
327
        for(int n2 = 0; n2 < height; ++n2) {
217
328
                // only take the first "width" chars
218
329
                QString line;
219
 
                for(int n = 0; str.at(at) != '\n' && at < len; ++n, ++at)
 
330
                bool hasNewline = false;
 
331
                for(int n = 0; at < len; ++n, ++at) {
 
332
                        if(str.at(at) == '\n') {
 
333
                                hasNewline = true;
 
334
                                break;
 
335
                        }
220
336
                        line += str.at(at);
 
337
                }
221
338
                ++at;
222
339
                if((int)line.length() > width) {
223
340
                        line.truncate(width-3);
224
341
                        line += "...";
225
342
                }
226
 
                out += line + '\n';
 
343
                out += line;
 
344
                if(hasNewline)
 
345
                        out += '\n';
227
346
 
228
347
                if(at >= len)
229
348
                        break;
319
438
        QString out;
320
439
 
321
440
        for(unsigned int n = 0; n < in.length(); ++n) {
322
 
                if(linkify_isOneOf(in.at(n), "\"\'<>")) {
 
441
                if(linkify_isOneOf(in.at(n), "\"\'`<>")) {
323
442
                        // hex encode
324
443
                        QString hex;
325
444
                        hex.sprintf("%%%02X", in.at(n).latin1());
333
452
        return out;
334
453
}
335
454
 
 
455
static bool linkify_okUrl(const QString &url)
 
456
{
 
457
        if(url.at(url.length()-1) == '.')
 
458
                return FALSE;
 
459
 
 
460
        return TRUE;
 
461
}
 
462
 
336
463
static bool linkify_okEmail(const QString &addy)
337
464
{
338
465
        // this makes sure that there is an '@' and a '.' after it, and that there is
345
472
                return FALSE;
346
473
        if((addy.length()-1) - d <= 0)
347
474
                return FALSE;
 
475
        if(addy.find("..") != -1)
 
476
                return false;
348
477
 
349
478
        return TRUE;
350
479
}
381
510
                        isUrl = TRUE;
382
511
                        href = "";
383
512
                }
 
513
                else if (linkify_pmatch(out, n, "ed2k://")) {
 
514
                        n += 7;
 
515
                        isUrl = TRUE;
 
516
                        href = "";
 
517
                }
384
518
                else if(linkify_pmatch(out, n, "www.")) {
385
519
                        isUrl = TRUE;
386
520
                        href = "http://";
404
538
                                if(out.at(x2).isSpace() || out.at(x2) == '<')
405
539
                                        break;
406
540
                        }
407
 
                        --x2;
 
541
                        int len = x2-x1;
 
542
                        QString pre = resolveEntities(out.mid(x1, x2-x1));
408
543
 
409
544
                        // go backward hacking off unwanted punctuation
410
 
                        for(; x2 >= n; --x2) {
411
 
                                if(!linkify_isOneOf(out.at(x2), "!?,.()\""))
 
545
                        int cutoff;
 
546
                        for(cutoff = pre.length()-1; cutoff >= 0; --cutoff) {
 
547
                                if(!linkify_isOneOf(pre.at(cutoff), "!?,.()[]{}<>\""))
412
548
                                        break;
413
549
                        }
414
 
                        ++x2;
 
550
                        ++cutoff;
 
551
                        //++x2;
415
552
 
416
 
                        int len = x2-x1;
417
 
                        link = out.mid(x1, len);
418
 
                        href += resolveEntities(link);
 
553
                        link = pre.mid(0, cutoff);
 
554
                        if(!linkify_okUrl(link)) {
 
555
                                n = x1 + link.length();
 
556
                                continue;
 
557
                        }
 
558
                        href += link;
419
559
                        href = linkify_htmlsafe(href);
420
560
                        //printf("link: [%s], href=[%s]\n", link.latin1(), href.latin1());
421
 
                        linked = QString("<a href=\"%1\">").arg(href) + link + "</a>";
 
561
                        linked = QString("<a href=\"%1\">").arg(href) + expandEntities(link) + "</a>" + expandEntities(pre.mid(cutoff));
422
562
                        out.replace(x1, len, linked);
423
563
                        n = x1 + linked.length() - 1;
424
564
                }
460
600
        return out;
461
601
}
462
602
 
 
603
// sickening
 
604
QString emoticonify(const QString &in)
 
605
{
 
606
        RTParse p(in);
 
607
        while ( !p.atEnd() ) {
 
608
                // returns us the first chunk as a plaintext string
 
609
                QString str = p.next();
 
610
 
 
611
                int i = 0;
 
612
                while ( i >= 0 ) {
 
613
                        // find closest emoticon
 
614
                        int ePos = -1;
 
615
                        Icon *closest = 0;
 
616
 
 
617
                        int foundPos = -1, foundLen = -1;
 
618
 
 
619
                        QPtrListIterator<Iconset> iconsets(is->emoticons);
 
620
                        Iconset *iconset;
 
621
                        while ( (iconset = iconsets.current()) != 0 ) {
 
622
                                QPtrListIterator<Icon> it = iconset->iterator();
 
623
                                for ( ; it.current(); ++it) {
 
624
                                        Icon *icon = it.current();
 
625
                                        if ( icon->regExp().isEmpty() )
 
626
                                                continue;
 
627
 
 
628
                                        // some hackery
 
629
                                        int iii = i;
 
630
                                        bool searchAgain;
 
631
 
 
632
                                        do {
 
633
                                                searchAgain = false;
 
634
 
 
635
                                                // find the closest match
 
636
                                                const QRegExp &rx = icon->regExp();
 
637
                                                int n = rx.search(str, iii);
 
638
                                                if ( n == -1 )
 
639
                                                        continue;
 
640
 
 
641
                                                if(ePos == -1 || n < ePos || (rx.matchedLength() > foundLen && n < ePos + foundLen)) {
 
642
                                                        // there must be whitespace at least on one side of the emoticon
 
643
                                                        if ( ( n == 0 ) ||
 
644
                                                             ( n+rx.matchedLength() == (int)str.length() ) ||
 
645
                                                             ( n > 0 && str[n-1].isSpace() ) ||
 
646
                                                             ( n+rx.matchedLength() < (int)str.length() && str[n+rx.matchedLength()].isSpace() ) )
 
647
                                                        {
 
648
                                                                ePos = n;
 
649
                                                                closest = icon;
 
650
 
 
651
                                                                foundPos = n;
 
652
                                                                foundLen = rx.matchedLength();
 
653
                                                                break;
 
654
                                                        }
 
655
 
 
656
                                                        searchAgain = true;
 
657
                                                }
 
658
 
 
659
                                                iii = n + rx.matchedLength();
 
660
                                        } while ( searchAgain );
 
661
                                }
 
662
 
 
663
                                ++iconsets;
 
664
                        }
 
665
 
 
666
                        QString s;
 
667
                        if(ePos == -1)
 
668
                                s = str.mid(i);
 
669
                        else
 
670
                                s = str.mid(i, ePos-i);
 
671
                        p.putPlain(s);
 
672
 
 
673
                        if ( !closest )
 
674
                                break;
 
675
 
 
676
                        p.putRich( QString("<icon name=\"%1\" text=\"%2\">").arg(closest->name()).arg(str.mid(foundPos, foundLen)) );
 
677
                        i = foundPos + foundLen;
 
678
                }
 
679
        }
 
680
 
 
681
        QString out = p.output();
 
682
 
 
683
        //enable *bold* stuff
 
684
        // //old code
 
685
        //out=out.replace(QRegExp("(^[^<>\\s]*|\\s[^<>\\s]*)\\*(\\S+)\\*([^<>\\s]*\\s|[^<>\\s]*$)"),"\\1<b>*\\2*</b>\\3");
 
686
        //out=out.replace(QRegExp("(^[^<>\\s\\/]*|\\s[^<>\\s\\/]*)\\/([^\\/\\s]+)\\/([^<>\\s\\/]*\\s|[^<>\\s\\/]*$)"),"\\1<i>/\\2/</i>\\3");
 
687
        //out=out.replace(QRegExp("(^[^<>\\s]*|\\s[^<>\\s]*)_(\\S+)_([^<>\\s]*\\s|[^<>\\s]*$)"),"\\1<u>_\\2_</u>\\3");
 
688
 
 
689
        out=out.replace(QRegExp("(^_|\\s_)(\\S+)(_\\s|_$)"),"\\1<u>\\2</u>\\3");
 
690
        out=out.replace(QRegExp("(^\\*|\\s\\*)(\\S+)(\\*\\s|\\*$)"),"\\1<b>\\2</b>\\3");
 
691
        out=out.replace(QRegExp("(^\\/|\\s\\/)(\\S+)(\\/\\s|\\/$)"),"\\1<i>\\2</i>\\3");
 
692
 
 
693
        return out;
 
694
}
 
695
 
463
696
QString encodePassword(const QString &pass, const QString &key)
464
697
{
465
698
        QString result;
503
736
        return result;
504
737
}
505
738
 
506
 
QPixmap & status2pix(int status)
507
 
{
508
 
        switch(status) {
509
 
                case STATUS_OFFLINE:    return *pix_offline;
510
 
                case STATUS_ONLINE:     return *pix_online;
511
 
                case STATUS_AWAY:       return *pix_away;
512
 
                case STATUS_XA:         return *pix_xa;
513
 
                case STATUS_DND:        return *pix_dnd;
514
 
 
515
 
                default:                return *pix_online;
516
 
        }
517
 
}
518
 
 
519
 
QImage & status2qim(int status)
520
 
{
521
 
        switch(status) {
522
 
                case STATUS_OFFLINE:    return *qim_offline;
523
 
                case STATUS_ONLINE:     return *qim_online;
524
 
                case STATUS_AWAY:       return *qim_away;
525
 
                case STATUS_XA:         return *qim_xa;
526
 
                case STATUS_DND:        return *qim_dnd;
527
 
 
528
 
                default:                return *qim_online;
529
 
        }
530
 
}
531
 
 
532
739
QString status2txt(int status)
533
740
{
534
 
        switch(status) {
535
 
                case STATUS_OFFLINE:    return QObject::tr("Offline");
536
 
                case STATUS_ONLINE:     return QObject::tr("Online");
537
 
                case STATUS_AWAY:       return QObject::tr("Away");
538
 
                case STATUS_XA:         return QObject::tr("Not Available");
539
 
                case STATUS_DND:        return QObject::tr("Do not Disturb");
540
 
 
541
 
                default:                return QObject::tr("Online");
542
 
        }
543
 
}
544
 
 
545
 
 
546
 
QString RecognizedTransportNames[] = {
547
 
        "ICQ",
548
 
        "AIM",
549
 
        "MSN",
550
 
        "Yahoo!",
551
 
};
552
 
 
553
 
const QString & transport2str(const QString &name)
554
 
{
555
 
        QString service(name);
556
 
 
557
 
        if(service.mid(0,4) == "icq.")
558
 
                return RecognizedTransportNames[0];
559
 
        else if(service.mid(0,4) == "aim.")
560
 
                return RecognizedTransportNames[1];
561
 
        else if(service.mid(0,4) == "msn.")
562
 
                return RecognizedTransportNames[2];
563
 
        else if(service.mid(0,6) == "yahoo.")
564
 
                return RecognizedTransportNames[3];
565
 
 
566
 
        return name;
567
 
}
568
 
 
569
 
QPixmap & transport2icon(const QString &jid, int status)
570
 
{
571
 
        int trans, pix;
572
 
 
573
 
        if(jid.mid(0,4) == "icq.")
574
 
                trans = 1;
575
 
        else if(jid.mid(0,4) == "aim.")
576
 
                trans = 2;
577
 
        else if(jid.mid(0,4) == "msn.")
578
 
                trans = 3;
579
 
        else if(jid.mid(0,6) == "yahoo.")
580
 
                trans = 4;
581
 
        else
582
 
                trans = 0;
583
 
 
584
741
        switch(status) {
585
 
                case STATUS_OFFLINE:    pix = 0; break;
586
 
                case STATUS_ONLINE:     pix = 1; break;
587
 
                case STATUS_AWAY:       pix = 2; break;
588
 
                case STATUS_XA:         pix = 3; break;
589
 
                case STATUS_DND:        pix = 4; break;
590
 
 
591
 
                default:                pix = 1; break;
592
 
        }
593
 
 
594
 
        if(!tic[trans].p[pix])
595
 
                trans = 0;
596
 
 
597
 
        return *tic[trans].p[pix];
598
 
}
599
 
 
600
 
QPixmap *loadImage(const QString &fname, const QStringList &_dirs)
601
 
{
602
 
        QImage image;
603
 
        QStringList dirs = _dirs;
604
 
 
605
 
        for(QStringList::Iterator it = dirs.begin(); it != dirs.end(); ++it) {
606
 
                QString str = (*it) + "/" + fname;
607
 
                if(image.load(str) == TRUE) {
608
 
                        QPixmap *p = new QPixmap;
609
 
                        // this is weird, but it gets the mask right on Windows
610
 
                        p->convertFromImage(image.copy(0,0,image.width(),image.height()));
611
 
                        return p;
612
 
                }
613
 
        }
614
 
 
615
 
        return 0;
616
 
}
617
 
 
618
 
char *loadImageData(const QString &fname, const QStringList &_dirs, int *size)
619
 
{
620
 
        char *p;
621
 
        QStringList dirs = _dirs;
622
 
 
623
 
        for(QStringList::Iterator it = dirs.begin(); it != dirs.end(); ++it) {
624
 
                QString str = (*it) + "/" + fname;
625
 
                QFileInfo info(str);
626
 
                if(info.exists()) {
627
 
                        *size = info.size();
628
 
                        QFile f(str);
629
 
                        if(!f.open(IO_ReadOnly))
630
 
                                continue;
631
 
                        QByteArray a = f.readAll();
632
 
                        p = new char[(*size)];
633
 
                        memcpy(p, a.data(), *size);
634
 
 
635
 
                        return p;
636
 
                }
637
 
        }
638
 
 
639
 
        return 0;
640
 
}
641
 
 
642
 
Anim *loadAnim(const QString &fname, const QStringList &dirs)
643
 
{
644
 
        QPixmap *p = loadImage(fname, dirs);
645
 
        if(!p)
646
 
                return 0;
647
 
 
648
 
        Anim *a = new Anim(*p);
649
 
        delete p;
650
 
 
651
 
        return a;
652
 
}
653
 
 
654
 
void bringToFront(QWidget *w)
655
 
{
656
 
        w->show();
657
 
        w->raise();
658
 
        w->setActiveWindow();
659
 
}
660
 
 
661
 
#ifdef Q_WS_WIN
662
 
void win_raiseNoFocus(QWidget *w)
663
 
{
664
 
        w->show();
665
 
        w->raise();
666
 
        //SetWindowPos(w->winId(),HWND_TOP,0,0,0,0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
667
 
}
668
 
#endif
 
742
                case STATUS_OFFLINE:    return QObject::tr("Offline");
 
743
                case STATUS_AWAY:       return QObject::tr("Away");
 
744
                case STATUS_XA:         return QObject::tr("Not Available");
 
745
                case STATUS_DND:        return QObject::tr("Do not Disturb");
 
746
                case STATUS_CHAT:       return QObject::tr("Free for Chat");
 
747
                case STATUS_INVISIBLE:  return QObject::tr("Invisible");
 
748
 
 
749
                case STATUS_ONLINE:
 
750
                default:                return QObject::tr("Online");
 
751
        }
 
752
}
 
753
 
 
754
Icon category2icon(const QString &category, const QString &type)
 
755
{
 
756
        // TODO: update this to http://www.jabber.org/registrar/disco-categories.html#gateway
 
757
 
 
758
        // still have to add more options...
 
759
        if ( category == "service" || category == "gateway" ) {
 
760
                QString trans;
 
761
 
 
762
                if (type == "aim")
 
763
                        trans = "aim";
 
764
                else if (type == "icq")
 
765
                        trans = "icq";
 
766
                else if (type == "msn")
 
767
                        trans = "msn";
 
768
                else if (type == "yahoo")
 
769
                        trans = "yahoo";
 
770
                else if (type == "gadugadu" || type == "x-gadugadu")
 
771
                        trans = "gadugadu";
 
772
                else if (type == "sms")
 
773
                        trans = "sms";
 
774
                else
 
775
                        trans = "transport";
 
776
 
 
777
                return is->transportStatus(trans, STATUS_ONLINE);
 
778
 
 
779
                // irc
 
780
                // jud
 
781
                // pager
 
782
                // jabber
 
783
                // serverlist
 
784
                // smtp
 
785
        }
 
786
        else if ( category == "conference" ) {
 
787
                if (type == "public" || type == "private" || type == "text" || type == "irc")
 
788
                        return IconsetFactory::icon("psi/groupChat");
 
789
                else if (type == "url")
 
790
                        return IconsetFactory::icon("psi/www");
 
791
                // irc
 
792
                // list
 
793
                // topic
 
794
        }
 
795
        else if ( category == "validate" ) {
 
796
                if (type == "xml")
 
797
                        return IconsetFactory::icon("psi/xml");
 
798
                // grammar
 
799
                // spell
 
800
        }
 
801
        else if ( category == "user" || category == "client" ) {
 
802
                // client
 
803
                // forward
 
804
                // inbox
 
805
                // portable
 
806
                // voice
 
807
                return is->status(STATUS_ONLINE);
 
808
        }
 
809
        // application
 
810
           // bot
 
811
           // calendar
 
812
           // editor
 
813
           // fileserver
 
814
           // game
 
815
           // whiteboard
 
816
        // headline
 
817
           // logger
 
818
           // notice
 
819
           // rss
 
820
           // stock
 
821
        // keyword
 
822
           // dictionary
 
823
           // dns
 
824
           // software
 
825
           // thesaurus
 
826
           // web
 
827
           // whois
 
828
        // render
 
829
           // en2ru
 
830
           // ??2??
 
831
           // tts
 
832
        return Icon();
 
833
}
669
834
 
670
835
int hexChar2int(char c)
671
836
{
689
854
 
690
855
QString jidEncode(const QString &jid)
691
856
{
692
 
        QString jid2;
693
 
 
694
 
        for(unsigned int n = 0; n < jid.length(); ++n) {
695
 
                if(jid.at(n) == '@') {
696
 
                        jid2.append("_at_");
697
 
                }
698
 
                else if(jid.at(n) == '.') {
699
 
                        jid2.append('.');
700
 
                }
701
 
                else if(!jid.at(n).isLetterOrNumber()) {
702
 
                        // hex encode
703
 
                        QString hex;
704
 
                        hex.sprintf("%%%02X", jid.at(n).latin1());
705
 
                        jid2.append(hex);
706
 
                }
707
 
                else {
708
 
                        jid2.append(jid.at(n));
709
 
                }
710
 
        }
711
 
 
712
 
        return jid2;
 
857
        QString jid2;
 
858
 
 
859
        for(unsigned int n = 0; n < jid.length(); ++n) {
 
860
                if(jid.at(n) == '@') {
 
861
                        jid2.append("_at_");
 
862
                }
 
863
                else if(jid.at(n) == '.') {
 
864
                        jid2.append('.');
 
865
                }
 
866
                else if(!jid.at(n).isLetterOrNumber()) {
 
867
                        // hex encode
 
868
                        QString hex;
 
869
                        hex.sprintf("%%%02X", jid.at(n).latin1());
 
870
                        jid2.append(hex);
 
871
                }
 
872
                else {
 
873
                        jid2.append(jid.at(n));
 
874
                }
 
875
        }
 
876
 
 
877
        return jid2;
713
878
}
714
879
 
715
880
QString jidDecode(const QString &jid)
786
951
        return ret;
787
952
}
788
953
 
789
 
void unfinishedSoftware()
790
 
{
791
 
        QMessageBox::information(0, CAP(QObject::tr("Warning")), QObject::tr(
792
 
         "<h3>*** Warning! ***</h3>\n"
793
 
         "This is unfinished software.  It has been released so that interested users "
794
 
         "can try it out and perhaps follow its development.  It is not guaranteed to be "
795
 
         "bugfree, although it is quite stable in my experience.<br><br>\n"
796
 
         "One day it will be finished.  Until then, don't count on every "
797
 
         "Jabber feature to work.  If you want to assist me in making this program "
798
 
         "better, feel free to email me bugreports/patches/wishes.<br><br>\n"
799
 
         "Note: quite a few options/features appear \"grayed out\".  They "
800
 
         "indicate planned features that are not in the program yet.<br><br>"
801
 
         "Now that this is out of the way, enjoy Psi!\n"
802
 
         ));
803
 
}
804
 
 
805
 
bool loadPsiIconSet(const QString name)
806
 
{
807
 
        QStringList dirs;
808
 
        QString subdir = "/iconsets/" + name;
809
 
 
810
 
        dirs += "." + subdir;
811
 
        dirs += g.pathHome + subdir;
812
 
        dirs += g.pathBase + subdir;
813
 
        dirs += g.pathBase + "/iconsets/stellar";
814
 
 
815
 
 
816
 
        // load animations - this needs to be implemented better
817
 
        anim_message = loadAnim("message.png", dirs);
818
 
        anim_system = loadAnim("system.png", dirs);
819
 
        anim_chat = loadAnim("chat.png", dirs);
820
 
        anim_headline = loadAnim("headline.png", dirs);
821
 
        if(!anim_message || !anim_system || !anim_chat || !anim_headline)
822
 
                return FALSE;
823
 
 
824
 
        // load pixmaps
825
 
        pix_online      = loadImage("online.png", dirs);
826
 
        pix_offline     = loadImage("offline.png", dirs);
827
 
        pix_away        = loadImage("away.png", dirs);
828
 
        pix_xa          = loadImage("xa.png", dirs);
829
 
        pix_dnd         = loadImage("dnd.png", dirs);
830
 
        pix_arrow[0]    = loadImage("groupclose.png", dirs);
831
 
        pix_arrow[1]    = loadImage("groupopen.png", dirs);
832
 
        pix_arrow[2]    = loadImage("groupempty.png", dirs);
833
 
        pix_add         = loadImage("add.png", dirs);
834
 
        pix_remove      = loadImage("remove.png", dirs);
835
 
        pix_send        = loadImage("send.png", dirs);
836
 
        pix_history     = loadImage("history.png", dirs);
837
 
        pix_info        = loadImage("info.png", dirs);
838
 
        pix_changeacc   = loadImage("changeacc.png", dirs);
839
 
        pix_url         = loadImage("url.png", dirs);
840
 
 
841
 
        if(!pix_online || !pix_offline || !pix_away || !pix_xa || !pix_dnd || !pix_arrow[0] ||
842
 
           !pix_arrow[1] || !pix_arrow[2] || !pix_add || !pix_remove || !pix_send || !pix_history ||
843
 
           !pix_info || !pix_changeacc || !pix_url)
844
 
                return FALSE;
845
 
 
846
 
        qim_online      = new QImage(pix_online->convertToImage());
847
 
        qim_offline     = new QImage(pix_offline->convertToImage());
848
 
        qim_away        = new QImage(pix_away->convertToImage());
849
 
        qim_xa          = new QImage(pix_xa->convertToImage());
850
 
        qim_dnd         = new QImage(pix_dnd->convertToImage());
851
 
 
852
 
        return TRUE;
853
 
}
854
 
 
855
 
void unloadPsiIconSet()
856
 
{
857
 
        return;
858
 
        delete anim_message;
859
 
        delete anim_system;
860
 
        delete anim_chat;
861
 
        delete anim_headline;
862
 
 
863
 
        delete pix_online;
864
 
        delete pix_offline;
865
 
        delete pix_away;
866
 
        delete pix_xa;
867
 
        delete pix_dnd;
868
 
        delete pix_arrow[0];
869
 
        delete pix_arrow[1];
870
 
        delete pix_arrow[2];
871
 
        delete pix_add;
872
 
        delete pix_remove;
873
 
        delete pix_send;
874
 
        delete pix_history;
875
 
        delete pix_changeacc;
876
 
        delete pix_url;
877
 
 
878
 
        delete qim_online;
879
 
        delete qim_offline;
880
 
        delete qim_away;
881
 
        delete qim_xa;
882
 
        delete qim_dnd;
883
 
}
884
 
 
885
 
void getPsiIconSets(QStringList &names, QStringList &descriptions)
886
 
{
887
 
        QStringList dirs;
888
 
        QString subdir = "/iconsets";
889
 
 
890
 
        dirs += "." + subdir;
891
 
        dirs += g.pathHome + subdir;
892
 
        dirs += g.pathBase + subdir;
893
 
 
894
 
        for(QStringList::Iterator it = dirs.begin(); it != dirs.end(); ++it) {
895
 
                if(!QFile::exists(*it))
896
 
                        continue;
897
 
                QDir d(*it);
898
 
                QStringList entries = d.entryList();
899
 
                for(QStringList::Iterator it2 = entries.begin(); it2 != entries.end(); ++it2) {
900
 
                        // make sure we don't have it
901
 
                        bool found = FALSE;
902
 
                        for(QStringList::Iterator it3 = names.begin(); it3 != names.end(); ++it3) {
903
 
                                if(*it3 == *it2) {
904
 
                                        found = TRUE;
 
954
void qstringlistisort(QStringList &c)
 
955
{
 
956
        if ( c.count() <= 1 )
 
957
                return;
 
958
 
 
959
        QStringList::Iterator it;
 
960
        uint size = c.count();
 
961
 
 
962
        // first, make array that is easy (and quick) to manipulate
 
963
        QString *heap = new QString[ size ];
 
964
 
 
965
        int i = 0;
 
966
        for (it = c.begin(); it != c.end(); ++it)
 
967
                heap[i++] = *it;
 
968
 
 
969
        // Insertion sort
 
970
        for (uint tmp = 0; tmp < c.count(); tmp++) {
 
971
                heap[tmp] = c[tmp];
 
972
                size = tmp + 1;
 
973
 
 
974
                for (uint j = 1; j < size; j++) {
 
975
                        QString k = heap[j].lower();
 
976
                        QString r = heap[j];
 
977
 
 
978
                        for (i = j - 1; i >= 0; i--) {
 
979
                                if ( QString::compare(k, heap[i].lower()) > 0 )
905
980
                                        break;
906
 
                                }
 
981
 
 
982
                                heap[i+1] = heap[i];
907
983
                        }
908
 
                        if(found)
909
 
                                continue;
910
 
 
911
 
                        QFile f(*it + "/" + *it2 + "/desc");
912
 
                        if(!f.open(IO_ReadOnly))
913
 
                                continue;
914
 
                        QCString line;
915
 
                        line.resize(256);
916
 
                        int n = f.readLine(line.data(), 255);
917
 
                        if(n == -1)
918
 
                                continue;
919
 
                        line[n] = 0;
920
 
                        if(line.at(line.length()-1) == '\n')
921
 
                                line.at(line.length()-1) = 0;
922
 
 
923
 
                        QString desc = QString::fromUtf8(line);
924
 
 
925
 
                        names += *it2;
926
 
                        descriptions += line;
 
984
 
 
985
                        heap[i+1] = r;
927
986
                }
928
987
        }
 
988
 
 
989
        // now, copy sorted data back to QStringList
 
990
        it = c.begin();
 
991
        for (i = 0; i < (int)size; i++)
 
992
                *it++ = heap[i];
 
993
 
 
994
        delete[] heap;
929
995
}
930
996
 
931
 
 
932
997
void openURL(const QString &url)
933
998
{
934
999
        //fprintf(stderr, "openURL: [%s]\n", url.latin1());
935
1000
        bool useCustom = TRUE;
936
1001
 
 
1002
        int colon = url.find(':');
 
1003
        if ( colon == -1 )
 
1004
                colon = 0;
 
1005
        QString service = url.left( colon );
 
1006
        if ( service == "jabber" || service == "jid" ) {
 
1007
                // TODO
 
1008
                return;
 
1009
        }
 
1010
 
937
1011
#ifdef Q_WS_WIN
938
1012
        if(option.browser == 0)
939
1013
                useCustom = FALSE;
940
1014
#endif
941
1015
#ifdef Q_WS_X11
942
 
        if(option.browser == 0)
 
1016
        if(option.browser == 0 || option.browser == 2)
943
1017
                useCustom = FALSE;
944
1018
#endif
945
1019
#ifdef Q_WS_MAC
961
1035
                                QMessageBox::critical(0, CAP(QObject::tr("URL error")), QObject::tr("Unable to open the URL. You have not selected a mailer (see Options)."));
962
1036
                                return;
963
1037
                        }
964
 
                        args += option.customMailer;
 
1038
                        args += QStringList::split(' ', option.customMailer);
965
1039
                }
966
1040
                else {
967
1041
                        if(option.customBrowser.isEmpty()) {
968
1042
                                QMessageBox::critical(0, CAP(QObject::tr("URL error")), QObject::tr("Unable to open the URL. You have not selected a browser (see Options)."));
969
1043
                                return;
970
1044
                        }
971
 
                        args += option.customBrowser;
 
1045
                        args += QStringList::split(' ', option.customBrowser);
972
1046
                }
973
1047
 
974
1048
                args += s;
979
1053
        }
980
1054
        else {
981
1055
#ifdef Q_WS_WIN
982
 
                if ((unsigned int)::ShellExecuteA(NULL,NULL,url.latin1(),NULL,NULL,SW_SHOW) <= 32) {
 
1056
                QCString cs = url.local8Bit();
 
1057
                if ((unsigned int)::ShellExecuteA(NULL,NULL,cs.data(),NULL,NULL,SW_SHOW) <= 32) {
983
1058
                        QMessageBox::critical(0, CAP(QObject::tr("URL error")), QObject::tr("Unable to open the URL. Ensure that you have a web browser installed."));
984
1059
                }
985
1060
#endif
986
1061
#ifdef Q_WS_X11
987
 
                QStringList args;
988
 
                args += "kfmclient";
989
 
                args += "exec";
990
 
                args += url;
991
 
                QProcess cmd(args);
992
 
                if(!cmd.start()) {
993
 
                        QMessageBox::critical(0, CAP(QObject::tr("URL error")), QObject::tr("Unable to open the URL. Ensure that you have KDE installed."));
 
1062
                // KDE
 
1063
                if(option.browser == 0) {
 
1064
                        QStringList args;
 
1065
                        args += "kfmclient";
 
1066
                        args += "exec";
 
1067
                        args += url;
 
1068
                        QProcess cmd(args);
 
1069
                        if(!cmd.start()) {
 
1070
                                QMessageBox::critical(0, CAP(QObject::tr("URL error")), QObject::tr("Unable to open the URL. Ensure that you have KDE installed."));
 
1071
                        }
 
1072
                }
 
1073
                // GNOME 2
 
1074
                else if(option.browser == 2) {
 
1075
                        QStringList args;
 
1076
                        args += "gnome-open";
 
1077
                        args += url;
 
1078
                        QProcess cmd(args);
 
1079
                        if(!cmd.start()) {
 
1080
                                QMessageBox::critical(0, CAP(QObject::tr("URL error")), QObject::tr("Unable to open the URL. Ensure that you have GNOME 2 installed."));
 
1081
                        }
994
1082
                }
995
1083
#endif
996
1084
#ifdef Q_WS_MAC
1004
1092
    OSStatus error = ::ICStart( &icInstance, psiSignature );
1005
1093
    if ( error == noErr ) {
1006
1094
      ConstStr255Param hint( 0x0 );
1007
 
      const char* data = url.latin1();
1008
 
      long length = url.length();
 
1095
      QCString cs = url.local8Bit();
 
1096
      const char* data = cs.data();
 
1097
      long length = cs.length();
1009
1098
      long start( 0 );
1010
1099
      long end( length );
1011
1100
      // Don't bother testing return value (error); launched application will report problems.
1016
1105
        }
1017
1106
}
1018
1107
 
1019
 
Anim *messagetype2anim(int type)
1020
 
{
1021
 
        if(type == MESSAGE_SYS || type == MESSAGE_AUTHREQ || type == MESSAGE_ERROR)
1022
 
                return anim_system;
1023
 
        else if(type == MESSAGE_CHAT)
1024
 
                return anim_chat;
1025
 
        else if(type == MESSAGE_HEADLINE)
1026
 
                return anim_headline;
1027
 
 
1028
 
        return anim_message;
1029
 
}
1030
 
 
1031
 
QString messagetype2str(int type)
1032
 
{
1033
 
        if(type == MESSAGE_SYS)
1034
 
                return QString(QObject::tr("System"));
1035
 
        else if(type == MESSAGE_AUTHREQ)
1036
 
                return QString(QObject::tr("Auth Request"));
1037
 
        else if(type == MESSAGE_CHAT)
1038
 
                return QString(QObject::tr("Chat"));
1039
 
        else if(type == MESSAGE_ERROR)
1040
 
                return QString(QObject::tr("Error"));
1041
 
        else if(type == MESSAGE_HEADLINE)
1042
 
                return QString(QObject::tr("Headline"));
1043
 
        else
1044
 
                return QString(QObject::tr("Normal"));
1045
 
}
1046
 
 
1047
1108
static bool sysinfo_done = FALSE;
1048
1109
static int timezone_offset = 0;
1049
1110
static QString timezone_str = "N/A";
1062
1123
        time_t x;
1063
1124
        time(&x);
1064
1125
        char str[256];
1065
 
        char *fmt = "%z";
 
1126
        char fmt[32];
 
1127
        strcpy(fmt, "%z");
1066
1128
        strftime(str, 256, fmt, localtime(&x));
1067
1129
        if(strcmp(fmt, str)) {
1068
1130
                QString s = str;
1071
1133
                s.truncate(s.length()-2);
1072
1134
                timezone_offset = s.toInt();
1073
1135
        }
1074
 
        fmt = "%Z";
 
1136
        strcpy(fmt, "%Z");
1075
1137
        strftime(str, 256, fmt, localtime(&x));
1076
1138
        if(strcmp(fmt, str))
1077
1139
                timezone_str = str;
 
1140
#endif
 
1141
#if defined(Q_WS_X11)
1078
1142
        struct utsname u;
1079
1143
        uname(&u);
1080
1144
        os_str.sprintf("%s", u.sysname);
1081
 
#elif defined(Q_WS_WIN)
 
1145
 
 
1146
        // get description about os
 
1147
        enum LinuxName {
 
1148
                LinuxNone = 0,
 
1149
 
 
1150
                LinuxMandrake,
 
1151
                LinuxDebian,
 
1152
                LinuxRedHat,
 
1153
                LinuxGentoo,
 
1154
                LinuxSlackware,
 
1155
                LinuxSuSE,
 
1156
                LinuxConectiva,
 
1157
                LinuxCaldera,
 
1158
 
 
1159
                LinuxASP, // Russian Linux distros
 
1160
                LinuxALT,
 
1161
 
 
1162
                LinuxPLD, // Polish Linux distros
 
1163
                LinuxAurox,
 
1164
                LinuxArch
 
1165
        };
 
1166
 
 
1167
        enum OsFlags {
 
1168
                OsUseName = 0,
 
1169
                OsUseFile,
 
1170
                OsAppendFile
 
1171
        };
 
1172
 
 
1173
        struct OsInfo {
 
1174
                LinuxName id;
 
1175
                OsFlags flags;
 
1176
                QString file;
 
1177
                QString name;
 
1178
        } osInfo[] = {
 
1179
                { LinuxMandrake,        OsUseFile,      "/etc/mandrake-release",        "Mandrake Linux"        },
 
1180
                { LinuxDebian,          OsAppendFile,   "/etc/debian_version",          "Debian GNU/Linux"      },
 
1181
                { LinuxGentoo,          OsUseFile,      "/etc/gentoo-release",          "Gentoo Linux"          },
 
1182
                { LinuxSlackware,       OsAppendFile,   "/etc/slackware-version",       "Slackware Linux"       },
 
1183
                { LinuxPLD,             OsUseFile,      "/etc/pld-release",             "PLD Linux"             },
 
1184
                { LinuxAurox,           OsUseName,      "/etc/aurox-release",           "Aurox Linux"           },
 
1185
                { LinuxArch,            OsUseFile,      "/etc/arch-release",            "Arch Linux"            },
 
1186
 
 
1187
                // untested
 
1188
                { LinuxSuSE,            OsUseFile,      "/etc/SuSE-release",            "SuSE Linux"            },
 
1189
                { LinuxConectiva,       OsUseFile,      "/etc/conectiva-release",       "Conectiva Linux"       },
 
1190
                { LinuxCaldera,         OsUseFile,      "/etc/.installed",              "Caldera Linux"         },
 
1191
 
 
1192
                // many distros use the /etc/redhat-release for compatibility, so RedHat will be the last :)
 
1193
                { LinuxRedHat,          OsUseFile,      "/etc/redhat-release",          "RedHat Linux"          },
 
1194
 
 
1195
                { LinuxNone,            OsUseName,      "",                             ""                      }
 
1196
        };
 
1197
 
 
1198
        for (int i = 0; osInfo[i].id != LinuxNone; i++) {
 
1199
                QFileInfo fi( osInfo[i].file );
 
1200
                if ( fi.exists() ) {
 
1201
                        QString desc;
 
1202
 
 
1203
                        QFile f( osInfo[i].file );
 
1204
                        f.open( IO_ReadOnly );
 
1205
                        f.readLine( desc, 128 );
 
1206
 
 
1207
                        desc = desc.stripWhiteSpace ();
 
1208
 
 
1209
                        switch ( osInfo[i].flags ) {
 
1210
                                case OsUseFile:
 
1211
                                        os_str = desc;
 
1212
                                        break;
 
1213
                                case OsUseName:
 
1214
                                        os_str = osInfo[i].name;
 
1215
                                        break;
 
1216
                                case OsAppendFile:
 
1217
                                        os_str = osInfo[i].name + " (" + desc + ")";
 
1218
                                        break;
 
1219
                        }
 
1220
 
 
1221
                        break;
 
1222
                }
 
1223
        }
 
1224
#elif defined(Q_WS_MAC)
 
1225
        os_str = "MacOS X";
 
1226
#endif
 
1227
 
 
1228
#if defined(Q_WS_WIN)
1082
1229
        TIME_ZONE_INFORMATION i;
1083
 
        GetTimeZoneInformation(&i);
1084
 
        timezone_offset = (-i.Bias) / 60;
 
1230
        //GetTimeZoneInformation(&i);
 
1231
        //timezone_offset = (-i.Bias) / 60;
 
1232
        memset(&i, 0, sizeof(i));
 
1233
        bool inDST = (GetTimeZoneInformation(&i) == TIME_ZONE_ID_DAYLIGHT);
 
1234
        int bias = i.Bias;
 
1235
        if(inDST)
 
1236
                bias += i.DaylightBias;
 
1237
        timezone_offset = (-bias) / 60;
1085
1238
        timezone_str = "";
1086
1239
        for(int n = 0; n < 32; ++n) {
1087
 
                uint w = i.StandardName[n];
 
1240
                uint w = inDST ? i.DaylightName[n] : i.StandardName[n];
1088
1241
                if(w == 0)
1089
1242
                        break;
1090
1243
                timezone_str += QChar(w);
1135
1288
#ifdef Q_WS_X11
1136
1289
QString getResourcesDir()
1137
1290
{
1138
 
        return "/usr/share/psi";
 
1291
        return LIBDIR;
1139
1292
}
1140
1293
 
1141
1294
QString getHomeDir()
1144
1297
        if(!proghome.exists()) {
1145
1298
                QDir home = QDir::home();
1146
1299
                home.mkdir(".psi");
1147
 
                chmod(proghome.path().latin1(), 0700);
 
1300
                chmod(QFile::encodeName(proghome.path()), 0700);
1148
1301
        }
1149
1302
 
1150
1303
        return proghome.path();
1154
1307
#ifdef Q_WS_WIN
1155
1308
QString getResourcesDir()
1156
1309
{
1157
 
        return ".";
 
1310
#if QT_VERSION >= 0x030200
 
1311
        return qApp->applicationDirPath();
 
1312
#else
 
1313
        char baseName[MAX_PATH];
 
1314
        GetModuleFileNameA(GetModuleHandle(NULL), baseName, MAX_PATH);
 
1315
        QString base(baseName);
 
1316
        int idx = base.findRev('\\');
 
1317
 
 
1318
        if (-1 == idx)
 
1319
                return ".";
 
1320
 
 
1321
        base.truncate(idx);
 
1322
        QDir baseDir(base);
 
1323
 
 
1324
        return baseDir.absPath();
 
1325
#endif
1158
1326
}
1159
1327
 
1160
1328
QString getHomeDir()
1194
1362
  QString resourcePath;
1195
1363
  CFBundleRef mainBundle = CFBundleGetMainBundle();
1196
1364
  CFStringRef resourceCFStringRef
1197
 
      = CFStringCreateWithCString( NULL, "Psi.icns",
 
1365
      = CFStringCreateWithCString( NULL, "application.icns",
1198
1366
                                   kCFStringEncodingASCII );
1199
1367
  CFURLRef resourceURLRef = CFBundleCopyResourceURL( mainBundle,
1200
1368
                                                     resourceCFStringRef,
1235
1403
        if(!proghome.exists()) {
1236
1404
                QDir home = QDir::home();
1237
1405
                home.mkdir(".psi");
 
1406
                chmod(QFile::encodeName(proghome.path()), 0700);
1238
1407
        }
1239
1408
 
1240
1409
        return proghome.path();
1247
1416
        return pathToProfile(activeProfile) + "/history";
1248
1417
}
1249
1418
 
 
1419
QString getVCardDir()
 
1420
{
 
1421
        return pathToProfile(activeProfile) + "/vcard";
 
1422
}
 
1423
 
1250
1424
bool fileCopy(const QString &src, const QString &dest)
1251
1425
{
1252
1426
        QFile in(src);
1297
1471
}
1298
1472
#endif
1299
1473
 
 
1474
void soundPlay(const QString &str)
 
1475
{
 
1476
        if(str == "!beep") {
 
1477
                QApplication::beep();
 
1478
                return;
 
1479
        }
 
1480
 
 
1481
        if(!QFile::exists(str))
 
1482
                return;
 
1483
 
 
1484
#if defined(Q_WS_WIN) || defined(Q_WS_MAC)
 
1485
        QSound::play(str);
 
1486
#else
 
1487
        if(!option.player.isEmpty()) {
 
1488
                QStringList args;
 
1489
                args = QStringList::split(' ', option.player);
 
1490
                args += str;
 
1491
                QProcess cmd(args);
 
1492
                if(!cmd.start())
 
1493
                        wait3(NULL,WNOHANG,NULL);
 
1494
        }
 
1495
#endif
 
1496
}
 
1497
 
 
1498
XMPP::Status makeStatus(int x, const QString &str)
 
1499
{
 
1500
        XMPP::Status s;
 
1501
        s.setStatus(str);
 
1502
        if(x == STATUS_OFFLINE)
 
1503
                s.setIsAvailable(false);
 
1504
        else if(x == STATUS_INVISIBLE)
 
1505
                s.setIsInvisible(true);
 
1506
        else {
 
1507
                if(x == STATUS_AWAY)
 
1508
                        s.setShow("away");
 
1509
                else if(x == STATUS_XA)
 
1510
                        s.setShow("xa");
 
1511
                else if(x == STATUS_DND)
 
1512
                        s.setShow("dnd");
 
1513
                else if(x == STATUS_CHAT)
 
1514
                        s.setShow("chat");
 
1515
        }
 
1516
 
 
1517
        return s;
 
1518
}
 
1519
 
 
1520
int makeSTATUS(const XMPP::Status &s)
 
1521
{
 
1522
        int type = STATUS_ONLINE;
 
1523
        if(!s.isAvailable())
 
1524
                type = STATUS_OFFLINE;
 
1525
        else if(s.isInvisible())
 
1526
                type= STATUS_INVISIBLE;
 
1527
        else {
 
1528
                if(s.show() == "away")
 
1529
                        type = STATUS_AWAY;
 
1530
                else if(s.show() == "xa")
 
1531
                        type = STATUS_XA;
 
1532
                else if(s.show() == "dnd")
 
1533
                        type = STATUS_DND;
 
1534
                else if(s.show() == "chat")
 
1535
                        type = STATUS_CHAT;
 
1536
        }
 
1537
        return type;
 
1538
}
 
1539
 
 
1540
#include<qlayout.h>
 
1541
QLayout *rw_recurseFindLayout(QLayout *lo, QWidget *w)
 
1542
{
 
1543
        //printf("scanning layout: %p\n", lo);
 
1544
        QLayoutIterator it = lo->iterator();
 
1545
        for(QLayoutItem *i; (i = it.current()); ++it) {
 
1546
                //printf("found: %p,%p\n", i->layout(), i->widget());
 
1547
                QLayout *slo = i->layout();
 
1548
                if(slo) {
 
1549
                        QLayout *tlo = rw_recurseFindLayout(slo, w);
 
1550
                        if(tlo)
 
1551
                                return tlo;
 
1552
                }
 
1553
                else if(i->widget() == w)
 
1554
                        return lo;
 
1555
        }
 
1556
        return 0;
 
1557
}
 
1558
 
 
1559
QLayout *rw_findLayoutOf(QWidget *w)
 
1560
{
 
1561
        return rw_recurseFindLayout(w->parentWidget()->layout(), w);
 
1562
}
 
1563
 
 
1564
void replaceWidget(QWidget *a, QWidget *b)
 
1565
{
 
1566
        if(!a)
 
1567
                return;
 
1568
 
 
1569
        QLayout *lo = rw_findLayoutOf(a);
 
1570
        if(!lo)
 
1571
                return;
 
1572
        //printf("decided on this: %p\n", lo);
 
1573
 
 
1574
        if(lo->inherits("QBoxLayout")) {
 
1575
                QBoxLayout *bo = (QBoxLayout *)lo;
 
1576
                int n = bo->findWidget(a);
 
1577
                bo->insertWidget(n+1, b);
 
1578
                delete a;
 
1579
        }
 
1580
}
 
1581
 
 
1582
void closeDialogs(QWidget *w)
 
1583
{
 
1584
        // close qmessagebox?
 
1585
        const QObjectList *list = w->children();
 
1586
        if(list) {
 
1587
                QObjectListIt it(*list);
 
1588
                QPtrList<QDialog> dialogs;
 
1589
                for(QObject *o; (o = it.current()); ++it) {
 
1590
                        if(o->inherits("QDialog"))
 
1591
                                dialogs.append((QDialog *)o);
 
1592
                }
 
1593
                QPtrListIterator<QDialog> dit(dialogs);
 
1594
                for(QDialog *w; (w = dit.current()); ++dit)
 
1595
                        w->close();
 
1596
        }
 
1597
}
 
1598
 
 
1599
QString enc822jid(const QString &s)
 
1600
{
 
1601
        QString out;
 
1602
        for(int n = 0; n < (int)s.length(); ++n) {
 
1603
                if(s[n] == '\\' || s[n] == '<' || s[n] == '>') {
 
1604
                        QString hex;
 
1605
                        hex.sprintf("\\x%02X", (unsigned char )s[n]);
 
1606
                        out.append(hex);
 
1607
                }
 
1608
                else
 
1609
                        out += s[n];
 
1610
        }
 
1611
        return out;
 
1612
}
 
1613
 
 
1614
QString dec822jid(const QString &s)
 
1615
{
 
1616
        QString out;
 
1617
        for(int n = 0; n < (int)s.length(); ++n) {
 
1618
                if(s[n] == '\\' && n + 3 < (int)s.length()) {
 
1619
                        int x = n + 1;
 
1620
                        n += 3;
 
1621
                        if(s[x] != 'x')
 
1622
                                continue;
 
1623
                        ushort val = 0;
 
1624
                        val += hexChar2int(s[x+1])*16;
 
1625
                        val += hexChar2int(s[x+2]);
 
1626
                        QChar c(val);
 
1627
                        out += c;
 
1628
                }
 
1629
                else
 
1630
                        out += s[n];
 
1631
        }
 
1632
        return out;
 
1633
}
 
1634
 
 
1635
#ifdef Q_WS_X11
 
1636
#include<X11/Xlib.h>
 
1637
#include<X11/Xutil.h> // needed for WM_CLASS hinting
 
1638
 
 
1639
void x11wmClass(Display *dsp, WId wid, QString resName)
 
1640
{
 
1641
        char app_name[] = "psi";
 
1642
 
 
1643
        //Display *dsp = x11Display();                  // get the display
 
1644
        //WId win = winId();                            // get the window
 
1645
        XClassHint classhint;                           // class hints
 
1646
        classhint.res_name = (char *)resName.latin1();  // res_name
 
1647
        classhint.res_class = app_name;                 // res_class
 
1648
        XSetClassHint(dsp, wid, &classhint);            // set the class hints
 
1649
}
 
1650
 
 
1651
//>>>-- Nathaniel Gray -- Caltech Computer Science ------>
 
1652
//>>>-- Mojave Project -- http://mojave.cs.caltech.edu -->
 
1653
// Copied from http://www.nedit.org/archives/discuss/2002-Aug/0386.html
 
1654
 
 
1655
// Helper function
 
1656
bool getCardinal32Prop(Display *display, Window win, char *propName, long *value)
 
1657
{
 
1658
        Atom nameAtom, typeAtom, actual_type_return;
 
1659
        int actual_format_return, result;
 
1660
        unsigned long nitems_return, bytes_after_return;
 
1661
        long *result_array=NULL;
 
1662
 
 
1663
        nameAtom = XInternAtom(display, propName, False);
 
1664
        typeAtom = XInternAtom(display, "CARDINAL", False);
 
1665
        if (nameAtom == None || typeAtom == None) {
 
1666
                //qDebug("Atoms not interned!");
 
1667
                return false;
 
1668
        }
 
1669
 
 
1670
 
 
1671
        // Try to get the property
 
1672
        result = XGetWindowProperty(display, win, nameAtom, 0, 1, False,
 
1673
                typeAtom, &actual_type_return, &actual_format_return,
 
1674
                &nitems_return, &bytes_after_return,
 
1675
                (unsigned char **)&result_array);
 
1676
 
 
1677
        if( result != Success ) {
 
1678
                //qDebug("not Success");
 
1679
                return false;
 
1680
        }
 
1681
        if( actual_type_return == None || actual_format_return == 0 ) {
 
1682
                //qDebug("Prop not found");
 
1683
                return false;
 
1684
        }
 
1685
        if( actual_type_return != typeAtom ) {
 
1686
                //qDebug("Wrong type atom");
 
1687
        }
 
1688
        *value = result_array[0];
 
1689
        XFree(result_array);
 
1690
        return true;
 
1691
}
 
1692
 
 
1693
 
 
1694
// Get the desktop number that a window is on
 
1695
bool desktopOfWindow(Window *window, long *desktop)
 
1696
{
 
1697
        Display *display = qt_xdisplay();
 
1698
        bool result = getCardinal32Prop(display, *window, (char *)"_NET_WM_DESKTOP", desktop);
 
1699
        //if( result )
 
1700
        //      qDebug("Desktop: " + QString::number(*desktop));
 
1701
        return result;
 
1702
}
 
1703
 
 
1704
 
 
1705
// Get the current desktop the WM is displaying
 
1706
bool currentDesktop(long *desktop)
 
1707
{
 
1708
        Window rootWin;
 
1709
        Display *display = qt_xdisplay();;
 
1710
        bool result;
 
1711
 
 
1712
        rootWin = RootWindow(qt_xdisplay(), XDefaultScreen(qt_xdisplay()));
 
1713
        result = getCardinal32Prop(display, rootWin, (char *)"_NET_CURRENT_DESKTOP", desktop);
 
1714
        //if( result )
 
1715
        //      qDebug("Current Desktop: " + QString::number(*desktop));
 
1716
        return result;
 
1717
}
 
1718
#endif
 
1719
 
 
1720
void bringToFront(QWidget *w, bool)
 
1721
{
 
1722
#ifdef Q_WS_X11
 
1723
        // If we're not on the current desktop, do the hide/show trick
 
1724
        long dsk, curr_dsk;
 
1725
        Window win = w->winId();
 
1726
        if(desktopOfWindow(&win, &dsk) && currentDesktop(&curr_dsk)) {
 
1727
                if(dsk != curr_dsk) {
 
1728
                        w->hide();
 
1729
                        //qApp->processEvents();
 
1730
                }
 
1731
        }
 
1732
 
 
1733
        // FIXME: multi-desktop hacks for Win and Mac required
 
1734
#endif
 
1735
 
 
1736
        w->show();
 
1737
        if(w->isMinimized()) {
 
1738
                //w->hide();
 
1739
                if(w->isMaximized())
 
1740
                        w->showMaximized();
 
1741
                else
 
1742
                        w->showNormal();
 
1743
        }
 
1744
        //if(grabFocus)
 
1745
        //      w->setActiveWindow();
 
1746
        w->raise();
 
1747
        w->setActiveWindow();
 
1748
}
 
1749
 
 
1750
bool operator!=(const QMap<QString, QString> &m1, const QMap<QString, QString> &m2)
 
1751
{
 
1752
        if ( m1.size() != m2.size() )
 
1753
                return true;
 
1754
 
 
1755
        QMap<QString, QString>::ConstIterator it = m1.begin(), it2;
 
1756
        for ( ; it != m1.end(); ++it) {
 
1757
                it2 = m2.find( it.key() );
 
1758
                if ( it2 == m2.end() )
 
1759
                        return true;
 
1760
                if ( it.data() != it2.data() )
 
1761
                        return true;
 
1762
        }
 
1763
 
 
1764
        return false;
 
1765
}
 
1766