Adding the ignore file
[gc-dialer] / src / backends / file_backend.py
1 #!/usr/bin/python
2
3 """
4 DialCentral - Front end for Google's Grand Central service.
5 Copyright (C) 2008  Eric Warnke ericew AT gmail DOT com
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20
21 Filesystem backend for contact support
22 """
23
24
25 import os
26 import re
27 import csv
28
29
30 class CsvAddressBook(object):
31         """
32         Currently supported file format
33         @li Has the first line as a header
34         @li Escapes with quotes
35         @li Comma as delimiter
36         @li Column 0 is name, column 1 is number
37         """
38
39         _nameRe = re.compile("name", re.IGNORECASE)
40         _phoneRe = re.compile("phone", re.IGNORECASE)
41         _mobileRe = re.compile("mobile", re.IGNORECASE)
42
43         def __init__(self, csvPath):
44                 self.__csvPath = csvPath
45                 self.__contacts = list(
46                         self.read_csv(csvPath)
47                 )
48
49         @classmethod
50         def read_csv(cls, csvPath):
51                 try:
52                         csvReader = iter(csv.reader(open(csvPath, "rU")))
53                 except IOError, e:
54                         if e.errno != 2:
55                                 raise
56                         return
57
58                 header = csvReader.next()
59                 nameColumn, phoneColumns = cls._guess_columns(header)
60
61                 yieldCount = 0
62                 for row in csvReader:
63                         contactDetails = []
64                         for (phoneType, phoneColumn) in phoneColumns:
65                                 try:
66                                         if len(row[phoneColumn]) == 0:
67                                                 continue
68                                         contactDetails.append((phoneType, row[phoneColumn]))
69                                 except IndexError:
70                                         pass
71                         if len(contactDetails) != 0:
72                                 yield str(yieldCount), row[nameColumn], contactDetails
73                                 yieldCount += 1
74
75         @classmethod
76         def _guess_columns(cls, row):
77                 names = []
78                 phones = []
79                 for i, item in enumerate(row):
80                         if cls._nameRe.search(item) is not None:
81                                 names.append((item, i))
82                         elif cls._phoneRe.search(item) is not None:
83                                 phones.append((item, i))
84                         elif cls._mobileRe.search(item) is not None:
85                                 phones.append((item, i))
86                 if len(names) == 0:
87                         names.append(("Name", 0))
88                 if len(phones) == 0:
89                         phones.append(("Phone", 1))
90
91                 return names[0][1], phones
92
93         def clear_caches(self):
94                 pass
95
96         @staticmethod
97         def factory_name():
98                 return "csv"
99
100         @staticmethod
101         def contact_source_short_name(contactId):
102                 return "csv"
103
104         def get_contacts(self):
105                 """
106                 @returns Iterable of (contact id, contact name)
107                 """
108                 for contact in self.__contacts:
109                         yield contact[0:2]
110
111         def get_contact_details(self, contactId):
112                 """
113                 @returns Iterable of (Phone Type, Phone Number)
114                 """
115                 contactId = int(contactId)
116                 return iter(self.__contacts[contactId][2])
117
118
119 class FilesystemAddressBookFactory(object):
120
121         FILETYPE_SUPPORT = {
122                 "csv": CsvAddressBook,
123         }
124
125         def __init__(self, path):
126                 self.__path = path
127
128         def clear_caches(self):
129                 pass
130
131         def get_addressbooks(self):
132                 """
133                 @returns Iterable of (Address Book Factory, Book Id, Book Name)
134                 """
135                 for root, dirs, filenames in os.walk(self.__path):
136                         for filename in filenames:
137                                 try:
138                                         name, ext = filename.rsplit(".", 1)
139                                 except ValueError:
140                                         continue
141
142                                 if ext in self.FILETYPE_SUPPORT:
143                                         yield self, os.path.join(root, filename), name
144
145         def open_addressbook(self, bookId):
146                 name, ext = bookId.rsplit(".", 1)
147                 assert ext in self.FILETYPE_SUPPORT, "Unsupported file extension %s" % ext
148                 return self.FILETYPE_SUPPORT[ext](bookId)
149
150         @staticmethod
151         def factory_name():
152                 return "File"
153
154
155 def print_filebooks(contactPath = None):
156         """
157         Included here for debugging.
158
159         Either insert it into the code or launch python with the "-i" flag
160         """
161         if contactPath is None:
162                 contactPath = os.path.join(os.path.expanduser("~"), ".dialcentral", "contacts")
163
164         abf = FilesystemAddressBookFactory(contactPath)
165         for book in abf.get_addressbooks():
166                 ab = abf.open_addressbook(book[1])
167                 print book
168                 for contact in ab.get_contacts():
169                         print "\t", contact
170                         for details in ab.get_contact_details(contact[0]):
171                                 print "\t\t", details