3 * centerim contact list class
4 * $Id: icqcontacts.cc,v 1.54 2004/07/08 23:52:48 konst Exp $
6 * Copyright (C) 2001-2004 by Konstantin Klyagin <k@thekonst.net>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25 #include "icqcontacts.h"
28 #include "icqgroups.h"
29 #include "abstracthook.h"
50 #define SORT_CONTACTS "#odcanl_!N"
52 // this is the original status sort, where the contacts
53 // get sorted by status
54 static char getsortstatus1(const icqcontact
& c
){
55 return c
.hasevents() ? '#' : \
57 c
.getstatus() == invisible
? 'o' : \
58 c
.getstatus() == freeforchat
? 'o' : \
63 // this is the modified status sort, where the contacts
64 // don't get sorted by status (only by name or whatever)
65 static char getsortstatus2(const icqcontact
& c
){
66 return c
.hasevents() ? '#' : !c
.inlist() ? '!' : 'o';
69 static icqcontacts_sort sortmodes
[icqconf::sort_by_nb_of_sorts
] = {
70 {getsortstatus1
, icqcontact::compare1
}, // sort_by_status_and_activity
71 {getsortstatus1
, icqcontact::compare2
}, // sort_by_status_and_name
72 {getsortstatus2
, icqcontact::compare1
}, // sort_by_activity
73 {getsortstatus2
, icqcontact::compare2
} // sort_by_name
76 icqcontacts_sort
*icqcontacts::sort_order
= &sortmodes
[icqconf::sort_by_status_and_activity
];
78 /* Function used to delete icqcontact when removed from the list */
79 static void deletecontact(void *contact
){
80 icqcontact
*c
= (icqcontact
*)contact
;
84 icqcontacts::icqcontacts() {
85 freeitem
= deletecontact
;
88 icqcontacts::~icqcontacts() {
91 icqcontact
*icqcontacts::addnew(const imcontact
&cinfo
, bool notinlist
, int agroupid
, bool reqauth
) {
92 icqcontact
*c
= new icqcontact(cinfo
);
97 c
->setnick(i2str(cinfo
.uin
));
98 c
->setdispnick(i2str(cinfo
.uin
));
102 c
->setnick(cinfo
.nickname
);
103 c
->setdispnick(cinfo
.nickname
);
107 icqcontact::basicinfo bi
= c
->getbasicinfo();
108 bi
.requiresauth
= bi
.authawait
= reqauth
;
112 c
->setgroupid(agroupid
, false);
120 c
->excludefromlist();
121 abstracthook
&h
= gethook(cinfo
.pname
);
123 if(h
.getCapabs().count(hookcapab::cltemporary
))
124 h
.sendnewuser(cinfo
);
126 h
.requestinfo(cinfo
);
129 c
->includeintolist();
135 void icqcontacts::load() {
136 string tuname
, fname
, dname
;
147 if(d
= opendir(conf
.getdirname().c_str())) {
148 while(ent
= readdir(d
)) {
150 tuname
= conf
.getdirname() + dname
;
152 if(!stat(tuname
.c_str(), &st
))
153 if(S_ISDIR(st
.st_mode
)) {
155 pname
= conf
.getprotocolbyletter(dname
[0]);
159 c
= new icqcontact(imcontact(atol(dname
.c_str()), pname
));
165 c
= new icqcontact(imcontact(atol(dname
.c_str()+1), pname
));
168 case protocolname_size
:
169 // Strange dir, doesn't belong to any of the
170 // supported protocols.
174 if(get(imcontact(dname
.substr(1), pname
)))
177 // Doesn't make sense, transport contacts (and JIDs generally) don't need to contain @
178 /*if(dname.substr(1).find("@") == -1) {
179 string oldname = conf.getdirname() + dname;
180 string ndname = oldname + "@jabber.com";
182 if(!access(ndname.c_str(), F_OK))
183 rename(ndname.c_str(), (conf.getdirname() + "_" + dname).c_str());
185 rename(oldname.c_str(), ndname.c_str());
186 dname = justfname(ndname);
190 c
= new icqcontact(imcontact(dname
.substr(1), pname
));
191 c
->setnick(dname
.substr(1));
196 if(!get(c
->getdesc())) add(c
);
205 if(!get(contactroot
)) {
206 add(new icqcontact(contactroot
));
210 void icqcontacts::save(bool removenil
) {
213 for(i
= 0; i
< count
; i
++) {
214 icqcontact
*c
= (icqcontact
*) at(i
);
216 if(c
->inlist()) c
->save(); else
217 if(removenil
&& !c
->hasevents()) {
218 string fname
= c
->getdirname() + "offline";
219 if(access(fname
.c_str(), F_OK
)) c
->remove();
224 void icqcontacts::remove(const imcontact
&cinfo
) {
228 for(i
= 0; i
< count
; i
++) {
229 c
= (icqcontact
*) at(i
);
231 if(cinfo
== c
->getdesc()) {
233 linkedlist::remove(i
);
239 icqcontact
*icqcontacts::get(const imcontact
&cinfo
) {
243 for(i
= 0; i
< count
; i
++) {
244 c
= (icqcontact
*) at(i
);
246 if(c
->getdesc() == cinfo
)
247 return (icqcontact
*) at(i
);
253 void icqcontacts::setsortmode(icqconf::sortmode smode
){
254 sort_order
= sortmodes
+smode
;
257 int icqcontacts::clistsort(void *p1
, void *p2
) {
258 icqcontact
*c1
= (icqcontact
*) p1
, *c2
= (icqcontact
*) p2
;
259 static char *sorder
= SORT_CONTACTS
;
263 s1
= sort_order
->sortstatus(*c1
);
264 s2
= sort_order
->sortstatus(*c2
);
266 switch(conf
.getgroupmode()) {
267 case icqconf::group1
:
270 case icqconf::group2
:
271 makegroup
= (s1
!= '_' && s2
!= '_') || (s1
== '_' && s2
== '_');
279 if(!strchr("!N", s1
) && !strchr("!N", s2
))
280 if(!c1
->hasevents() && !c2
->hasevents()) {
281 if(c1
->getgroupid() > c2
->getgroupid()) return -1; else
282 if(c1
->getgroupid() < c2
->getgroupid()) return 1;
286 return -sort_order
->compare(*c1
,*c2
);
288 if(strchr(sorder
, s1
) > strchr(sorder
, s2
)) return -1; else return 1;
292 void icqcontacts::order() {
296 void icqcontacts::rearrange() {
300 for(i
= 0; i
< count
; i
++) {
301 c
= (icqcontact
*) at(i
);
302 if(::find(groups
.begin(), groups
.end(), c
->getgroupid()) == groups
.end()) {
308 void icqcontacts::setoffline(protocolname pname
) {
312 for(i
= 0; i
< count
; i
++) {
313 c
= (icqcontact
*) at(i
);
314 if(c
->getdesc().pname
== pname
)
315 c
->setstatus(offline
);
319 icqcontact
*icqcontacts::getmobile(const string
&anumber
) {
322 string cnumber
, number
;
324 if(!anumber
.empty()) {
327 while((pos
= number
.find_first_not_of("0123456789")) != -1)
328 number
.erase(pos
, 1);
330 for(i
= 0; i
< count
; i
++) {
331 c
= (icqcontact
*) at(i
);
332 cnumber
= c
->getbasicinfo().cellular
;
334 while((pos
= cnumber
.find_first_not_of("0123456789")) != -1)
335 cnumber
.erase(pos
, 1);
337 if(number
== cnumber
)
345 icqcontact
*icqcontacts::getemail(const string
&aemail
) {
349 if(!aemail
.empty()) {
350 for(i
= 0; i
< count
; i
++) {
351 c
= (icqcontact
*) at(i
);
353 if(aemail
== c
->getbasicinfo().email
)
361 void icqcontacts::updateEntry(const imcontact
&ic
, const string
&groupname
) {
363 icqcontact
*c
= get(ic
);
364 if(!c
) c
= addnew(ic
, false);
366 if(conf
.getgroupmode() != icqconf::nogroups
&& !groupname
.empty()) {
367 vector
<icqgroup
>::iterator ig
= ::find(groups
.begin(), groups
.end(), groupname
);
369 if(ig
!= groups
.end()) gid
= ig
->getid();
370 else gid
= groups
.add(groupname
);