Merge branch 'main-master'
[centerim/funkyfish.git] / src / icqcontacts.cc
blobc62607ae199780a99bfec27adaf839c0f35e8930
1 /*
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
21 * USA
25 #include "icqcontacts.h"
26 #include "icqmlist.h"
27 #include "icqconf.h"
28 #include "icqgroups.h"
29 #include "abstracthook.h"
33 * SORT_CONTACTS
35 * o Online
36 * f Free for chat
37 * i Invisible
38 * d Do not disturb
39 * c Occupied
40 * a Away
41 * n N/A
43 * _ Offline
44 * ! Not in list
45 * N Non-ICQ
46 * # Unread
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() ? '#' : \
56 !c.inlist() ? '!' : \
57 c.getstatus() == invisible ? 'o' : \
58 c.getstatus() == freeforchat ? 'o' : \
59 c.getshortstatus() \
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;
81 delete c;
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);
94 switch(cinfo.pname) {
95 case icq:
96 case gadu:
97 c->setnick(i2str(cinfo.uin));
98 c->setdispnick(i2str(cinfo.uin));
99 break;
101 default:
102 c->setnick(cinfo.nickname);
103 c->setdispnick(cinfo.nickname);
104 break;
107 icqcontact::basicinfo bi = c->getbasicinfo();
108 bi.requiresauth = bi.authawait = reqauth;
109 c->setbasicinfo(bi);
111 if(agroupid) {
112 c->setgroupid(agroupid, false);
115 c->save();
116 add(c);
118 if(c)
119 if(notinlist) {
120 c->excludefromlist();
121 abstracthook &h = gethook(cinfo.pname);
123 if(h.getCapabs().count(hookcapab::cltemporary))
124 h.sendnewuser(cinfo);
126 h.requestinfo(cinfo);
128 } else {
129 c->includeintolist();
132 return c;
135 void icqcontacts::load() {
136 string tuname, fname, dname;
137 struct dirent *ent;
138 struct stat st;
139 DIR *d;
140 FILE *f;
141 icqcontact *c;
142 imcontact cinfo;
143 protocolname pname;
145 // empty();
147 if(d = opendir(conf.getdirname().c_str())) {
148 while(ent = readdir(d)) {
149 dname = ent->d_name;
150 tuname = conf.getdirname() + dname;
152 if(!stat(tuname.c_str(), &st))
153 if(S_ISDIR(st.st_mode)) {
154 c = 0;
155 pname = conf.getprotocolbyletter(dname[0]);
157 switch(pname) {
158 case icq:
159 c = new icqcontact(imcontact(atol(dname.c_str()), pname));
160 break;
162 case infocard:
163 case rss:
164 case gadu:
165 c = new icqcontact(imcontact(atol(dname.c_str()+1), pname));
166 break;
168 case protocolname_size:
169 // Strange dir, doesn't belong to any of the
170 // supported protocols.
171 break;
173 case jabber:
174 if(get(imcontact(dname.substr(1), pname)))
175 continue;
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);
189 default:
190 c = new icqcontact(imcontact(dname.substr(1), pname));
191 c->setnick(dname.substr(1));
192 break;
195 if(c) {
196 if(!get(c->getdesc())) add(c);
197 else delete c;
202 closedir(d);
205 if(!get(contactroot)) {
206 add(new icqcontact(contactroot));
210 void icqcontacts::save(bool removenil) {
211 int i;
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) {
225 int i;
226 icqcontact *c;
228 for(i = 0; i < count; i++) {
229 c = (icqcontact *) at(i);
231 if(cinfo == c->getdesc()) {
232 c->remove();
233 linkedlist::remove(i);
234 break;
239 icqcontact *icqcontacts::get(const imcontact &cinfo) {
240 int i;
241 icqcontact *c;
243 for(i = 0; i < count; i++) {
244 c = (icqcontact *) at(i);
246 if(c->getdesc() == cinfo)
247 return (icqcontact *) at(i);
250 return 0;
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;
260 char s1, s2;
261 bool makegroup;
263 s1 = sort_order->sortstatus(*c1);
264 s2 = sort_order->sortstatus(*c2);
266 switch(conf.getgroupmode()) {
267 case icqconf::group1:
268 makegroup = true;
269 break;
270 case icqconf::group2:
271 makegroup = (s1 != '_' && s2 != '_') || (s1 == '_' && s2 == '_');
272 break;
273 default:
274 makegroup = false;
275 break;
278 if(makegroup)
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;
285 if(s1 == s2) {
286 return -sort_order->compare(*c1,*c2);
287 } else {
288 if(strchr(sorder, s1) > strchr(sorder, s2)) return -1; else return 1;
292 void icqcontacts::order() {
293 sort(&clistsort);
296 void icqcontacts::rearrange() {
297 int i;
298 icqcontact *c;
300 for(i = 0; i < count; i++) {
301 c = (icqcontact *) at(i);
302 if(::find(groups.begin(), groups.end(), c->getgroupid()) == groups.end()) {
303 c->setgroupid(1);
308 void icqcontacts::setoffline(protocolname pname) {
309 int i;
310 icqcontact *c;
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) {
320 int i, pos;
321 icqcontact *c;
322 string cnumber, number;
324 if(!anumber.empty()) {
325 number = anumber;
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)
338 return c;
342 return 0;
345 icqcontact *icqcontacts::getemail(const string &aemail) {
346 int i;
347 icqcontact *c;
349 if(!aemail.empty()) {
350 for(i = 0; i < count; i++) {
351 c = (icqcontact *) at(i);
353 if(aemail == c->getbasicinfo().email)
354 return c;
358 return 0;
361 void icqcontacts::updateEntry(const imcontact &ic, const string &groupname) {
362 int gid;
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);
372 } else {
373 gid = 1;
377 c->setgroupid(gid);