fix GNUTLS connection
[centerim.git] / src / icqcontacts.cc
blobc90294d13e4fb988d5e094a75efe0d3520a31ead
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 icqcontact *c;
141 imcontact cinfo;
142 protocolname pname;
144 // empty();
146 if(d = opendir(conf->getdirname().c_str())) {
147 while(ent = readdir(d)) {
148 dname = ent->d_name;
149 tuname = conf->getdirname() + dname;
151 if(!stat(tuname.c_str(), &st))
152 if(S_ISDIR(st.st_mode)) {
153 c = 0;
154 pname = conf->getprotocolbyletter(dname[0]);
156 switch(pname) {
157 case icq:
158 c = new icqcontact(imcontact(atol(dname.c_str()), pname));
159 break;
161 case infocard:
162 case rss:
163 case gadu:
164 c = new icqcontact(imcontact(atol(dname.c_str()+1), pname));
165 break;
167 case protocolname_size:
168 // Strange dir, doesn't belong to any of the
169 // supported protocols.
170 break;
172 case jabber:
173 if(get(imcontact(dname.substr(1), pname)))
174 continue;
176 // Doesn't make sense, transport contacts (and JIDs generally) don't need to contain @
177 /*if(dname.substr(1).find("@") == -1) {
178 string oldname = conf->getdirname() + dname;
179 string ndname = oldname + "@jabber.com";
181 if(!access(ndname.c_str(), F_OK))
182 rename(ndname.c_str(), (conf->getdirname() + "_" + dname).c_str());
184 rename(oldname.c_str(), ndname.c_str());
185 dname = justfname(ndname);
188 default:
189 c = new icqcontact(imcontact(dname.substr(1), pname));
190 c->setnick(dname.substr(1));
191 break;
194 if(c) {
195 if(!get(c->getdesc())) add(c);
196 else delete c;
201 closedir(d);
204 if(!get(contactroot)) {
205 add(new icqcontact(contactroot));
209 void icqcontacts::save(bool removenil) {
210 int i;
212 for(i = 0; i < count; i++) {
213 icqcontact *c = (icqcontact *) at(i);
215 if(c->inlist()) c->save(); else
216 if(removenil && !c->hasevents()) {
217 string fname = c->getdirname() + "offline";
218 if(access(fname.c_str(), F_OK)) c->remove();
223 void icqcontacts::remove(const imcontact &cinfo) {
224 int i;
225 icqcontact *c;
227 for(i = 0; i < count; i++) {
228 c = (icqcontact *) at(i);
230 if(cinfo == c->getdesc()) {
231 c->remove();
232 linkedlist::remove(i);
233 break;
238 icqcontact *icqcontacts::get(const imcontact &cinfo) {
239 int i;
240 icqcontact *c;
242 for(i = 0; i < count; i++) {
243 c = (icqcontact *) at(i);
245 if(c->getdesc() == cinfo)
246 return (icqcontact *) at(i);
249 return 0;
252 void icqcontacts::setsortmode(icqconf::sortmode smode){
253 sort_order = sortmodes+smode;
256 int icqcontacts::clistsort(void *p1, void *p2) {
257 icqcontact *c1 = (icqcontact *) p1, *c2 = (icqcontact *) p2;
258 static char *sorder = SORT_CONTACTS;
259 char s1, s2;
260 bool makegroup;
262 s1 = sort_order->sortstatus(*c1);
263 s2 = sort_order->sortstatus(*c2);
265 switch(conf->getgroupmode()) {
266 case icqconf::group1:
267 makegroup = true;
268 break;
269 case icqconf::group2:
270 makegroup = (s1 != '_' && s2 != '_') || (s1 == '_' && s2 == '_');
271 break;
272 default:
273 makegroup = false;
274 break;
277 if(makegroup)
278 if(!strchr("!N", s1) && !strchr("!N", s2))
279 if(!c1->hasevents() && !c2->hasevents()) {
280 if(c1->getgroupid() > c2->getgroupid()) return -1; else
281 if(c1->getgroupid() < c2->getgroupid()) return 1;
284 if(s1 == s2) {
285 return -sort_order->compare(*c1,*c2);
286 } else {
287 if(strchr(sorder, s1) > strchr(sorder, s2)) return -1; else return 1;
291 void icqcontacts::order() {
292 sort(&clistsort);
295 void icqcontacts::rearrange() {
296 int i;
297 icqcontact *c;
299 for(i = 0; i < count; i++) {
300 c = (icqcontact *) at(i);
301 if(::find(groups.begin(), groups.end(), c->getgroupid()) == groups.end()) {
302 c->setgroupid(1);
307 void icqcontacts::setoffline(protocolname pname) {
308 int i;
309 icqcontact *c;
311 for(i = 0; i < count; i++) {
312 c = (icqcontact *) at(i);
313 if(c->getdesc().pname == pname)
314 c->setstatus(offline);
318 icqcontact *icqcontacts::getmobile(const string &anumber) {
319 int i, pos;
320 icqcontact *c;
321 string cnumber, number;
323 if(!anumber.empty()) {
324 number = anumber;
326 while((pos = number.find_first_not_of("0123456789")) != -1)
327 number.erase(pos, 1);
329 for(i = 0; i < count; i++) {
330 c = (icqcontact *) at(i);
331 cnumber = c->getbasicinfo().cellular;
333 while((pos = cnumber.find_first_not_of("0123456789")) != -1)
334 cnumber.erase(pos, 1);
336 if(number == cnumber)
337 return c;
341 return 0;
344 icqcontact *icqcontacts::getemail(const string &aemail) {
345 int i;
346 icqcontact *c;
348 if(!aemail.empty()) {
349 for(i = 0; i < count; i++) {
350 c = (icqcontact *) at(i);
352 if(aemail == c->getbasicinfo().email)
353 return c;
357 return 0;
360 void icqcontacts::updateEntry(const imcontact &ic, const string &groupname) {
361 int gid;
362 icqcontact *c = get(ic);
363 if(!c) c = addnew(ic, false);
365 if(conf->getgroupmode() != icqconf::nogroups && !groupname.empty()) {
366 vector<icqgroup>::iterator ig = ::find(groups.begin(), groups.end(), groupname);
368 if(ig != groups.end()) gid = ig->getid();
369 else gid = groups.add(groupname);
371 } else {
372 gid = 1;
376 c->setgroupid(gid);