/* -*- C++ -*- This file implements the basic personal information management class used in the TDE addressbook. the TDE addressbook $ Author: Mirko Boehm $ $ Copyright: (C) 1996-2001, Mirko Boehm $ $ Contact: mirko@kde.org http://www.kde.org $ $ License: GPL with the following explicit clarification: This code may be linked against any version of the Qt toolkit from Troll Tech, Norway. $ $Id$ */ #include "addressbook.h" #include "qconfigDB.h" #include #include #include #include #include #include #include #include extern "C" { #include #include #include #include } // ----- some defines: #ifdef KAB_KDEBUG_AREA #undef KAB_KDEBUG_AREA #endif #define KAB_KDEBUG_AREA 800 #ifdef STD_USERFILENAME #undef STD_USERFILENAME #endif #define STD_USERFILENAME "kab/addressbook.kab" #ifdef STD_CONFIGFILENAME #undef STD_CONFIGFILENAME #endif #define STD_CONFIGFILENAME "kab/kab.config" #ifdef ENTRY_SECTION #undef ENTRY_SECTION #endif #define ENTRY_SECTION "entries" // the name of the file-local configuration section #ifdef LOCAL_CONFIG_SECTION #undef LOCAL_CONFIG_SECTION #endif #define LOCAL_CONFIG_SECTION "config" // the name of the subsection for each entry #ifdef ADDRESS_SUBSECTION #undef ADDRESS_SUBSECTION #endif #define ADDRESS_SUBSECTION "addresses" #ifdef KAB_TEMPLATEFILE #undef KAB_TEMPLATEFILE #endif #define KAB_TEMPLATEFILE "kab/template.kab" #ifdef KAB_CONFIGTEMPLATE #undef KAB_CONFIGTEMPLATE #endif #define KAB_CONFIGTEMPLATE "kab/template.config" #ifdef KAB_CATEGORY_KEY #undef KAB_CATEGORY_KEY #endif #define KAB_CATEGORY_KEY "categories" const char* AddressBook::Entry::Address::Fields[]= { "headline", "position", "org", "orgunit", "orgsubunit", "deliverylabel", "address", "zip", "town", "country", "state" }; const int AddressBook::Entry::Address::NoOfFields =sizeof(AddressBook::Entry::Address::Fields) /sizeof(AddressBook::Entry::Address::Fields[0]); const char* AddressBook::Entry::Fields[]= { "title", "rank", "fn", "nameprefix", "firstname", "middlename", "lastname", "birthday", "comment", "talk", "emails", "keywords", "telephone", "urls", "user1", "user2", "user3", "user4", "custom", "categories" }; const int AddressBook::Entry::NoOfFields =sizeof(AddressBook::Entry::Fields)/sizeof(AddressBook::Entry::Fields[0]); struct QStringLess : public binary_function { /** The function operator, inline. */ bool operator()(const TQString& x, const TQString& y) const { return x < y; // make one Qt operator fit exactly } }; // ----- the derived map class: class StringKabKeyMap : public map { /* Same as map, but a class for compilation reasons. This way we do not need * to include the QStringLess class into the addressbook header file. */ }; // ----- another derived map class: class KeyNameMap : public map > { // same thing }; KeyNameMap* AddressBook::Entry::fields; KeyNameMap* AddressBook::Entry::Address::fields; bool KabKey::operator == (const KabKey& key) const { // ########################################################################### return key.getKey()==getKey(); // ########################################################################### } void KabKey::setKey(const TQCString& text) { // ########################################################################### key=text; // ########################################################################### } TQCString KabKey::getKey() const { // ########################################################################### return key; // ########################################################################### } AddressBook::Entry::Address::Address() { } bool AddressBook::Entry::Address::nameOfField(const char* key, TQString& value) { KeyNameMap::iterator pos; // ----- if(fields==0) { // this is executed exactly one time per application instance, // as fields is static int counter=0; fields=new KeyNameMap; TQ_CHECK_PTR(fields); if(!fields->insert (map >::value_type (Fields[counter++], i18n("Headline"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Position"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Organization"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Department"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Sub-Department"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Delivery Label"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("street/postal","Address"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Zipcode"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("City"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Country"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("As in addresses", "State"))).second) { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::Entry::Address::nameOfField (while " << " creating field-name map): TYPO, correct this." << endl; } else { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::Entry::Address::nameOfField: " << "inserted field names." << endl; } #if ! defined NDEBUG TQString name; kdDebug(KAB_KDEBUG_AREA) << "AddressBook::Entry::Address::nameOfField:" << endl << "Created key-fieldname-map. Defined fields are:" << endl; for(counter=0; counterfind(Fields[counter]); if(pos==fields->end()) { kdDebug(KAB_KDEBUG_AREA) << " UNDEFINED" << endl; } else { kdDebug(KAB_KDEBUG_AREA) << " " << Fields[counter] << " (" << (*pos).second.utf8() << ")" << endl; } } #endif } // ----- now finally do the lookup: pos=fields->find(key); if(pos==fields->end()) { return false; } else { value=(*pos).second; return true; } } bool AddressBook::Entry::nameOfField(const char* key, TQString& value) { KeyNameMap::iterator pos; // ----- if(fields==0) { // this is executed exactly one time per application instance, // as fields is static int counter=0; fields=new KeyNameMap; TQ_CHECK_PTR(fields); if(!fields->insert (map >::value_type (Fields[counter++], i18n("person","Title"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Rank"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Formatted Name"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Name Prefix"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("First Name"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Middle Name"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Last Name"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Birthday"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Comment"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Talk Addresses"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Email Addresses"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Keywords"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Telephone Number"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("URLs"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("User Field 1"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("User Field 2"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("User Field 3"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("User Field 4"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Custom"))).second || !fields->insert (map >::value_type (Fields[counter++], i18n("Categories"))).second) { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::Entry::Address::nameOfField (while " << " creating field-name map): TYPO, correct this." << endl; } else { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::Entry::Address::nameOfField: " << "inserted field names." << endl; } #if ! defined NDEBUG TQString name; kdDebug(KAB_KDEBUG_AREA) << "AddressBook::Entry::nameOfField:" << endl << "Created key-fieldname-map. Defined fields are:" << endl; for(counter=0; counterfind(Fields[counter]); if(pos==fields->end()) { kdDebug(KAB_KDEBUG_AREA) << " UNDEFINED" << endl; } else { kdDebug(KAB_KDEBUG_AREA) << " " << Fields[counter] << " (" << (*pos).second.utf8() << ")" << endl; } } #endif } // ----- now finally do the lookup: pos=fields->find(key); if(pos==fields->end()) { return false; } else { value=(*pos).second; return true; } } AddressBook::ErrorCode AddressBook::Entry::getAddress(int index, Address& address) const { // ########################################################################### list
::const_iterator pos; // ----- if(index>=0 && (unsigned)indexquit(); // It is critical, but will possibly never happen. } connect(data, TQT_SIGNAL(fileChanged()), TQT_SLOT(dataFileChanged())); connect(data, TQT_SIGNAL(changed(QConfigDB*)), TQT_SLOT(reloaded(QConfigDB*))); connect(config, TQT_SIGNAL(fileChanged()), TQT_SLOT(configFileChanged())); // ----- set style: filename = locate( "data", STD_CONFIGFILENAME); if (filename.isEmpty()) { filename = locateLocal( "data", STD_CONFIGFILENAME ); // config does not exist yet if(createConfigFile()!=NoError) { KMessageBox::sorry(this, i18n("Your local kab configuration file " "\"%1\" " "could not be created. kab will probably not " "work correctly without it.\n" "Make sure you have not removed write permission " "from your local TDE directory (usually ~/.trinity).").arg(filename)); state=PermDenied; } } loadConfigFile(); // ----- now get some configuration settings: if(config->get("config", keys)) { keys->get("CreateBackupOnStartup", createBackup); } // ----- check and possibly create user standard file: filename = locate( "data", STD_USERFILENAME ); if(filename.isEmpty()) // if it does not exist { filename = locateLocal( "data", STD_USERFILENAME); if(createNew(filename)!=NoError) // ...and we cannot create it { KMessageBox::sorry(this, i18n("Your standard kab database file " "\"%1\" " "could not be created. kab will probably not " "work correctly without it.\n" "Make sure you have not removed write permission " "from your local TDE directory (usually ~/.trinity).").arg(filename)); state=PermDenied; } else { KMessageBox::information (this, i18n("kab has created your standard addressbook in\n\"%1\"") .arg(filename)); } } // ----- load the user standard file: if(loadit) { if(load(filename)!=NoError) { // ----- the standard file could not be loaded state=PermDenied; } else { if(createBackup) { // ----- create the backup file: TQString temp=data->fileName(); if(data->setFileName(temp+".backup", false, false)) { if(!data->save()) { KMessageBox::information (this, i18n("Cannot create backup file (permission denied)."), i18n("File Error")); } } else { KMessageBox::error (this, i18n("Cannot open backup file for " "writing (permission denied)."), i18n("File Error")); } // ----- reset the filename: if(!data->setFileName(temp, true, true)) { KMessageBox::error (this, i18n("Critical error:\n" "Permissions changed in local directory!"), i18n("File Error")); closeFile(false); state=PermDenied; } else { state=NoError; } } } } // ----- data->watch(true); // ########################################################################### } AddressBook::~AddressBook() { // ########################################################################### delete data; delete config; delete entries; // ########################################################################### } QConfigDB* AddressBook::getConfig() { // ########################################################################### return config; // ########################################################################### } AddressBook::ErrorCode AddressBook::getState() { // ########################################################################### return state; // ########################################################################### } AddressBook::ErrorCode AddressBook::load(const TQString& filename) { // ----- Remark: Close the file if it could not be loaded! // ########################################################################### ErrorCode rc=NoError; TQFileInfo newfile, oldfile; // ----- TQString fname = (filename.isEmpty()) ? data->fileName() : filename ; if(fname.isEmpty()) // there was never a filename set: { state=NoFile; return NoFile; } // ----- newfile.setFile(fname); oldfile.setFile(data->fileName()); if(isSameFile(fname, data->fileName())) { // ----- possibly deleted file: if(data->load()) { emit(setStatus(i18n("File reloaded."))); state=NoError; } else { switch (KMessageBox::questionYesNo (this, i18n("The currently loaded file " "\"%1\" " "cannot be reloaded. kab may close or save it.\n" "Save it if you accidentally deleted your data file.\n" "Close it if you intended to do so.\n" "Your file will be closed by default.") .arg(oldfile.absFilePath()), i18n("File Error"), KStdGuiItem::close(), KStdGuiItem::save())) { case KMessageBox::No: // save if(!data->save(i18n("(Safety copy on file error)").ascii(), true)) { KMessageBox::information(this, i18n("Cannot save the file; will close it now."), i18n("File Error")); closeFile(false); state=NoFile; rc=PermDenied; } else { state=NoError; rc=NoError; } break; // no error if we could save the file default: // close closeFile(false); state=NoFile; rc=NoSuchFile; break; } } } else { // ----- set new filename if(data->setFileName(fname, true, true)) { if(data->load()) { emit(changed()); emit(setStatus(i18n("File opened."))); state=NoError; } else { KMessageBox::information(this, i18n("Could not load the file."), i18n("File Error")); closeFile(false); emit(setStatus(i18n("No such file."))); rc=NoSuchFile; } } else { if(KMessageBox::questionYesNo (this, i18n("The file \"%1\" cannot be found. " "Create a new one?").arg(fname), i18n("No Such File"), i18n("Create"), KStdGuiItem::cancel())==KMessageBox::Yes) { if(createNew(fname)==NoError) { emit(setStatus(i18n("New file."))); } else { // ----- do not close here, stick with the old file: emit(setStatus(i18n("Canceled."))); } } } } // ----- if(rc==NoError) { data->watch(true); updateMirrorMap(); } // ----- return rc; // ########################################################################### } AddressBook::ErrorCode AddressBook::getListOfNames(TQStringList* strings, bool reverse, bool initials) { register bool GUARD; GUARD=false; // ########################################################################### kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::getListOfNames: called.\n"; StringKabKeyMap::iterator pos; TQString desc; ErrorCode rc=NoError; ErrorCode temp; // ----- erase the list contents: strings->clear(); // ----- ...and fill it: for(pos=entries->begin(); pos!=entries->end(); ++pos) { temp=literalName((*pos).second, desc, reverse, initials); if(temp!=AddressBook::NoError) { desc=i18n("(Internal error in kab)"); rc=InternError; } if(desc.isEmpty()) { desc=i18n("(empty entry)"); } kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::getListOfNames: adding " << desc << endl; strings->append(desc); } // ----- any problems? kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::getListOfNames: done, " << strings->count() << " entries.\n"; return rc; // ########################################################################### } AddressBook::ErrorCode AddressBook::literalName(const KabKey& key, TQString& text, bool rev, bool init) { // ########################################################################### Entry entry; ErrorCode rc; // ----- get the entry: rc=getEntry(key, entry); if(rc!=NoError) { return rc; } // ----- return literalName(entry, text, rev, init); // ########################################################################### } AddressBook::ErrorCode AddressBook::literalName(const Entry& entry, TQString& text, bool rev, bool init) { register bool GUARD; GUARD=false; // ########################################################################### kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::literalName: called.\n"; TQString firstname, middlename, lastname, nameprefix; // ----- is the formatted name set? if(!entry.fn.isEmpty()) { text=entry.fn; kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::literalName: done (fn).\n"; return NoError; } // ----- prepare the strings: firstname=entry.firstname.simplifyWhiteSpace(); middlename=entry.middlename.simplifyWhiteSpace(); lastname=entry.lastname.simplifyWhiteSpace(); nameprefix=entry.nameprefix.simplifyWhiteSpace(); // ----- create the initials: if(init) { if(!firstname.isEmpty()) firstname=firstname.mid(0, 1)+'.'; if(!middlename.isEmpty()) middlename=middlename.mid(0, 1)+'.'; // if(!lastname.isEmpty()) lastname=lastname.mid(0, 1)+'.'; } // ----- assemble the string: text=""; if(rev) { // name, firstname - add. name - name prefix if(!lastname.isEmpty()) { text=lastname; } if(!firstname.isEmpty() || !middlename.isEmpty() || !nameprefix.isEmpty()) { text+=','; } if(!firstname.isEmpty()) { if(!text.isEmpty()) { text+=' '; } text+=firstname; } if(!middlename.isEmpty()) { if(!text.isEmpty()) { text+=' '; } text+=middlename; } if(!nameprefix.isEmpty()) { if(!text.isEmpty()) { text+=' '; } text+=nameprefix; } } else { // firstname - add. name - name prefix - name text=firstname; if(!middlename.isEmpty()) { if(!text.isEmpty()) { text+=' '; } text+=middlename; } if(!nameprefix.isEmpty()) { if(!text.isEmpty()) { text+=' '; } text+=nameprefix; } if(!lastname.isEmpty()) { if(!text.isEmpty()) { text+=' '; } text+=lastname; } } // ----- kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::literalName: done: " << text << ".\n"; return NoError; // ########################################################################### } unsigned int AddressBook::noOfEntries() { // ########################################################################### return entries->size(); // ########################################################################### } void AddressBook::dataFileChanged() { // ########################################################################### data->watch(false); // will be restarted after successful load load(); // ########################################################################### } void AddressBook::configFileChanged() { register bool GUARD; GUARD=true; // ########################################################################### if(!config->load()) { KMessageBox::error(this, i18n("Cannot reload configuration file!"), i18n("File Error")); } else { kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::configFileChanged: " "config file reloaded.\n"; emit(setStatus(i18n("Configuration file reloaded."))); } // ########################################################################### } void AddressBook::reloaded(QConfigDB* db) { register bool GUARD; GUARD=false; // ########################################################################### if(db==data) { kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::reloaded: file has been " "reloaded.\n"; updateMirrorMap(); // WORK_TO_DO: what's up with the return value? changed(); } // ########################################################################### } AddressBook::ErrorCode AddressBook::save(const TQString& filename, bool force) { // ########################################################################### if(filename.isEmpty()) { if(data->save(0, force)) { emit(setStatus(i18n("File saved."))); return NoError; } else { return PermDenied; } } else { if(data->setFileName(filename, false, false)) { if(data->save(0, true)) { emit(newFile(filename)); return NoError; } else { return PermDenied; } } else { return PermDenied; } } // ########################################################################### } bool AddressBook::isSameFile(const TQString& a, const TQString& b) { // ########################################################################### TQFileInfo filea(a), fileb(b); // ----- return filea.absFilePath()==fileb.absFilePath(); // ########################################################################### } AddressBook::ErrorCode AddressBook::closeFile(bool saveit) { // ########################################################################### if(saveit) { if(save()!=NoError) { emit(setStatus(i18n("Permission denied."))); return PermDenied; } } data->clear(); // data->reset(); WORK_TO_DO: File name is not reset by now. emit(setStatus(i18n("File closed."))); return NoError; // ########################################################################### } AddressBook::ErrorCode AddressBook::getEntry(const KabKey& key, Entry& entry) { // ########################################################################### Section *section; // ----- if(getEntry(key, section)==NoError) { return makeEntryFromSection(section, entry); } else { return NoSuchEntry; } // ########################################################################### } AddressBook::ErrorCode AddressBook::getEntry(const KabKey& key, Section*& section) { register bool GUARD; GUARD=false; // ########################################################################### kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::getEntry: searching entry " "with key " << key.getKey().data() << endl; StringKabKeyMap::iterator pos; // ----- for(pos=entries->begin(); pos!=entries->end(); ++pos) { if((*pos).second==key) { kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::getEntry: key exists." << endl; break; } } if(pos==entries->end()) { kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::getEntry: no such entry.\n"; return NoSuchEntry; } else { if(data->get((TQCString)ENTRY_SECTION+'/'+key.getKey(), section)) { kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::getEntry: done." << endl; return NoError; } else { return InternError; } } // ########################################################################### } AddressBook::ErrorCode AddressBook::getEntries(list& thelist) { // ########################################################################### StringKabKeyMap::iterator pos; Entry entry; ErrorCode rc; // ----- kdDebug(!thelist.empty(), KAB_KDEBUG_AREA) << "AddressBook::getEntries: warning - non-empty value list!" << endl; thelist.erase(thelist.begin(), thelist.end()); for(pos=entries->begin(); pos!=entries->end(); ++pos) { rc=getEntry((*pos).second, entry); if(rc==NoError) { thelist.push_back(entry); } else { return InternError; } } // ----- return NoError; // ########################################################################### } AddressBook::ErrorCode AddressBook::getKey(int index, KabKey& key) { // ########################################################################### StringKabKeyMap::iterator pos; // ----- if((unsigned)indexsize()) { pos=entries->begin(); advance(pos, index); key=(*pos).second; return NoError; } else { return NoSuchEntry; } // ########################################################################### } AddressBook::ErrorCode AddressBook::getIndex(const KabKey& key, int& index) { register bool GUARD; GUARD=true; // ########################################################################### StringKabKeyMap::iterator pos; // ----- index=0; for(pos=entries->begin(); pos!=entries->end(); ++pos) { // kdDebug(KAB_KDEBUG_AREA) << (*pos).second.getKey().data() << " <--> " << // key.getKey().data() << endl; if((*pos).second==key) break; ++index; } kdDebug(pos==entries->end(), KAB_KDEBUG_AREA) << "AddressBook::getIndex: no such key." << endl; if(pos==entries->end()) { return NoSuchEntry; } else { return NoError; } // ########################################################################### } Section* AddressBook::entrySection() { // ########################################################################### Section* section; // ----- if(!data->get(ENTRY_SECTION, section)) { return 0; } else { return section; } // ########################################################################### } AddressBook::ErrorCode AddressBook::add(const Entry& entry, KabKey& key, bool update) { bool GUARD; GUARD=true; kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::add: called." << endl; // ########################################################################### Section* theEntries=entrySection(); Section* newEntry; KabKey nextKey; ErrorCode locked; ErrorCode rc; // ----- if(theEntries==0) { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::add: no entries section." << endl; return NoFile; } newEntry=new Section; if(newEntry==0) { KMessageBox::error(this, i18n("Cannot initialize local variables."), i18n("Out of Memory")); kapp->quit(); // It is critical, but will possibly never happen. return InternError; // shut the compiler up... } // ----- lock the file: locked=lock(); switch(locked) { case PermDenied: kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::add: permission denied." << endl; return PermDenied; // cannot get r/w mode case Locked: kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::add: db is already in r/w mode." << endl; break; case NoError: kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::add: got writing permissions." << endl; break; default: kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::add: unknown response, exiting." << endl; return InternError; } // ----- if(makeSectionFromEntry(entry, *newEntry)==NoError) { nextKey=nextAvailEntryKey(); if(!theEntries->add(nextKey.getKey(), newEntry)) { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::add: Cannot insert section.\n"; rc=InternError; } else { key=nextKey; emit(changed()); rc=NoError; } if(update) updateMirrorMap(); } else { rc=InternError; } if(locked!=Locked) { // ----- unlock the file here: kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::add: dropped writing permissions." << endl; locked=unlock(); } // ----- kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::add: done." << endl; if(locked!=NoError) { return locked; } if(rc!=NoError) { return rc; } return NoError; // ########################################################################### } AddressBook::ErrorCode AddressBook::change(const KabKey& key, const Entry& entry) { // ########################################################################### Section* theEntries=entrySection(); Section* oldEntry; ErrorCode locked; ErrorCode rc; // ----- if(theEntries==0) { return NoFile; } // ----- lock the file: locked=lock(); if(locked==PermDenied) { return PermDenied; // cannot get r/w mode } // ----- if(!theEntries->find(key.getKey(), oldEntry)) { rc=NoSuchEntry; } else { oldEntry->clear(); rc=makeSectionFromEntry(entry, *oldEntry); emit(changed()); } // ----- if(locked!=PermDenied) { // ----- unlock the file here: locked=unlock(); } if(locked==NoError) { return rc; } else { return locked; } // ########################################################################### } AddressBook::ErrorCode AddressBook::remove(const KabKey& key) { // ########################################################################### Section *theEntries=entrySection(); ErrorCode locked; ErrorCode rc; // ----- if(theEntries==0) { return NoFile; } // ----- lock the file: locked=lock(); if(locked==PermDenied) { return PermDenied; // cannot get r/w mode } // ----- if(theEntries->remove(key.getKey())) { rc=NoError; emit(changed()); } else { rc=NoSuchEntry; } // ----- if(locked!=PermDenied) { // ----- unlock the file here: locked=unlock(); } if(locked==NoError) { return rc; } else { return locked; } // ########################################################################### } AddressBook::ErrorCode AddressBook::lock() { // ########################################################################### if(!data->isRO()) return Locked; if(data->setFileName(data->fileName(), false, false)) { return NoError; } else { KMessageBox::information(this, i18n("The file you wanted to change could not be locked.\n" "It is probably in use by another application or read-only."), i18n("File Error")); return PermDenied; } // ########################################################################### } AddressBook::ErrorCode AddressBook::unlock() { // ########################################################################### if(data->isRO()) return PermDenied; if(data->setFileName(data->fileName(), true, true)) { return NoError; } else { return InternError; } // ########################################################################### } KabKey AddressBook::nextAvailEntryKey() { // ########################################################################### int max=0; int temp; Section::StringSectionMap::iterator pos; Section *section=entrySection(); KabKey key; TQCString dummy; bool good=true; // ----- if(section!=0) { for(pos=section->sectionsBegin(); pos!=section->sectionsEnd(); ++pos) { temp=0; temp=(*pos).first.toInt(&good); if(!good) { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::nextAvailEntryKey: non-integer entry " << endl; } if(temp>max) { max=temp; } } } // ----- dummy.setNum(++max); key.setKey(dummy); // CHECK(key.getKey().toInt(&good)==max); return key; // ########################################################################### } AddressBook::ErrorCode AddressBook::updateMirrorMap() { register bool GUARD; GUARD=false; // ########################################################################### kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::updateMirrorMap: updating mirror map.\n"; TQString key; Entry entry; ErrorCode ec; KabKey kk; Section *section=entrySection(); Section::StringSectionMap::iterator pos; // ----- entries->erase(entries->begin(), entries->end()); if(section==0) { kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::updateMirrorMap: done, " "no file loaded." << endl; return NoError; } for(pos=section->sectionsBegin(); pos!=section->sectionsEnd(); ++pos) { if(makeEntryFromSection((*pos).second, entry)!=NoError) { // return InternError; // it is saver to continue without a key } key=""; ec=literalName(entry, key, true, false); if(key.isEmpty() || ec!=NoError) { key=i18n("(empty entry)"); } key+=(*pos).first; // append the section name to make the key unique kk.setKey((*pos).first); entries->insert(StringKabKeyMap::value_type(key, kk)); } // ----- kdDebug(GUARD, KAB_KDEBUG_AREA) << "AddressBook::updateMirrorMap: done." << endl; return NoError; // ########################################################################### } AddressBook::ErrorCode AddressBook::makeEntryFromSection(Section* section, Entry& entry) { // ########################################################################### Section *addresses; Section *addressSection; Section::StringSectionMap::iterator pos; KeyValueMap *keys; Entry temp; Entry::Address address; Entry::Address addressDummy; int count; // ----- create the aggregats: const TQCString StringKeys[]= { "title", "rank", "fn", "nameprefix", "firstname", "middlename", "lastname", "comment", "user1", "user2", "user3", "user4" }; TQString* StringValues[]= { &temp.title, &temp.rank, &temp.fn, &temp.nameprefix, &temp.firstname, &temp.middlename, &temp.lastname, &temp.comment, &temp.user1, &temp.user2, &temp.user3, &temp.user4 }; const int StringKeySize=sizeof(StringKeys)/sizeof(StringKeys[0]); const TQCString StringListKeys[]= { "talk", "emails", "keywords", "telephone", "URLs", "custom", "categories" }; TQStringList* StringListValues[]= { &temp.talk, &temp.emails, &temp.keywords, &temp.telephone, &temp.URLs, &temp.custom, &temp.categories }; const int StringListKeySize=sizeof(StringListKeys)/sizeof(StringListKeys[0]); // ----- first parse "addresses" subsection: if(!section->find(ADDRESS_SUBSECTION, addresses)) { return InternError; // no subsection called "addresses" } for(pos=addresses->sectionsBegin(); pos!=addresses->sectionsEnd(); ++pos) { if(!addresses->find((*pos).first, addressSection)) { return InternError; // no section we have an iterator for? } keys=addressSection->getKeys(); address=addressDummy; // clean it up if(makeAddressFromMap(keys, address)==AddressBook::NoError) { // ----- add the address to the list of addresses: temp.addresses.push_back(address); } else { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::makeEntryFromSection: cannot find all fields " << "in an address subsection." << endl; } } // ----- now parse all other fields directly: keys=section->getKeys(); for(count=0; countget(StringKeys[count], *StringValues[count])) { /* Spits out lots of warnings: kdDebug(KAB_KDEBUG_AREA) << "AddressBook::makeEntryFromSection: error: could not get " << "value for key " << (const char*)StringKeys[count] << "." << endl; */ } } for(count=0; countget(StringListKeys[count], *StringListValues[count])) { /* Spits out lots of warnings: kdDebug(KAB_KDEBUG_AREA) << "AddressBook::makeEntryFromSection: error: could not get " << "value for key " << (const char*)StringListKeys[count] << "." << endl; */ } } // ----- finally get the birthday: keys->get("birthday", temp.birthday); // this may return false (no date) // ----- entry=temp; return NoError; // ########################################################################### } AddressBook::ErrorCode AddressBook::makeAddressFromMap(KeyValueMap* keys, Entry::Address& address) { // ########################################################################### const TQCString Keys[]= { "headline", "position", "org", "orgunit", "orgsubunit", // "role", "deliverylabel", "address", "zip", "town", "country", "state" }; TQString* strings[]= { &address.headline, &address.position, &address.org, &address.orgUnit, &address.orgSubUnit, // &address.role, &address.deliveryLabel, &address.address, &address.zip, &address.town, &address.country, &address.state }; const int Size=sizeof(Keys)/sizeof(Keys[0]); int count; // ----- for(count=0; countget(Keys[count], *strings[count]); } return NoError; // ########################################################################### } AddressBook::ErrorCode AddressBook::makeSectionFromEntry(const Entry& entry, Section& section) { // ########################################################################### list::const_iterator addPos; Section *addresses=0; Section *address=0; TQCString key; // used for creating address subsection keys int count=0; // counts the addresses KeyValueMap *keys; // ----- prepare the section object: section.clear(); // ----- first create "addresses" subsection: if(!section.add(ADDRESS_SUBSECTION)) { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::makeSectionFromEntry: cannot create " << "subsection." << " " << endl; return InternError; } if(!section.find(ADDRESS_SUBSECTION, addresses)) { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::makeSectionFromEntry: cannot get new section." << endl; return InternError; } // ----- now insert addresses: for(addPos=entry.addresses.begin(); addPos!=entry.addresses.end(); ++addPos) { ++count; key.setNum(count); if(!addresses->add(key)) { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::makeSectionFromEntry: cannot create address " << endl; return InternError; } if(!addresses->find(key, address)) { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::makeSectionFromEntry: cannot get new " << endl; return InternError; } keys=address->getKeys(); // ----- now insert keys into address: if(!keys->insert("headline", (*addPos).headline) || !keys->insert("position", (*addPos).position) || !keys->insert("org", (*addPos).org) || !keys->insert("orgunit", (*addPos).orgUnit) || !keys->insert("orgsubunit", (*addPos).orgSubUnit) || // !keys->insert("role", (*addPos).role) || !keys->insert("deliverylabel", (*addPos).deliveryLabel) || !keys->insert("address", (*addPos).address) || !keys->insert("zip", (*addPos).zip) || !keys->insert("town", (*addPos).town) || !keys->insert("country", (*addPos).country) || !keys->insert("state", (*addPos).state)) { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::makeSectionFromEntry: cannot completely " << "insert this address." << endl; return InternError; } } // ----- now add the other fields: keys=section.getKeys(); if(!keys->insert("title", entry.title) || !keys->insert("rank", entry.rank) || !keys->insert("fn", entry.fn) || !keys->insert("nameprefix", entry.nameprefix) || !keys->insert("firstname", entry.firstname) || !keys->insert("middlename", entry.middlename) || !keys->insert("lastname", entry.lastname) || !keys->insert("birthday", entry.birthday) || !keys->insert("comment", entry.comment) || !keys->insert("talk", entry.talk) || !keys->insert("emails", entry.emails) || !keys->insert("keywords", entry.keywords) || !keys->insert("telephone", entry.telephone) || !keys->insert("URLs", entry.URLs) || !keys->insert("user1", entry.user1) || !keys->insert("user2", entry.user2) || !keys->insert("user3", entry.user3) || !keys->insert("user4", entry.user4) || !keys->insert("custom", entry.custom) || !keys->insert("categories", entry.categories)) { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::makeEntryFromSection: cannot insert " << "all fields of the entry." << endl; return InternError; } // ----- return NoError; // ########################################################################### } AddressBook::ErrorCode AddressBook::createNew(const TQString& filename) { // ########################################################################### const TQString KabTemplateFile=locate("data", "kab/template.kab"); kdDebug(KAB_KDEBUG_AREA) << "AddressBook::createNew: template file is \"" << (const char*)KabTemplateFile.utf8() << "\"." << endl; QConfigDB db; // ----- if(KabTemplateFile.isEmpty() || !db.setFileName(KabTemplateFile, true, true)) { KMessageBox::error(this, i18n("Cannot find kab's template file.\n" "You cannot create new files."), i18n("File Error")); return InternError; } if(!db.load()) { KMessageBox::error(this, i18n("Cannot read kab's template file.\n" "You cannot create new files."), i18n("Format Error")); return InternError; } if(!db.setFileName(filename, false, false)) { KMessageBox::error(this, i18n("Cannot create the file\n\"") +filename+"\"\n"+ i18n("Could not create the new file."), i18n("File Error")); return PermDenied; } if(!db.save()) { KMessageBox::error(this, i18n("Cannot save the file\n\"") +filename+"\"\n"+ i18n("Could not create the new file."), i18n("File Error")); return InternError; } // ----- return NoError; // ########################################################################### } AddressBook::ErrorCode AddressBook::createConfigFile() { // ########################################################################### const TQString ConfigTemplateFile=locate("data", "kab/template.config"); kdDebug(KAB_KDEBUG_AREA) << "AddressBook::createConfigFile: config template file is \"" << (const char*)ConfigTemplateFile.utf8() << "\"." << endl; const TQString filename= locateLocal( "data", STD_CONFIGFILENAME); QConfigDB db; // ----- if(ConfigTemplateFile.isEmpty() || !db.setFileName(ConfigTemplateFile, true, true)) { KMessageBox::error(this, i18n("Cannot find kab's configuration template file.\n" "kab cannot be configured."), i18n("File Error")); return InternError; } if(!db.load()) { KMessageBox::error(this, i18n("Cannot read kab's configuration template file.\n" "kab cannot be configured."), i18n("File Error")); return InternError; } if(!db.setFileName(filename, false, false)) { KMessageBox::error(this, i18n("Cannot create the file\n\"") +filename+"\"\n"+ i18n("Could not create the new configuration file."), i18n("File Error")); return PermDenied; } if(!db.save()) { KMessageBox::error(this, i18n("Cannot save the file\n\"") +filename+"\"\n"+ i18n("Could not create the new configuration file."), i18n("File Error")); return InternError; } // ----- return NoError; // ########################################################################### } AddressBook::ErrorCode AddressBook::loadConfigFile() { // ########################################################################### TQString file = locateLocal( "data", STD_CONFIGFILENAME); if(config->setFileName(file, true, true)) { if(config->load()) { return NoError; } else { KMessageBox::information(this, i18n("Cannot load kab's local configuration file.\n" "There may be a formatting error.\n" "kab cannot be configured."), i18n("File Error")); return InternError; } } else { KMessageBox::information(this, i18n("Cannot find kab's local configuration file.\n" "kab cannot be configured."), i18n("File Error")); return NoSuchFile; } // ########################################################################### } AddressBook::ErrorCode AddressBook::makeVCardFromEntry(const Entry&, const TQString&) { // ########################################################################### return NotImplemented; // ########################################################################### } AddressBook::ErrorCode AddressBook::makeEntryFromVCard(const TQString&, Entry&) { // ########################################################################### return NotImplemented; // ########################################################################### } TQString AddressBook::getStandardFileName() { // ########################################################################### return locateLocal( "data", STD_USERFILENAME); // ########################################################################### } TQString AddressBook::phoneType(AddressBook::Telephone phone) { switch(phone) { case Fixed: return i18n("fixed"); break; case Mobile: return i18n("mobile"); break; case Fax: return i18n("fax"); break; case Modem: return i18n("modem"); break; default: return i18n("general"); } } void AddressBook::externalChange() { updateMirrorMap(); } Section* AddressBook::configurationSection() { Section *section; if(data!=0) { if(data->get(LOCAL_CONFIG_SECTION, section)) { return section; } else { return 0; } } else { return 0; } } AddressBook::ErrorCode AddressBook::Entry::get(const char* fieldname, TQVariant& field) { // "title", "rank", "fn", "nameprefix", "firstname", "middlename", "lastname", // "birthday", "comment", "talk", "emails", "keywords", "telephone", // "urls", "user1", "user2", "user3", "user4", "custom" int dummy=0; // ----- if(fieldname==Fields[dummy++]) { // the title field=title; return NoError; } if(fieldname==Fields[dummy++]) { // the rank field=rank; return NoError; } if(fieldname==Fields[dummy++]) { // the formatted name field=fn; return NoError; } if(fieldname==Fields[dummy++]) { // the nameprefix field=nameprefix; return NoError; } if(fieldname==Fields[dummy++]) { // the firstname field=firstname; return NoError; } if(fieldname==Fields[dummy++]) { // the middle name field=middlename; return NoError; } if(fieldname==Fields[dummy++]) { // the last name field=lastname; return NoError; } if(fieldname==Fields[dummy++]) { // the birthday field=TQString(birthday.toString()); return NoError; } if(fieldname==Fields[dummy++]) { // the comment field=comment; return NoError; } if(fieldname==Fields[dummy++]) { // the talk addresses field=talk; return NoError; } if(fieldname==Fields[dummy++]) { // the email addresses field=emails; return NoError; } if(fieldname==Fields[dummy++]) { // the keywords field=keywords; return NoError; } if(fieldname==Fields[dummy++]) { // the telephones field=telephone; return NoError; } if(fieldname==Fields[dummy++]) { // the urls field=URLs; return NoError; } if(fieldname==Fields[dummy++]) { // the user field 1 field=user1; return NoError; } if(fieldname==Fields[dummy++]) { // the user field 2 field=user2; return NoError; } if(fieldname==Fields[dummy++]) { // the user field 3 field=user3; return NoError; } if(fieldname==Fields[dummy++]) { // the user field 4 field=user4; return NoError; } if(fieldname==Fields[dummy++]) { // the custom fields (app specific) field=custom; return NoError; } // ----- we did not find that field: return NoSuchField; } AddressBook::ErrorCode AddressBook::Entry::Address::get(const char* fieldname, TQVariant& field) { // "headline", "position", // "org", "orgunit", "orgsubunit", // "deliverylabel", "address", "zip", "town", "country", "state" int dummy=0; // ----- if(fieldname==Fields[dummy++]) { // the headline field=headline; return NoError; } if(fieldname==Fields[dummy++]) { // the position field=position; return NoError; } if(fieldname==Fields[dummy++]) { // the organization field=org; return NoError; } if(fieldname==Fields[dummy++]) { // the organizational unit field=orgUnit; return NoError; } if(fieldname==Fields[dummy++]) { // the organizational subunit field=orgSubUnit; return NoError; } if(fieldname==Fields[dummy++]) { // the delivery label field=deliveryLabel; return NoError; } if(fieldname==Fields[dummy++]) { // the address field=address; return NoError; } if(fieldname==Fields[dummy++]) { // the zip code field=zip; return NoError; } if(fieldname==Fields[dummy++]) { // the town field=town; return NoError; } if(fieldname==Fields[dummy++]) { // the country field=country; return NoError; } if(fieldname==Fields[dummy++]) { // the state field=state; return NoError; } // ----- we did not find that field: return NoSuchField; } Section* AddressBook::categoriesSection() { const TQString Predefines[]= { i18n("Business"), i18n("Private"), i18n("Dates") }; size_t Size=sizeof(Predefines)/sizeof(Predefines[0]); Section* section; Section* categories; KeyValueMap *keys; // ----- if(data->get(KAB_CATEGORY_KEY, section)) { // it exists, go ahead return section; } else { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::categoriesSection: creating categories structure." << endl; // it does not exist - create it if(!data->createSection(KAB_CATEGORY_KEY)) { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::categoriesSection: error creating categories section." << endl; return 0; } data->get(KAB_CATEGORY_KEY, section); // add the predefined categories: categories=new Section; keys=categories->getKeys(); for(size_t count=0; countinsert(TQCString().setNum(count), values); } section->add(KAB_CATEGORY_KEY, categories); keys=section->getKeys(); keys->insert("NextAvailableCatKey", (long)Size); } save(); if(data->get(KAB_CATEGORY_KEY, section)) return section; return 0; // might not happen } AddressBook::ErrorCode AddressBook::categories(CategoriesMap& cat) { // WORK_TO_DO: use a permanent cached map and update on changed() kdDebug(KAB_KDEBUG_AREA, !cat.isEmpty()) << "AddressBook::categories: warning - categories map is supposed to be empty!" << endl; Section *section; Section *categories; KeyValueMap* keys; int key; bool rc; TQStringList values; StringStringMap::iterator pos; // ----- query categories section: section=categoriesSection(); TQ_CHECK_PTR(section); // ----- if(!section->find(KAB_CATEGORY_KEY, categories)) { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::categories: error in database structure." << endl; return InternError; } // ----- everything is set up, create the categories map: // use an iterator to walk over all elements of categories key-value-map: keys=categories->getKeys(); for(pos=keys->begin(); pos!=keys->end(); ++pos) { if(!keys->get((*pos).first, values)) { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::categories: internal error querying categories." << endl; } else { key=(*pos).first.toInt(&rc); if(rc) { cat.insert(key, values[0]); } else { kdDebug(KAB_KDEBUG_AREA) << "AddressBook::categories: error - non-integer category key - ignored." << endl; } } } return NoError; } #include "addressbook.moc"