1 /* 2 * Contact 3 * 4 * Copyright (C) 2001 Barnaby Gray <barnaby@beedesign.co.uk> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #include "Contact.h" 23 24 #include "sstream_fix.h" 25 #include <time.h> 26 #include <ctype.h> 27 28 #include "userinfoconstants.h" 29 #include "Capabilities.h" 30 31 #include "events.h" 32 33 using std::string; 34 using std::ostringstream; 35 using std::istringstream; 36 37 namespace ICQ2000 { 38 39 /** 40 * Do not use this constructor outside the library. 41 * It constructs a contact that is virtual, but doesn't have 42 * an imaginary UIN allocated to it. 43 */ Contact()44 Contact::Contact() 45 : count(0), m_virtualcontact(true), m_uin(nextImaginaryUIN()), m_status(STATUS_OFFLINE), 46 m_invisible(false), m_seqnum(0xffff) 47 { 48 Init(); 49 } 50 Contact(unsigned int uin)51 Contact::Contact(unsigned int uin) 52 : count(0), m_virtualcontact(false), m_uin(uin), m_status(STATUS_OFFLINE), 53 m_invisible(false), m_capabilities( new Capabilities() ), m_seqnum(0xffff) 54 { 55 m_main_home_info.alias = UINtoString(m_uin); 56 Init(); 57 } 58 Contact(const string & a)59 Contact::Contact(const string& a) 60 : count(0), m_virtualcontact(true), m_uin(nextImaginaryUIN()), 61 m_status(STATUS_OFFLINE), m_invisible(false), m_capabilities( new Capabilities() ), 62 m_seqnum(0xffff) 63 { 64 m_main_home_info.alias = a; 65 Init(); 66 } 67 ~Contact()68 Contact::~Contact() 69 { 70 delete m_capabilities; 71 } 72 Init()73 void Contact::Init() 74 { 75 m_tcp_version = 0; 76 m_dc_cookie = 0; 77 m_ext_ip = 0; 78 m_lan_ip = 0; 79 m_ext_port = 0; 80 m_lan_port = 0; 81 m_direct = true; 82 m_bday = false; 83 m_signon_time = 0; 84 m_last_online_time = 0; 85 m_last_status_change_time = 0; 86 m_last_message_time = 0; 87 m_last_away_msg_check_time = 0; 88 m_group_id = 0; 89 m_tag_id = 0; 90 m_server_based = false; 91 m_authreq = false; 92 m_authawait = false; 93 } 94 getUIN() const95 unsigned int Contact::getUIN() const { return m_uin; } 96 setUIN(unsigned int uin)97 void Contact::setUIN(unsigned int uin) { 98 m_uin = uin; 99 m_virtualcontact = false; 100 userinfo_change_emit(); 101 } 102 getStringUIN() const103 string Contact::getStringUIN() const { return UINtoString(m_uin); } 104 getAlias() const105 string Contact::getAlias() const { return m_main_home_info.alias; } 106 getNameAlias() const107 string Contact::getNameAlias() const 108 { 109 string ret = getAlias(); 110 if (ret.empty()) { 111 ret = getFirstName(); 112 if (!ret.empty() && !getLastName().empty()) ret += " "; 113 ret += getLastName(); 114 } 115 if (ret.empty()) { 116 if (isICQContact()) ret = getStringUIN(); 117 else ret = getMobileNo(); 118 } 119 120 return ret; 121 } 122 getStatus() const123 Status Contact::getStatus() const { return m_status; } 124 getMobileNo() const125 string Contact::getMobileNo() const { return m_main_home_info.getMobileNo(); } 126 getNormalisedMobileNo() const127 string Contact::getNormalisedMobileNo() const { return m_main_home_info.getNormalisedMobileNo(); } 128 getFirstName() const129 string Contact::getFirstName() const { return m_main_home_info.firstname; } 130 getLastName() const131 string Contact::getLastName() const { return m_main_home_info.lastname; } 132 getEmail() const133 string Contact::getEmail() const { return m_main_home_info.email; } 134 getExtIP() const135 unsigned int Contact::getExtIP() const { return m_ext_ip; } 136 getLanIP() const137 unsigned int Contact::getLanIP() const { return m_lan_ip; } 138 getExtPort() const139 unsigned short Contact::getExtPort() const { return m_ext_port; } 140 getLanPort() const141 unsigned short Contact::getLanPort() const { return m_lan_port; } 142 getTCPVersion() const143 unsigned char Contact::getTCPVersion() const { return m_tcp_version; } 144 getDCCookie() const145 unsigned int Contact::getDCCookie() const { return m_dc_cookie; } 146 getDirect() const147 bool Contact::getDirect() const { return (m_direct && m_status != STATUS_OFFLINE); } 148 setDirect(bool b)149 void Contact::setDirect(bool b) { 150 m_direct = b; 151 userinfo_change_emit(true); 152 } 153 get_accept_adv_msgs() const154 bool Contact::get_accept_adv_msgs() const { 155 return (m_status != STATUS_OFFLINE && m_capabilities->get_accept_adv_msgs()); 156 } 157 get_capabilities() const158 Capabilities Contact::get_capabilities() const { return * m_capabilities; } 159 get_signon_time() const160 unsigned int Contact::get_signon_time() const { return m_signon_time; } 161 get_last_online_time() const162 unsigned int Contact::get_last_online_time() const 163 { 164 if (m_status == STATUS_ONLINE) { 165 return time(NULL); 166 } else { 167 return m_last_online_time; 168 } 169 } 170 get_last_status_change_time() const171 unsigned int Contact::get_last_status_change_time() const { return m_last_status_change_time; } 172 get_last_message_time() const173 unsigned int Contact::get_last_message_time() const { return m_last_message_time; } 174 get_last_away_msg_check_time() const175 unsigned int Contact::get_last_away_msg_check_time() const { return m_last_away_msg_check_time; } 176 isInvisible() const177 bool Contact::isInvisible() const { return m_invisible; } 178 getAuthReq() const179 bool Contact::getAuthReq() const { return m_authreq; } 180 getAuthAwait() const181 bool Contact::getAuthAwait() const { return m_authawait; } 182 getServerBased() const183 bool Contact::getServerBased() const { return m_server_based; } 184 setMobileNo(const string & mn)185 void Contact::setMobileNo(const string& mn) { 186 m_main_home_info.setMobileNo(mn); 187 userinfo_change_emit(); 188 } 189 setAlias(const string & al)190 void Contact::setAlias(const string& al) { 191 m_main_home_info.alias = al; 192 userinfo_change_emit(); 193 } 194 setFirstName(const string & fn)195 void Contact::setFirstName(const string& fn) { 196 m_main_home_info.firstname = fn; 197 userinfo_change_emit(); 198 } 199 setLastName(const string & ln)200 void Contact::setLastName(const string& ln) { 201 m_main_home_info.lastname = ln; 202 userinfo_change_emit(); 203 } 204 setEmail(const string & em)205 void Contact::setEmail(const string& em) { 206 m_main_home_info.email = em; 207 userinfo_change_emit(); 208 } 209 setStatus(Status st)210 void Contact::setStatus(Status st) { 211 setStatus(st, m_invisible); 212 } 213 setStatus(Status st,bool i)214 void Contact::setStatus(Status st, bool i) { 215 if (m_status == st && m_invisible == i) return; 216 217 StatusChangeEvent sev(this, st, m_status); 218 219 m_status = st; 220 m_invisible = i; 221 222 m_last_status_change_time = time(NULL); 223 224 // clear dynamic fields on going OFFLINE 225 if (m_status == STATUS_OFFLINE) 226 { 227 m_ext_ip = 0; 228 m_lan_ip = 0; 229 m_ext_port = 0; 230 m_lan_port = 0; 231 m_tcp_version = 0; 232 m_capabilities->clear(); 233 m_last_online_time = time(NULL); 234 } 235 236 status_change_signal.emit( &sev ); 237 } 238 userinfo_change_emit()239 void Contact::userinfo_change_emit() 240 { 241 userinfo_change_emit(false); 242 } 243 userinfo_change_emit(bool is_transient_detail)244 void Contact::userinfo_change_emit(bool is_transient_detail) 245 { 246 UserInfoChangeEvent ev(this, is_transient_detail); 247 userinfo_change_signal.emit(&ev); 248 } 249 setInvisible(bool inv)250 void Contact::setInvisible(bool inv) { 251 setStatus(m_status, inv); 252 } 253 setAuthReq(bool b)254 void Contact::setAuthReq(bool b) { 255 m_authreq = b; 256 userinfo_change_emit(true); 257 } 258 setAuthAwait(bool b)259 void Contact::setAuthAwait(bool b) { 260 m_authawait = b; 261 userinfo_change_emit(true); 262 } 263 setServerBased(bool b)264 void Contact::setServerBased(bool b) { 265 m_server_based = b; 266 userinfo_change_emit(true); 267 } 268 isICQContact() const269 bool Contact::isICQContact() const { return !m_virtualcontact; } 270 isVirtualContact() const271 bool Contact::isVirtualContact() const { return m_virtualcontact; } 272 isSMSable() const273 bool Contact::isSMSable() const 274 { 275 // ' SMS' suffix might be better way, but isn't reliable really 276 return !m_main_home_info.getNormalisedMobileNo().empty(); 277 } 278 setExtIP(unsigned int ip)279 void Contact::setExtIP(unsigned int ip) { 280 m_ext_ip = ip; 281 userinfo_change_emit(true); 282 } 283 setLanIP(unsigned int ip)284 void Contact::setLanIP(unsigned int ip) { 285 m_lan_ip = ip; 286 userinfo_change_emit(true); 287 } 288 setExtPort(unsigned short port)289 void Contact::setExtPort(unsigned short port) { 290 m_ext_port = port; 291 userinfo_change_emit(true); 292 } 293 setLanPort(unsigned short port)294 void Contact::setLanPort(unsigned short port) { 295 m_lan_port = port; 296 userinfo_change_emit(true); 297 } 298 setTCPVersion(unsigned char v)299 void Contact::setTCPVersion(unsigned char v) { 300 m_tcp_version = v; 301 userinfo_change_emit(true); 302 } 303 setDCCookie(unsigned int cookie)304 void Contact::setDCCookie(unsigned int cookie) { 305 m_dc_cookie = cookie; 306 userinfo_change_emit(true); 307 } 308 setServerSideInfo(unsigned short group_id,unsigned short tag_id)309 void Contact::setServerSideInfo(unsigned short group_id, unsigned short tag_id) 310 { 311 m_group_id = group_id; 312 m_tag_id = tag_id; 313 userinfo_change_emit(true); 314 } 315 getServerSideGroupID() const316 unsigned short Contact::getServerSideGroupID() const { 317 return m_group_id; 318 } 319 getServerSideID() const320 unsigned short Contact::getServerSideID() const { 321 unsigned short r = m_tag_id; 322 if(!r) { 323 r = m_uin; 324 if(r > 50000) { 325 r -= r-1000; 326 r += rand()%1000; 327 } 328 } 329 330 return r; 331 } 332 set_capabilities(const Capabilities & c)333 void Contact::set_capabilities(const Capabilities& c) 334 { 335 (*m_capabilities) = c; 336 } 337 set_signon_time(unsigned int t)338 void Contact::set_signon_time(unsigned int t) 339 { 340 m_signon_time = t; 341 userinfo_change_emit(true); 342 } 343 set_last_online_time(unsigned int t)344 void Contact::set_last_online_time(unsigned int t) 345 { 346 m_last_online_time = t; 347 userinfo_change_emit(true); 348 } 349 set_last_status_change_time(unsigned int t)350 void Contact::set_last_status_change_time(unsigned int t) 351 { 352 m_last_status_change_time = t; 353 userinfo_change_emit(true); 354 } 355 set_last_message_time(unsigned int t)356 void Contact::set_last_message_time(unsigned int t) 357 { 358 m_last_message_time = t; 359 userinfo_change_emit(true); 360 } 361 set_last_away_msg_check_time(unsigned int t)362 void Contact::set_last_away_msg_check_time(unsigned int t) 363 { 364 m_last_away_msg_check_time = t; 365 userinfo_change_emit(true); 366 } 367 setMainHomeInfo(const MainHomeInfo & s)368 void Contact::setMainHomeInfo(const MainHomeInfo& s) { 369 m_main_home_info = s; 370 userinfo_change_emit(); 371 } 372 setHomepageInfo(const HomepageInfo & s)373 void Contact::setHomepageInfo(const HomepageInfo& s) { 374 m_homepage_info = s; 375 userinfo_change_emit(); 376 } 377 setEmailInfo(const EmailInfo & s)378 void Contact::setEmailInfo(const EmailInfo& s) { 379 m_email_info = s; 380 userinfo_change_emit(); 381 } 382 setWorkInfo(const WorkInfo & s)383 void Contact::setWorkInfo(const WorkInfo& s) { 384 m_work_info = s; 385 userinfo_change_emit(); 386 } 387 setInterestInfo(const PersonalInterestInfo & s)388 void Contact::setInterestInfo(const PersonalInterestInfo& s) { 389 m_personal_interest_info = s; 390 userinfo_change_emit(); 391 } 392 setBackgroundInfo(const BackgroundInfo & b)393 void Contact::setBackgroundInfo(const BackgroundInfo& b) { 394 m_background_info = b; 395 userinfo_change_emit(); 396 } 397 setAboutInfo(const string & about)398 void Contact::setAboutInfo(const string& about) { 399 m_about = about; 400 userinfo_change_emit(); 401 } 402 getMainHomeInfo()403 Contact::MainHomeInfo& Contact::getMainHomeInfo() { return m_main_home_info; } 404 getHomepageInfo()405 Contact::HomepageInfo& Contact::getHomepageInfo() { return m_homepage_info; } 406 getWorkInfo()407 Contact::WorkInfo& Contact::getWorkInfo() { return m_work_info; } 408 getPersonalInterestInfo()409 Contact::PersonalInterestInfo& Contact::getPersonalInterestInfo() { return m_personal_interest_info; } 410 getBackgroundInfo()411 Contact::BackgroundInfo& Contact::getBackgroundInfo() { return m_background_info; } 412 getEmailInfo()413 Contact::EmailInfo& Contact::getEmailInfo() { return m_email_info; } 414 getAboutInfo() const415 const string& Contact::getAboutInfo() const { return m_about; } 416 nextSeqNum()417 unsigned short Contact::nextSeqNum() { 418 return --m_seqnum; 419 } 420 UINtoString(unsigned int uin)421 string Contact::UINtoString(unsigned int uin) { 422 ostringstream ostr; 423 ostr << uin; 424 return ostr.str(); 425 } 426 StringtoUIN(const string & s)427 unsigned int Contact::StringtoUIN(const string& s) { 428 istringstream istr(s); 429 unsigned int uin = 0; 430 istr >> uin; 431 return uin; 432 } 433 434 unsigned int Contact::imag_uin = 0; 435 nextImaginaryUIN()436 unsigned int Contact::nextImaginaryUIN() { 437 return (--imag_uin); 438 } 439 440 441 MapStatusToICQStatus(Status st,bool inv)442 unsigned short Contact::MapStatusToICQStatus(Status st, bool inv) { 443 unsigned short s; 444 445 switch(st) { 446 case STATUS_ONLINE: 447 s = 0x0000; 448 break; 449 case STATUS_AWAY: 450 s = 0x0001; 451 break; 452 case STATUS_NA: 453 s = 0x0005; 454 break; 455 case STATUS_OCCUPIED: 456 s = 0x0011; 457 break; 458 case STATUS_DND: 459 s = 0x0013; 460 break; 461 case STATUS_FREEFORCHAT: 462 s = 0x0020; 463 break; 464 default: 465 s = 0x0000; 466 } 467 468 if (inv) s |= STATUS_FLAG_INVISIBLE; 469 return s; 470 } 471 MapICQStatusToStatus(unsigned short st)472 Status Contact::MapICQStatusToStatus(unsigned short st) { 473 if (st & STATUS_FLAG_DND) return STATUS_DND; 474 else if (st & STATUS_FLAG_NA) return STATUS_NA; 475 else if (st & STATUS_FLAG_OCCUPIED) return STATUS_OCCUPIED; 476 else if (st & STATUS_FLAG_FREEFORCHAT) return STATUS_FREEFORCHAT; 477 else if (st & STATUS_FLAG_AWAY) return STATUS_AWAY; 478 else return STATUS_ONLINE; 479 } 480 MapICQStatusToInvisible(unsigned short st)481 bool Contact::MapICQStatusToInvisible(unsigned short st) { 482 return (st & STATUS_FLAG_INVISIBLE); 483 } 484 485 // Extra Detailed info class implementations; 486 MainHomeInfo()487 Contact::MainHomeInfo::MainHomeInfo() 488 : country(COUNTRY_UNKNOWN), timezone(TIMEZONE_UNKNOWN) { } 489 getCountry() const490 Country Contact::MainHomeInfo::getCountry() const 491 { 492 return country; 493 } 494 getMobileNo() const495 string Contact::MainHomeInfo::getMobileNo() const 496 { 497 return cellular; 498 } 499 setMobileNo(const string & s)500 void Contact::MainHomeInfo::setMobileNo(const string& s) 501 { 502 cellular = s; 503 normaliseMobileNo(); 504 } 505 getNormalisedMobileNo() const506 string Contact::MainHomeInfo::getNormalisedMobileNo() const 507 { 508 return normalised_cellular; 509 } 510 normaliseMobileNo()511 void Contact::MainHomeInfo::normaliseMobileNo() 512 { 513 normalised_cellular.erase(); 514 string::iterator curr = cellular.begin(); 515 while (curr != cellular.end()) { 516 if (isdigit(*curr)) normalised_cellular += *curr; 517 ++curr; 518 } 519 } 520 HomepageInfo()521 Contact::HomepageInfo::HomepageInfo() 522 : age(0), sex(SEX_UNKNOWN), 523 lang1(LANGUAGE_UNKNOWN), lang2(LANGUAGE_UNKNOWN), lang3(LANGUAGE_UNKNOWN), 524 birth_year(0), birth_month(0), birth_day(0) 525 { } 526 527 /** 528 * Get a string representation of the birthdate. 529 * 530 * @deprecated This function is not internationalized - it does not 531 * return utf-8, and returns the hard-coded "Unspecified" also. 532 */ getBirthDate() const533 string Contact::HomepageInfo::getBirthDate() const 534 { 535 if (birth_day == 0 || birth_year == 0) return "Unspecified"; 536 537 struct tm birthdate; 538 birthdate.tm_sec = 0; 539 birthdate.tm_min = 0; 540 birthdate.tm_hour = 0; 541 birthdate.tm_mday = birth_day; 542 birthdate.tm_mon = birth_month-1; 543 birthdate.tm_year = birth_year - 1900; 544 birthdate.tm_isdst = 0; 545 mktime(&birthdate); 546 char bday[255]; 547 strftime(bday, 255, "%B %e, %G", &birthdate); 548 return string(bday); 549 } 550 getLanguage(int l) const551 Language Contact::HomepageInfo::getLanguage(int l) const 552 { 553 Language ret = LANGUAGE_UNKNOWN; 554 555 switch(l) 556 { 557 case 1: 558 ret = lang1; 559 break; 560 case 2: 561 ret = lang2; 562 break; 563 case 3: 564 ret = lang3; 565 break; 566 } 567 568 return ret; 569 } 570 EmailInfo()571 Contact::EmailInfo::EmailInfo() { } 572 addEmailAddress(const string & e)573 void Contact::EmailInfo::addEmailAddress(const string& e) { 574 emails.push_back(e); 575 } 576 WorkInfo()577 Contact::WorkInfo::WorkInfo() 578 : country(0) { } 579 BackgroundInfo()580 Contact::BackgroundInfo::BackgroundInfo() { } 581 addSchool(unsigned short cat,const string & s)582 void Contact::BackgroundInfo::addSchool(unsigned short cat, const string& s) { 583 schools.push_back(School(cat, s)); 584 } 585 PersonalInterestInfo()586 Contact::PersonalInterestInfo::PersonalInterestInfo() { } 587 addInterest(unsigned short cat,const string & s)588 void Contact::PersonalInterestInfo::addInterest(unsigned short cat, const string& s) { 589 interests.push_back(Interest(cat, s)); 590 } 591 getBirthday() const592 bool Contact::getBirthday() const { return m_bday; } 593 setBirthday(bool b)594 void Contact::setBirthday(bool b) { 595 m_bday = b; 596 userinfo_change_emit(true); 597 } 598 } 599