| 36 | | // Copy constructor |
| 37 | | CAddressBook::CAddressBook(const CAddressBook& copy) |
| 38 | | { |
| 39 | | InitAddressBook(); |
| 40 | | |
| 41 | | mAdbkName = copy.mAdbkName; |
| 42 | | mFlags = copy.mFlags; |
| | 50 | // This constructs the address book manager root |
| | 51 | CAddressBook::CAddressBook() |
| | 52 | { |
| | 53 | mProtocol = NULL; |
| | 54 | mParent = NULL; |
| | 55 | mChildren = new CAddressBookList; // Root must always have list |
| | 56 | mChildren->set_delete_data(false); |
| | 57 | SetFlags(eIsProtocol, true); |
| | 58 | SetFlags(eIsDirectory, true); |
| | 59 | SetFlags(eHasExpanded, true); |
| | 60 | mShortName = mName.c_str(); |
| | 61 | mSize = ULONG_MAX; |
| | 62 | mLastSync = 0; |
| | 63 | mACLs = NULL; |
| | 64 | mRefCount = 0; |
| | 65 | mVCardAdbk = NULL; |
| | 66 | } |
| | 67 | |
| | 68 | // This constructs the root of a protocol |
| | 69 | CAddressBook::CAddressBook(CAdbkProtocol* proto) |
| | 70 | { |
| | 71 | mProtocol = proto; |
| | 72 | mParent = &CAddressBookManager::sAddressBookManager->GetRoot(); |
| | 73 | mChildren = NULL; |
| | 74 | SetFlags(eIsProtocol, true); |
| | 75 | SetFlags(eIsDirectory, true); |
| | 76 | SetFlags(eHasExpanded, true); |
| | 77 | mName = proto->GetAccountName(); |
| | 78 | mShortName = mName.c_str(); |
| | 79 | mSize = ULONG_MAX; |
| | 80 | mLastSync = 0; |
| | 81 | mACLs = NULL; |
| | 82 | mVCardAdbk = NULL; |
| | 83 | } |
| | 84 | |
| | 85 | // This constructs an actual node |
| | 86 | CAddressBook::CAddressBook(CAdbkProtocol* proto, CAddressBook* parent, bool is_adbk, bool is_dir, const cdstring& name) |
| | 87 | { |
| | 88 | mProtocol = proto; |
| | 89 | mParent = parent; |
| | 90 | mChildren = NULL; // Root must always have list |
| | 91 | SetFlags(eIsAdbk, is_adbk); |
| | 92 | SetFlags(eIsDirectory, is_dir); |
| | 93 | mName = name; |
| | 94 | mSize = ULONG_MAX; |
| | 95 | mLastSync = 0; |
| | 96 | mACLs = NULL; |
| | 97 | mRefCount = 0; |
| | 98 | mVCardAdbk = NULL; |
| | 99 | |
| | 100 | SetShortName(); |
| 53 | | // Initialization |
| 54 | | void CAddressBook::InitAddressBook() |
| 55 | | { |
| 56 | | mACLs = NULL; |
| 57 | | mRefCount = 0; |
| | 118 | cdstring CAddressBook::GetAccountName(bool multi) const |
| | 119 | { |
| | 120 | cdstring name; |
| | 121 | if (multi) |
| | 122 | { |
| | 123 | name = mProtocol->GetAccountName(); |
| | 124 | name += cMailAccountSeparator; |
| | 125 | } |
| | 126 | name += GetName(); |
| | 127 | return name; |
| | 128 | } |
| | 129 | |
| | 130 | void CAddressBook::CheckSize() |
| | 131 | { |
| | 132 | GetProtocol()->SizeAdbk(this); |
| | 133 | } |
| | 134 | |
| | 135 | void CAddressBook::SyncNow() const |
| | 136 | { |
| | 137 | time_t now = ::time(NULL); |
| | 138 | mLastSync = ::mktime(::gmtime(&now)); |
| | 139 | } |
| | 140 | |
| | 141 | bool CAddressBook::IsCached() const |
| | 142 | { |
| | 143 | // Cached if not disconnected or known to have |
| | 144 | return !GetProtocol()->IsDisconnected() || mFlags.IsSet(eIsCached); |
| | 145 | } |
| | 146 | |
| | 147 | cdstring CAddressBook::GetURL(bool full) const |
| | 148 | { |
| | 149 | cdstring ruri = GetName(); |
| | 150 | ruri.EncodeURL(GetProtocol()->GetDirDelim()); |
| | 151 | |
| | 152 | cdstring result = mProtocol->GetURL(full); |
| | 153 | result += "/"; |
| | 154 | result += ruri; |
| | 155 | return result; |
| | 156 | } |
| | 157 | |
| | 158 | void CAddressBook::AddChild(CAddressBook* child, bool sort) |
| | 159 | { |
| | 160 | // Create if required |
| | 161 | if (mChildren == NULL) |
| | 162 | mChildren = new CAddressBookList; |
| | 163 | mChildren->push_back(child); |
| | 164 | child->mParent = this; |
| | 165 | |
| | 166 | // Setting a child means it has been expanded |
| | 167 | SetFlags(eHasExpanded, true); |
| | 168 | |
| | 169 | // Do sort if requested |
| | 170 | if (sort) |
| | 171 | SortChildren(); |
| | 172 | } |
| | 173 | |
| | 174 | void CAddressBook::AddChildHierarchy(CAddressBook* child, bool sort) |
| | 175 | { |
| | 176 | // Only do this if its the protocol root |
| | 177 | if (mParent != &CAddressBookManager::sAddressBookManager->GetRoot()) |
| | 178 | return; |
| | 179 | |
| | 180 | // Break the name down into components |
| | 181 | cdstrvect names; |
| | 182 | const char* start = child->GetName().c_str(); |
| | 183 | const char* end = ::strchr(start, mProtocol->GetDirDelim()); |
| | 184 | while(end != NULL) |
| | 185 | { |
| | 186 | names.push_back(cdstring(start, end - start)); |
| | 187 | start = end + 1; |
| | 188 | end = ::strchr(start, mProtocol->GetDirDelim()); |
| | 189 | } |
| | 190 | |
| | 191 | // Find each path component |
| | 192 | CAddressBook* parent = this; |
| | 193 | cdstring path; |
| | 194 | for(cdstrvect::const_iterator iter1 = names.begin(); iter1 != names.end(); iter1++) |
| | 195 | { |
| | 196 | // Get path component |
| | 197 | if (!path.empty()) |
| | 198 | path += mProtocol->GetDirDelim(); |
| | 199 | path += *iter1; |
| | 200 | |
| | 201 | // Find the node |
| | 202 | bool found = false; |
| | 203 | for(CAddressBookList::iterator iter2 = parent->GetChildren()->begin(); iter2 != parent->GetChildren()->end(); iter2++) |
| | 204 | { |
| | 205 | if ((*iter2)->GetName() == path) |
| | 206 | { |
| | 207 | parent = *iter2; |
| | 208 | found = true; |
| | 209 | break; |
| | 210 | } |
| | 211 | } |
| | 212 | |
| | 213 | // If not found, create a directory and make it the new parent |
| | 214 | if (!found) |
| | 215 | { |
| | 216 | CAddressBook* adbk = new CAddressBook(mProtocol, parent, false, true, path); |
| | 217 | parent->AddChild(adbk, sort); |
| | 218 | parent = adbk; |
| | 219 | } |
| | 220 | } |
| | 221 | |
| | 222 | // Now add to actual parent |
| | 223 | parent->AddChild(child, sort); |
| | 224 | } |
| | 225 | |
| | 226 | void CAddressBook::InsertChild(CAddressBook* child, uint32_t index, bool sort) |
| | 227 | { |
| | 228 | // Do ordinary add if no children or insert at end |
| | 229 | if ((mChildren == NULL) || (index >= mChildren->size())) |
| | 230 | AddChild(child, sort); |
| | 231 | else |
| | 232 | { |
| | 233 | mChildren->insert(mChildren->begin() + index, child); |
| | 234 | child->mParent = this; |
| | 235 | |
| | 236 | // Do sort if requested |
| | 237 | if (sort) |
| | 238 | SortChildren(); |
| | 239 | } |
| | 240 | } |
| | 241 | |
| | 242 | void CAddressBook::SortChildren() |
| | 243 | { |
| | 244 | if (mChildren == NULL) |
| | 245 | return; |
| | 246 | |
| | 247 | std::sort(mChildren->begin(), mChildren->end(), sort_by_name); |
| | 248 | } |
| | 249 | |
| | 250 | bool CAddressBook::sort_by_name(const CAddressBook* s1, const CAddressBook* s2) |
| | 251 | { |
| | 252 | return ::strcmpnocase(s1->GetShortName(), s2->GetShortName()) < 0; |
| | 253 | } |
| | 254 | |
| | 255 | CAddressBook* CAddressBook::FindNode(cdstrvect& hierarchy, bool discover) const |
| | 256 | { |
| | 257 | // Find top-level item matching last item in hierarchy |
| | 258 | if (mChildren) |
| | 259 | { |
| | 260 | for(CAddressBookList::iterator iter = mChildren->begin(); iter != mChildren->end(); iter++) |
| | 261 | { |
| | 262 | if (hierarchy.back() == (*iter)->GetShortName()) |
| | 263 | { |
| | 264 | hierarchy.pop_back(); |
| | 265 | if (hierarchy.empty()) |
| | 266 | return *iter; |
| | 267 | else |
| | 268 | { |
| | 269 | // May need discovery |
| | 270 | if (discover && (*iter)->IsDirectory() && !(*iter)->HasExpanded()) |
| | 271 | GetProtocol()->LoadSubList(*iter, false); |
| | 272 | return (*iter)->FindNode(hierarchy, discover); |
| | 273 | } |
| | 274 | } |
| | 275 | } |
| | 276 | } |
| | 277 | |
| | 278 | return NULL; |
| | 279 | } |
| | 280 | |
| | 281 | // Remove node from parent withtout deleting the node |
| | 282 | void CAddressBook::RemoveFromParent() |
| | 283 | { |
| | 284 | if (mParent) |
| | 285 | { |
| | 286 | CAddressBookList* list = mParent->GetChildren(); |
| | 287 | CAddressBookList::iterator found = ::find(list->begin(), list->end(), this); |
| | 288 | if (found != list->end()) |
| | 289 | { |
| | 290 | // NULL it out so that the node is not deleted, then erase |
| | 291 | *found = NULL; |
| | 292 | list->erase(found); |
| | 293 | } |
| | 294 | |
| | 295 | mParent = NULL; |
| | 296 | } |
| | 297 | } |
| | 298 | |
| | 299 | void CAddressBook::Clear() |
| | 300 | { |
| | 301 | if (mChildren != NULL) |
| | 302 | { |
| | 303 | // Erase children |
| | 304 | delete mChildren; |
| | 305 | mChildren = NULL; |
| | 306 | } |
| | 307 | } |
| | 308 | |
| | 309 | uint32_t CAddressBook::GetRow() const |
| | 310 | { |
| | 311 | // Look for sibling |
| | 312 | uint32_t row = GetParentOffset(); |
| | 313 | const CAddressBook* parent = mParent; |
| | 314 | while(parent != NULL) |
| | 315 | { |
| | 316 | row += parent->GetParentOffset(); |
| | 317 | parent = parent->mParent; |
| | 318 | } |
| | 319 | |
| | 320 | return row; |
| | 321 | } |
| | 322 | |
| | 323 | uint32_t CAddressBook::CountDescendants() const |
| | 324 | { |
| | 325 | uint32_t result = 0; |
| | 326 | if (mChildren != NULL) |
| | 327 | { |
| | 328 | for(CAddressBookList::iterator iter = mChildren->begin(); iter != mChildren->end(); iter++) |
| | 329 | result += (*iter)->CountDescendants() + 1; |
| | 330 | } |
| | 331 | |
| | 332 | return result; |
| | 333 | } |
| | 334 | |
| | 335 | uint32_t CAddressBook::GetParentOffset() const |
| | 336 | { |
| | 337 | uint32_t result = 0; |
| | 338 | if ((mParent != NULL) && mParent->HasInferiors()) |
| | 339 | { |
| | 340 | result++; |
| | 341 | for(CAddressBookList::iterator iter = mParent->GetChildren()->begin(); iter != mParent->GetChildren()->end(); iter++) |
| | 342 | { |
| | 343 | if (*iter == this) |
| | 344 | break; |
| | 345 | |
| | 346 | result += (*iter)->CountDescendants() + 1; |
| | 347 | } |
| | 348 | } |
| | 349 | |
| | 350 | return result; |
| | 351 | } |
| | 352 | |
| | 353 | const CAddressBook* CAddressBook::GetSibling() const |
| | 354 | { |
| | 355 | const CAddressBook* result = NULL; |
| | 356 | if ((mParent != NULL) && mParent->HasInferiors()) |
| | 357 | { |
| | 358 | for(CAddressBookList::iterator iter = mParent->GetChildren()->begin(); iter != mParent->GetChildren()->end(); iter++) |
| | 359 | { |
| | 360 | if (*iter == this) |
| | 361 | break; |
| | 362 | |
| | 363 | result = *iter; |
| | 364 | } |
| | 365 | } |
| | 366 | |
| | 367 | return result; |
| | 368 | } |
| | 369 | |
| | 370 | void CAddressBook::GetInsertRows(uint32_t& parent_row, uint32_t& sibling_row) const |
| | 371 | { |
| | 372 | // Get parent's row |
| | 373 | parent_row = (mParent ? mParent->GetRow() : 0); |
| | 374 | |
| | 375 | // Now get the sibling row |
| | 376 | uint32_t parent_offset = GetParentOffset(); |
| | 377 | if ((parent_offset != 0) && (GetSibling() != NULL)) |
| | 378 | { |
| | 379 | sibling_row = parent_row + parent_offset - GetSibling()->CountDescendants() - 1; |
| | 380 | } |
| | 381 | else |
| | 382 | sibling_row = 0; |
| | 383 | } |
| | 384 | |
| | 385 | // Set pointer to short name |
| | 386 | void CAddressBook::SetShortName() |
| | 387 | { |
| | 388 | // Determine last directory break |
| | 389 | const char* p = NULL; |
| | 390 | if ((GetProtocol()->GetDirDelim() != 0) && ((p = ::strrchr(mName.c_str(), mProtocol->GetDirDelim())) != NULL)) |
| | 391 | mShortName = ++p; |
| | 392 | else |
| | 393 | mShortName = mName.c_str(); |
| | 394 | } |
| | 395 | |
| | 396 | // Tell this and children to adjust names |
| | 397 | void CAddressBook::NewName(const cdstring& name) |
| | 398 | { |
| | 399 | // Adjust this one |
| | 400 | SetName(name); |
| | 401 | |
| | 402 | // Now iterate over children doing rename |
| | 403 | if (mChildren != NULL) |
| | 404 | { |
| | 405 | for(CAddressBookList::iterator iter = mChildren->begin(); iter != mChildren->end(); iter++) |
| | 406 | { |
| | 407 | (*iter)->ParentRenamed(); |
| | 408 | } |
| | 409 | } |
| | 410 | } |
| | 411 | |
| | 412 | // Tell children to adjust names when parent moves |
| | 413 | void CAddressBook::ParentRenamed() |
| | 414 | { |
| | 415 | // Must have a parent |
| | 416 | if (mParent == NULL) |
| | 417 | return; |
| | 418 | |
| | 419 | // Adjust this node |
| | 420 | cdstring new_name; |
| | 421 | new_name = mParent->GetName(); |
| | 422 | if (GetProtocol()->GetDirDelim()) |
| | 423 | new_name += GetProtocol()->GetDirDelim(); |
| | 424 | new_name += GetShortName(); |
| | 425 | SetName(new_name); |
| | 426 | |
| | 427 | // Now iterate over children doing rename |
| | 428 | if (mChildren != NULL) |
| | 429 | { |
| | 430 | for(CAddressBookList::iterator iter = mChildren->begin(); iter != mChildren->end(); iter++) |
| | 431 | { |
| | 432 | (*iter)->ParentRenamed(); |
| | 433 | } |
| | 434 | } |
| | 435 | } |
| | 436 | |
| | 437 | void CAddressBook::MoveAddressBook(const CAddressBook* dir, bool sibling) |
| | 438 | { |
| | 439 | #ifdef TODO |
| | 440 | #endif |
| | 441 | } |
| | 442 | |
| | 443 | // Copy this address book into another one |
| | 444 | void CAddressBook::CopyAddressBook(CAddressBook* node) |
| | 445 | { |
| | 446 | #ifdef TODO |
| | 447 | #endif |
| | 448 | } |
| | 449 | |
| | 450 | // Copy this address book's items into another one |
| | 451 | void CAddressBook::CopyAddressBookContents(CAddressBook* node) |
| | 452 | { |
| | 453 | #ifdef TODO |
| | 454 | #endif |
| | 455 | } |
| | 456 | |
| | 457 | // Switch into disconnected mode |
| | 458 | void CAddressBook::TestDisconnectCache() |
| | 459 | { |
| | 460 | if (mChildren != NULL) |
| | 461 | { |
| | 462 | // Test each child recursively |
| | 463 | for(CAddressBookList::iterator iter = mChildren->begin(); iter != mChildren->end(); iter++) |
| | 464 | (*iter)->TestDisconnectCache(); |
| | 465 | } |
| | 466 | |
| | 467 | // See if it exists locally |
| | 468 | if (IsAdbk()) |
| | 469 | SetFlags(eIsCached, mProtocol->TestAdbk(this)); |