source: psi/trunk/src/userlist.cpp

Last change on this file was 2, checked in by dmik, 19 years ago

Imported original Psi 0.10 sources from Affinix

File size: 12.9 KB
Line 
1/*
2 * userlist.cpp - high-level roster
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 library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include"userlist.h"
22
23#include"im.h"
24#include"openpgp.h"
25#include"common.h"
26#include"contactview.h"
27#include"avatars.h"
28
29using namespace XMPP;
30
31static QString dot_truncate(const QString &in, int clip)
32{
33 if((int)in.length() <= clip)
34 return in;
35 QString s = in;
36 s.truncate(clip);
37 s += "...";
38 return s;
39}
40
41//----------------------------------------------------------------------------
42// UserResource
43//----------------------------------------------------------------------------
44UserResource::UserResource()
45:Resource()
46{
47}
48
49UserResource::UserResource(const Resource &r)
50{
51 setResource(r);
52}
53
54UserResource::~UserResource()
55{
56}
57
58void UserResource::setResource(const Resource &r)
59{
60 setName(r.name());
61 setStatus(r.status());
62}
63
64const QString & UserResource::versionString() const
65{
66 return v_ver;
67}
68
69const QString & UserResource::clientName() const
70{
71 return v_clientName;
72}
73
74const QString & UserResource::clientVersion() const
75{
76 return v_clientVersion;
77}
78
79const QString & UserResource::clientOS() const
80{
81 return v_clientOS;
82}
83
84void UserResource::setClient(const QString &name, const QString& version, const QString& os)
85{
86 v_clientName = name;
87 v_clientVersion = version;
88 v_clientOS = os;
89 v_ver = v_clientName + " " + v_clientVersion;
90 if ( !v_clientOS.isEmpty() )
91 v_ver += " / " + v_clientOS;
92}
93
94const QString & UserResource::publicKeyID() const
95{
96 return v_keyID;
97}
98
99int UserResource::pgpVerifyStatus() const
100{
101 return v_pgpVerifyStatus;
102}
103
104QDateTime UserResource::sigTimestamp() const
105{
106 return sigts;
107}
108
109void UserResource::setPublicKeyID(const QString &s)
110{
111 v_keyID = s;
112}
113
114void UserResource::setPGPVerifyStatus(int x)
115{
116 v_pgpVerifyStatus = x;
117}
118
119void UserResource::setSigTimestamp(const QDateTime &ts)
120{
121 sigts = ts;
122}
123
124bool operator<(const UserResource &r1, const UserResource &r2)
125{
126 return r1.priority() > r2.priority();
127}
128
129bool operator<=(const UserResource &r1, const UserResource &r2)
130{
131 return r1.priority() >= r2.priority();
132}
133
134bool operator==(const UserResource &r1, const UserResource &r2)
135{
136 return r1.priority() == r2.priority();
137}
138
139bool operator>(const UserResource &r1, const UserResource &r2)
140{
141 return r1.priority() < r2.priority();
142}
143
144bool operator>=(const UserResource &r1, const UserResource &r2)
145{
146 return r1.priority() <= r2.priority();
147}
148
149
150//----------------------------------------------------------------------------
151// UserResourceList
152//----------------------------------------------------------------------------
153UserResourceList::UserResourceList()
154:QValueList<UserResource>()
155{
156}
157
158UserResourceList::~UserResourceList()
159{
160}
161
162UserResourceList::Iterator UserResourceList::find(const QString & _find)
163{
164 for(UserResourceList::Iterator it = begin(); it != end(); ++it) {
165 if((*it).name() == _find)
166 return it;
167 }
168
169 return end();
170}
171
172UserResourceList::Iterator UserResourceList::priority()
173{
174 UserResourceList::Iterator highest = end();
175
176 for(UserResourceList::Iterator it = begin(); it != end(); ++it) {
177 if(highest == end() || (*it).priority() > (*highest).priority())
178 highest = it;
179 }
180
181 return highest;
182}
183
184UserResourceList::ConstIterator UserResourceList::find(const QString & _find) const
185{
186 for(UserResourceList::ConstIterator it = begin(); it != end(); ++it) {
187 if((*it).name() == _find)
188 return it;
189 }
190
191 return end();
192}
193
194UserResourceList::ConstIterator UserResourceList::priority() const
195{
196 UserResourceList::ConstIterator highest = end();
197
198 for(UserResourceList::ConstIterator it = begin(); it != end(); ++it) {
199 if(highest == end() || (*it).priority() > (*highest).priority())
200 highest = it;
201 }
202
203 return highest;
204}
205
206void UserResourceList::sort()
207{
208 qHeapSort(*this);
209}
210
211
212//----------------------------------------------------------------------------
213// UserListItem
214//----------------------------------------------------------------------------
215UserListItem::UserListItem(bool self)
216{
217 v_inList = false;
218 v_self = self;
219 v_private = false;
220 lastmsgtype = -1;
221 v_avatarFactory = 0;
222}
223
224UserListItem::~UserListItem()
225{
226}
227
228bool UserListItem::inList() const
229{
230 return v_inList;
231}
232
233void UserListItem::setJid(const Jid &j)
234{
235 LiveRosterItem::setJid(j);
236
237 int n = jid().full().find('@');
238 if(n == -1)
239 v_isTransport = true;
240 else
241 v_isTransport = false;
242}
243
244bool UserListItem::isTransport() const
245{
246 return v_isTransport;
247}
248
249bool UserListItem::isAvailable() const
250{
251 return !v_url.isEmpty();
252}
253
254bool UserListItem::isHidden() const
255{
256 return groups().contains(ContactView::tr("Hidden"));
257}
258
259bool UserListItem::isAway() const
260{
261 int status;
262 if(!isAvailable())
263 status = STATUS_OFFLINE;
264 else
265 status = makeSTATUS((*userResourceList().priority()).status());
266
267 if(status == STATUS_AWAY || status == STATUS_XA || status == STATUS_DND)
268 return true;
269 else
270 return false;
271}
272
273QDateTime UserListItem::lastAvailable() const
274{
275 return v_t;
276}
277
278int UserListItem::lastMessageType() const
279{
280 return lastmsgtype;
281}
282
283void UserListItem::setLastMessageType(const int mtype)
284{
285// printf("setting message type to %i\n", mtype);
286 lastmsgtype = mtype;
287}
288
289const QString & UserListItem::presenceError() const
290{
291 return v_perr;
292}
293
294bool UserListItem::isSelf() const
295{
296 return v_self;
297}
298
299void UserListItem::setInList(bool b)
300{
301 v_inList = b;
302}
303
304void UserListItem::setLastAvailable(const QDateTime &t)
305{
306 v_t = t;
307}
308
309void UserListItem::setPresenceError(const QString &e)
310{
311 v_perr = e;
312}
313
314UserResourceList & UserListItem::userResourceList()
315{
316 return v_url;
317}
318
319UserResourceList::Iterator UserListItem::priority()
320{
321 return v_url.priority();
322}
323
324const UserResourceList & UserListItem::userResourceList() const
325{
326 return v_url;
327}
328
329UserResourceList::ConstIterator UserListItem::priority() const
330{
331 return v_url.priority();
332}
333
334QString UserListItem::makeTip(bool trim, bool doLinkify) const
335{
336 return "<qt>" + makeBareTip(trim,doLinkify) + "</qt>";
337}
338
339QString UserListItem::makeBareTip(bool trim, bool doLinkify) const
340{
341 QString str;
342
343#ifdef AVATARS
344 str += "<table cellspacing=\"0\"><tr>";
345 if (option.avatarsEnabled) {
346 QString client;
347 QString res;
348 if (!userResourceList().isEmpty()) {
349 client = (*userResourceList().priority()).clientName();
350 res = (*userResourceList().priority()).name();
351 }
352 if (avatarFactory()) {
353 QPixmap p = avatarFactory()->getAvatar(jid().withResource(res),client);
354 if (!p.isNull()) {
355 str += "<td align=\"center\">";
356 QMimeSourceFactory::defaultFactory()->setPixmap("avatar.png",p);
357 str += "<img src=\"avatar.png\">";
358 str += "</td>";
359 }
360 }
361 }
362
363 str += "<td>";
364#endif
365
366 QString nick = jidnick(jid().full(), name());
367 str += QString("<nobr>%1</nobr>").arg(expandEntities(nick));
368 if(jid().full() != nick)
369 str += QString("<br>[%1]").arg(expandEntities(jid().full()));
370
371 // subscription
372 if(!v_self)
373 str += QString("<br><nobr>") + QObject::tr("Subscription") + ": " + subscription().toString() + "</nobr>";
374
375 if(!v_keyID.isEmpty())
376 str += QString("<br><nobr>") + QObject::tr("OpenPGP") + ": " + v_keyID.right(8) + "</nobr>";
377
378 // resources
379 if(!userResourceList().isEmpty()) {
380 UserResourceList srl = userResourceList();
381 srl.sort();
382
383 for(UserResourceList::ConstIterator rit = srl.begin(); rit != srl.end(); ++rit) {
384 const UserResource &r = *rit;
385 QString name;
386 if(!r.name().isEmpty())
387 name = r.name();
388 else
389 name = QObject::tr("[blank]");
390
391 int status = makeSTATUS(r.status());
392 QString istr = "status/offline";
393 if(status == STATUS_ONLINE)
394 istr = "status/online";
395 else if(status == STATUS_AWAY)
396 istr = "status/away";
397 else if(status == STATUS_XA)
398 istr = "status/xa";
399 else if(status == STATUS_DND)
400 istr = "status/dnd";
401 else if(status == STATUS_CHAT)
402 istr = "status/chat";
403 else if(status == STATUS_INVISIBLE)
404 istr = "status/invisible"; //this shouldn't happen
405
406 QString imgTag = "icon name"; // or 'img src' if appropriate QMimeSourceFactory is installed. but mblsha noticed that QMimeSourceFactory unloads sometimes
407 QString secstr;
408 if(isSecure(r.name()))
409 secstr += QString(" <%1=\"psi/cryptoYes\">").arg(imgTag);
410 str += QString("<br><nobr>") + QString("<%1=\"%1\"> ").arg(imgTag).arg(istr) + QString("<b>%1</b> ").arg(expandEntities(name)) + QString("(%1)").arg(r.priority()) + secstr + "</nobr>";
411
412 if(!r.publicKeyID().isEmpty()) {
413 int v = r.pgpVerifyStatus();
414 if(v == OpenPGP::VerifyGood || v == OpenPGP::VerifyNoKey || v == OpenPGP::VerifyBad) {
415 if(v == OpenPGP::VerifyGood) {
416 QString d = r.sigTimestamp().toString(Qt::TextDate);
417 str += QString("<br><nobr>") + QObject::tr("Signed") + " @ " + "<font color=\"#2A993B\">" + d + "</font>";
418 }
419 else if(v == OpenPGP::VerifyNoKey) {
420 QString d = r.sigTimestamp().toString(Qt::TextDate);
421 str += QString("<br><nobr>") + QObject::tr("Signed") + " @ " + d;
422 }
423 else if(v == OpenPGP::VerifyBad) {
424 str += QString("<br><nobr>") + "<font color=\"#810000\">" + QObject::tr("Bad signature") + "</font>";
425 }
426
427 if(v_keyID != r.publicKeyID())
428 str += QString(" [%1]").arg(r.publicKeyID().right(8));
429 str += "</nobr>";
430 }
431 }
432
433 // last status
434 if(r.status().timeStamp().isValid()) {
435 QString d = r.status().timeStamp().toString(Qt::TextDate);
436 str += QString("<br><nobr>") + QObject::tr("Last Status") + " @ " + d + "</nobr>";
437 }
438
439 // gabber music
440 if(!r.status().songTitle().isEmpty()) {
441 QString s = r.status().songTitle();
442 if(trim)
443 s = dot_truncate(s, 80);
444 s = expandEntities(s);
445 str += QString("<br><nobr>") + QObject::tr("Listening to") + QString(": %1").arg(s) + "</nobr>";
446 }
447
448 // client
449 if(!r.versionString().isEmpty()) {
450 QString ver = r.versionString();
451 if(trim)
452 ver = dot_truncate(ver, 80);
453 ver = expandEntities(ver);
454 str += QString("<br><nobr>") + QObject::tr("Using") + QString(": %1").arg(ver) + "</nobr>";
455 }
456
457 // status message
458 QString s = r.status().status();
459 if(!s.isEmpty()) {
460 QString head = QObject::tr("Status Message");
461 if(trim)
462 s = plain2rich(clipStatus(s, 200, 12));
463 else
464 s = plain2rich(s);
465 if ( doLinkify )
466 s = linkify(s);
467 if( option.useEmoticons && !doLinkify )
468 s = emoticonify(s);
469 str += QString("<br><nobr><u>%1</u></nobr><br>%2").arg(head).arg(s);
470 }
471 }
472 }
473 else {
474 // last available
475 if(!lastAvailable().isNull()) {
476 QString d = lastAvailable().toString(Qt::TextDate);
477 str += QString("<br><nobr>") + QObject::tr("Last Available") + " @ " + d + "</nobr>";
478 }
479
480 // presence error
481 if(!v_perr.isEmpty()) {
482 str += QString("<br><nobr>") + QObject::tr("Presence Error") + QString(": %1").arg(expandEntities(v_perr)) + "</nobr>";
483 }
484
485 // status message
486 QString s = lastUnavailableStatus().status();
487 if(!s.isEmpty()) {
488 QString head = QObject::tr("Last Status Message");
489 if(trim)
490 s = plain2rich(clipStatus(s, 200, 12));
491 else {
492 s = plain2rich(clipStatus(s, 200, 12));
493 if ( doLinkify )
494 s = linkify(s);
495 }
496 str += QString("<br><nobr><u>%1</u></nobr><br>%2").arg(head).arg(s);
497 }
498 }
499
500#ifdef AVATARS
501 str += "</td>";
502 str += "</tr></table>";
503#endif
504
505 return str;
506}
507
508QString UserListItem::makeDesc() const
509{
510 return makeTip(false);
511}
512
513bool UserListItem::isPrivate() const
514{
515 return v_private;
516}
517
518void UserListItem::setPrivate(bool b)
519{
520 v_private = b;
521}
522
523bool UserListItem::isSecure(const QString &rname) const
524{
525 for(QStringList::ConstIterator it = secList.begin(); it != secList.end(); ++it) {
526 if(*it == rname)
527 return true;
528 }
529 return false;
530}
531
532void UserListItem::setSecure(const QString &rname, bool b)
533{
534 for(QStringList::Iterator it = secList.begin(); it != secList.end(); ++it) {
535 if(*it == rname) {
536 if(!b)
537 secList.remove(it);
538 return;
539 }
540 }
541 if(b)
542 secList.append(rname);
543}
544
545const QString & UserListItem::publicKeyID() const
546{
547 return v_keyID;
548}
549
550void UserListItem::setPublicKeyID(const QString &k)
551{
552 v_keyID = k;
553}
554
555AvatarFactory* UserListItem::avatarFactory() const
556{
557 return v_avatarFactory;
558}
559
560void UserListItem::setAvatarFactory(AvatarFactory* av)
561{
562 v_avatarFactory = av;
563}
564
565
566
567//----------------------------------------------------------------------------
568// UserList
569//----------------------------------------------------------------------------
570UserList::UserList()
571{
572}
573
574UserList::~UserList()
575{
576}
577
578UserListItem *UserList::find(const XMPP::Jid &j)
579{
580 UserListIt it(*this);
581 for(UserListItem *i; (i = it.current()); ++it) {
582 if(i->jid().compare(j))
583 return i;
584 }
585 return 0;
586}
587
Note: See TracBrowser for help on using the repository browser.