Trees | Indices | Help |
|
---|
|
1 """ 2 Synchronize with local VCF file 3 4 This file is part of Pisi. 5 6 VCF support is based on the VOBJECT library by skyhouseconsulting (U{http://vobject.skyhouseconsulting.com/}). 7 Consequently, the vobject site-package has to be installed for utilizing vcard support in PISI. 8 9 Pisi is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Pisi is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Pisi. If not, see <http://www.gnu.org/licenses/>. 21 """ 22 23 import sys,os,datetime 24 # Allows us to import event 25 sys.path.insert(0,os.path.abspath(__file__+"/../..")) 26 from contacts import contacts 27 import vobject 28 import os.path 29 import os 30 from pisiconstants import * 31 import pisiprogress 32 from vobjecttools import * 33 34 PATH_INTERACTIVE = "@interactive" 35 """Option in configuration file for supplying filename and path of VCF file interactively""" 36 DEFAULT_PHONETYPE = 'mobile' 37 """Phone type to use if none is provided in VCF file and user has not provided a default in config file for this source""" 3840 """ 41 The implementation of the interface L{contacts.AbstractContactSynchronizationModule} for VCF file persistence backend 42 """17444 """ 45 Constructor 46 47 Super class constructor (L{contacts.AbstractContactSynchronizationModule.__init__}) is called. 48 Local variables are initialized. 49 The settings from the configuration file are loaded. 50 """ 51 contacts.AbstractContactSynchronizationModule.__init__(self, verbose, soft, modulesString, config, configsection, "VCF") 52 self._vcfpath = config.get(configsection,'vcfpath') 53 try: 54 self._defaultPhone = config.get(configsection,'default_phonetype') 55 except: 56 self._defaultPhone = DEFAULT_PHONETYPE 57 self._folder = folder 58 pisiprogress.getCallback().verbose("contact VCF module loaded using file %s" %(self._vcfpath)) 59 self._rawData = {}6062 """ 63 Asks for user input on console 64 """ 65 if description: 66 pisiprogress.getCallback().message(description) 67 return pisiprogress.getCallback().promptFilename(prompt, default)6870 """ 71 Try to determine roughly how many entries are in this file (we can't know prior to parsing; but we have a guess using the file size) 72 """ 73 info = os.stat(self._vcfpath) 74 return info.st_size / VCF_BYTES_PER_ENTRY7577 """ 78 Load all data from local VCF file 79 80 File opened and the entries are parsed. For each entry a L{contacts.contacts.Contact} instance is created and stored in the instance dictionary 81 L{contacts.AbstractContactSynchronizationModule._allContacts}. 82 """ 83 pisiprogress.getCallback().verbose ("VCF: Loading") 84 if self._vcfpath == PATH_INTERACTIVE: 85 self._vcfpath = self._promptFilename("\tPath to VCF file ", "pisi_export.vcf", "You configured PISI VCF support to ask for VCF file name when running.") 86 87 file = None 88 try: 89 file = open(self._vcfpath, "r") 90 except IOError, e: 91 pisiprogress.getCallback().error("--> Error: Could not load VCF file - we still carry on with processing:\n\t%s" %(e)) 92 return 93 94 pisiprogress.getCallback().progress.push(0, 100) 95 comps = vobject.readComponents(file) 96 pisiprogress.getCallback().progress.setProgress(20) 97 pisiprogress.getCallback().update("Loading") 98 amount = self._guessAmount() 99 i = 0 100 for x in comps: 101 atts = extractVcfEntry(x, self._defaultPhone) 102 103 id = contacts.assembleID(atts) 104 c = contacts.Contact(id, atts) 105 self._allContacts[id] = c 106 self._rawData[id] = x 107 if i < amount: 108 i += 1 109 if amount: 110 pisiprogress.getCallback().progress.setProgress(20 + ((i*80) / amount)) 111 pisiprogress.getCallback().update('Loading') 112 113 file.close() 114 pisiprogress.getCallback().progress.drop()115117 """ 118 Checks each entry, whether all mandatory fields are available. 119 120 Delegates request to vobjecttools. 121 """ 122 checkForMandatoryFields(self._rawData)123 124126 """ 127 Save whatever changes have come by 128 129 We first make a backup of the old file. Then, the entire set of information is dumped into a new file. (I hope, you don't mind the order of your entries). 130 Thereby, we shouldn't create entries from the scratch when they were not changed in the meantime (in the likely case of PISI not supporting all fields 131 within the VCF format and file). 132 """ 133 pisiprogress.getCallback().verbose("VCF module: I apply %d changes now" %(len(self._history))) 134 135 if len(self._history) == 0: 136 return # don't touch anything if there haven't been any changes 137 138 # rename old file 139 try: 140 bakFilename = os.path.join(self._folder, os.path.basename(self._vcfpath)) 141 os.rename(self._vcfpath, bakFilename) 142 except OSError, e: 143 pisiprogress.getCallback().verbose("\tError when backing up old VCF file - we still carry on with processing:\n\t%s" %(e)) 144 145 # there is no unique key for contacts at all in VCF files; we have to use our global keys (name + given name) 146 147 file = open(self._vcfpath, "w") 148 149 i = 0 150 for actionItem in self._history: 151 action = actionItem[0] 152 contactID = actionItem[1] 153 if action == ACTIONID_DELETE: 154 del self._rawData[contactID] 155 pisiprogress.getCallback().verbose("\t\t<vcf> deleting %s" %(contactID)) 156 elif action == ACTIONID_ADD or action == ACTIONID_MODIFY: 157 c = self.getContact(contactID) 158 self._rawData[contactID] = createRawVcard(c) 159 pisiprogress.getCallback().verbose("\t\t<vcf> adding or replacing %s" %(contactID)) 160 i+=1 161 pisiprogress.getCallback().progress.setProgress(i * 70 / len(self._history)) 162 pisiprogress.getCallback().update('Storing') 163 164 self._checkForMandatoryFields() 165 pisiprogress.getCallback().progress.setProgress(70) 166 pisiprogress.getCallback().update('Storing') 167 168 pisiprogress.getCallback().verbose("\tVCF: Writing through file") 169 for x in self._rawData.values(): 170 file.write(x.serialize()) 171 file.write("\n") 172 pisiprogress.getCallback().verbose("\tNew VCF file saved to %s; \n\tbackup file is located in %s." %(self._vcfpath, bakFilename)) 173 file.close()
Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Fri Apr 2 09:04:25 2010 | http://epydoc.sourceforge.net |