def __init__(self): self.config = None self.address_book_list = [] self.uid_dict = {} # load config file xdg_config_home = os.environ.get("XDG_CONFIG_HOME") or \ os.path.expanduser("~/.config") config_file = os.environ.get("KHARD_CONFIG") or \ os.path.join(xdg_config_home, "khard", "khard.conf") if os.path.exists(config_file) == False: print("Config file %s not available" % config_file) sys.exit(2) self.config = ConfigObj(config_file, interpolation=False) # general settings if self.config.has_key("general") == False: print("Error in config file\nMissing main section \"[general]\".") sys.exit(2) # editor self.config['general']['editor'] = self.config['general'].get("editor") \ or os.environ.get("EDITOR") if self.config['general']['editor'] is None: print("Error in config file\n" \ "Set path to your preferred text editor in khard's config file or the $EDITOR shell variable\n" \ "Example for khard.conf: editor = vim") sys.exit(2) self.config['general']['editor'] = find_executable( os.path.expanduser(self.config['general']['editor'])) if self.config['general']['editor'] is None: print("Error in config file\nInvalid editor path or executable not found.") sys.exit(2) # merge editor self.config['general']['merge_editor'] = self.config['general'].get("merge_editor") \ or os.environ.get("MERGE_EDITOR") if self.config['general']['merge_editor'] is None: print("Error in config file\n" \ "Set path to your preferred text merge editor in khard's config file or the $MERGE_EDITOR shell variable\n" \ "Example for khard.conf: merge_editor = vimdiff") sys.exit(2) self.config['general']['merge_editor'] = find_executable( os.path.expanduser(self.config['general']['merge_editor'])) if self.config['general']['merge_editor'] is None: print("Error in config file\nInvalid merge editor path or executable not found.") sys.exit(2) # default values for action and nickname settings if self.config['general'].has_key("default_action") == False: print("Error in config file\nMissing default action parameter.") sys.exit(2) elif self.config['general']['default_action'] not in self.get_list_of_actions(): print("Error in config file\n" \ "Non existing value for default action parameter\n" \ "Possible values are: %s" % ', '.join(self.get_list_of_actions())) sys.exit(2) if self.config['general'].has_key("show_nicknames") == False: self.config['general']['show_nicknames'] = False elif self.config['general']['show_nicknames'] == "yes": self.config['general']['show_nicknames'] = True elif self.config['general']['show_nicknames'] == "no": self.config['general']['show_nicknames'] = False else: print("Error in config file\nshow_nicknames parameter must be yes or no.") sys.exit(2) # load address books and contacts error_counter = 0 number_of_contacts = 0 if self.config.has_key("addressbooks") == False: print("Error in config file\nMissing main section \"[addressbooks]\".") sys.exit(2) if len(self.config['addressbooks'].keys()) == 0: print("Error in config file\nNo address book entries available.") sys.exit(2) for name in self.config['addressbooks'].keys(): # create address book object try: address_book = AddressBook(name, self.config['addressbooks'][name]['path']) except KeyError as e: print("Error in config file\nMissing path to the \"%s\" address book." % name) sys.exit(2) except IOError as e: print("Error in config file\n%s" % e) sys.exit(2) # load all vcard files for filename in glob.glob(os.path.join(address_book.get_path(), "*.vcf")): try: address_book.add_contact( CarddavObject.from_file(address_book, filename)) number_of_contacts += 1 except IOError as e: print("Error: Could not open file %s\n%s" % (filename, e)) error_counter += 1 except vobject.base.ParseError as e: print("Error: Could not parse file %s\n%s" % (filename, e)) error_counter += 1 # add address book to list self.address_book_list.append(address_book) # check if one or more contacts could not be parsed if error_counter > 0: print("\n%d of %d vcard files could not be parsed" % (error_counter, number_of_contacts)) sys.exit(2) # check, if multiple contacts have the same uid length_of_shortest_uid = 100 number_of_contacts_with_uid = 0 for address_book in self.address_book_list: for contact in address_book.get_contact_list(): uid = contact.get_uid() if uid != "": matching_contact = self.uid_dict.get(uid) if matching_contact is None: self.uid_dict[uid] = contact number_of_contacts_with_uid += 1 if len(uid) < length_of_shortest_uid: length_of_shortest_uid = len(uid) else: print("The contact %s from address book %s" \ " and the contact %s from address book %s have the same uid %s" \ % (matching_contact.get_full_name(), matching_contact.get_address_book().get_name(), contact.get_full_name(), contact.get_address_book().get_name(), contact.get_uid()) ) sys.exit(2) # now we can be sure, that all uid's are unique but we don't want to enter # the whole uid, if we choose a contact by the -u / --uid option # so clear previously filled uid_dict and recreate with the shortest possible uid, so # that it's still unique and easier to enter # with around 100 contacts that short id should not be longer then two or three characters length_of_uid = 1 while True: self.uid_dict.clear() for address_book in self.address_book_list: for contact in address_book.get_contact_list(): uid = contact.get_uid()[:length_of_uid] if uid != "": self.uid_dict[uid] = contact if len(self.uid_dict.keys()) != number_of_contacts_with_uid: length_of_uid += 1 else: break if length_of_uid == length_of_shortest_uid: # prevent infinit loop, # should not be necessary, cause we checked the uid uniqueness in the previous step # so it's just a precaution print("Could not create the dictionary of the short uid's") sys.exit(2)
def __init__(self): self.config = None self.address_book_list = [] self.uid_dict = {} # load config file xdg_config_home = os.environ.get("XDG_CONFIG_HOME") or \ os.path.expanduser("~/.config") config_file = os.environ.get("KHARD_CONFIG") or \ os.path.join(xdg_config_home, "khard", "khard.conf") if os.path.exists(config_file) == False: print("Config file %s not available" % config_file) sys.exit(2) self.config = ConfigObj(config_file, interpolation=False) # general settings if self.config.has_key("general") == False: print("Error in config file\nMissing main section \"[general]\".") sys.exit(2) # editor self.config['general']['editor'] = self.config['general'].get("editor") \ or os.environ.get("EDITOR") if self.config['general']['editor'] is None: print("Error in config file\n" \ "Set path to your preferred text editor in khard's config file or the $EDITOR shell variable\n" \ "Example for khard.conf: editor = vim") sys.exit(2) self.config['general']['editor'] = find_executable( os.path.expanduser(self.config['general']['editor'])) if self.config['general']['editor'] is None: print("Error in config file\nInvalid editor path or executable not found.") sys.exit(2) # merge editor self.config['general']['merge_editor'] = self.config['general'].get("merge_editor") \ or os.environ.get("MERGE_EDITOR") if self.config['general']['merge_editor'] is None: print("Error in config file\n" \ "Set path to your preferred text merge editor in khard's config file or the $MERGE_EDITOR shell variable\n" \ "Example for khard.conf: merge_editor = vimdiff") sys.exit(2) self.config['general']['merge_editor'] = find_executable( os.path.expanduser(self.config['general']['merge_editor'])) if self.config['general']['merge_editor'] is None: print("Error in config file\nInvalid merge editor path or executable not found.") sys.exit(2) # default action if self.config['general'].has_key("default_action") == False: print("Error in config file\nMissing default action parameter.") sys.exit(2) elif self.config['general']['default_action'] not in self.get_list_of_actions(): print("Error in config file\n" \ "Invalid value for default_action parameter\n" \ "Possible values: %s" % ', '.join(self.get_list_of_actions())) sys.exit(2) # contact table settings if self.config.has_key("contact table") == False: self.config['contact table'] = {} # sort contacts table by first or last name if self.config['contact table'].has_key("sort") == False: self.config['contact table']['sort'] = "first_name" elif self.config['contact table']['sort'] not in ["first_name", "last_name"]: print("Error in config file\n" \ "Invalid value for sort parameter\n" \ "Possible values: first_name, last_name") sys.exit(2) # reverse contact table if self.config['contact table'].has_key("reverse") == False: self.config['contact table']['reverse'] = False elif self.config['contact table']['reverse'] == "yes": self.config['contact table']['reverse'] = True elif self.config['contact table']['reverse'] == "no": self.config['contact table']['reverse'] = False else: print("Error in config file\n" \ "Invalid value for reverse parameter\n" \ "Possible values: yes, no") sys.exit(2) # group contact table by address book if self.config['contact table'].has_key("group_by_addressbook") == False: self.config['contact table']['group_by_addressbook'] = False elif self.config['contact table']['group_by_addressbook'] == "yes": self.config['contact table']['group_by_addressbook'] = True elif self.config['contact table']['group_by_addressbook'] == "no": self.config['contact table']['group_by_addressbook'] = False else: print("Error in config file\n" \ "Invalid value for group_by_addressbook parameter\n" \ "Possible values: yes, no") sys.exit(2) # nickname if self.config['contact table'].has_key("show_nicknames") == False: self.config['contact table']['show_nicknames'] = False elif self.config['contact table']['show_nicknames'] == "yes": self.config['contact table']['show_nicknames'] = True elif self.config['contact table']['show_nicknames'] == "no": self.config['contact table']['show_nicknames'] = False else: print("Error in config file\n" \ "Invalid value for show_nicknames parameter\n" \ "Possible values: yes, no") sys.exit(2) # show uids if self.config['contact table'].has_key("show_uids") == False: self.config['contact table']['show_uids'] = True elif self.config['contact table']['show_uids'] == "yes": self.config['contact table']['show_uids'] = True elif self.config['contact table']['show_uids'] == "no": self.config['contact table']['show_uids'] = False else: print("Error in config file\n" \ "Invalid value for show_uids parameter\n" \ "Possible values: yes, no") sys.exit(2) # load address books and contacts error_counter = 0 number_of_contacts = 0 if self.config.has_key("addressbooks") == False: print("Error in config file\nMissing main section \"[addressbooks]\".") sys.exit(2) if len(self.config['addressbooks'].keys()) == 0: print("Error in config file\nNo address book entries available.") sys.exit(2) for name in self.config['addressbooks'].keys(): # create address book object try: address_book = AddressBook(name, self.config['addressbooks'][name]['path']) except KeyError as e: print("Error in config file\nMissing path to the \"%s\" address book." % name) sys.exit(2) except IOError as e: print("Error in config file\n%s" % e) sys.exit(2) # load all vcard files for filename in glob.glob(os.path.join(address_book.get_path(), "*.vcf")): try: address_book.add_contact( CarddavObject.from_file(address_book, filename)) number_of_contacts += 1 except IOError as e: print("Error: Could not open file %s\n%s" % (filename, e)) error_counter += 1 except vobject.base.ParseError as e: print("Error: Could not parse file %s\n%s" % (filename, e)) error_counter += 1 # add address book to list self.address_book_list.append(address_book) # check if one or more contacts could not be parsed if error_counter > 0: print("\n%d of %d vcard files could not be parsed" % (error_counter, number_of_contacts)) sys.exit(2) # check uniqueness of vcard uids and create short uid dictionary # that can be disabled with the show_uids option in the config file, if desired if self.config['contact table']['show_uids']: # check, if multiple contacts have the same uid flat_contact_list = [] for address_book in self.address_book_list: for contact in address_book.get_contact_list(): uid = contact.get_uid() if bool(uid): matching_contact = self.uid_dict.get(uid) if matching_contact is None: self.uid_dict[uid] = contact else: print("The contact %s from address book %s" \ " and the contact %s from address book %s have the same uid %s" \ % (matching_contact.get_full_name(), matching_contact.get_address_book().get_name(), contact.get_full_name(), contact.get_address_book().get_name(), contact.get_uid()) ) sys.exit(2) # add to flat contact list flat_contact_list.append(contact) # now we can be sure, that all uid's are unique but we don't want to enter # the whole uid, if we choose a contact by the -u / --uid option # so clear previously filled uid_dict and recreate with the shortest possible uid, so # that it's still unique and easier to enter # with around 100 contacts that short id should not be longer then two or three characters self.uid_dict.clear() flat_contact_list.sort(key = lambda x: x.get_uid()) if len(flat_contact_list) == 1: current = flat_contact_list[0] self.uid_dict[current.get_uid()[:1]] = current elif len(flat_contact_list) > 1: # first list element current = flat_contact_list[0] next = flat_contact_list[1] same = helpers.compare_uids(current.get_uid(), next.get_uid()) self.uid_dict[current.get_uid()[:same+1]] = current # list elements 1 to len(flat_contact_list)-1 for index in range(1, len(flat_contact_list)-1): prev = flat_contact_list[index-1] current = flat_contact_list[index] next = flat_contact_list[index+1] same = max( helpers.compare_uids(prev.get_uid(), current.get_uid()), helpers.compare_uids(current.get_uid(), next.get_uid())) self.uid_dict[current.get_uid()[:same+1]] = current # last list element prev = flat_contact_list[-2] current = flat_contact_list[-1] same = helpers.compare_uids(prev.get_uid(), current.get_uid()) self.uid_dict[current.get_uid()[:same+1]] = current