ddd89b3050423165c5057994a71f718506c71d94
[gc-dialer] / src / 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                 csvReader = iter(csv.reader(open(csvPath, "rU")))
52
53                 header = csvReader.next()
54                 nameColumn, phoneColumns = cls._guess_columns(header)
55
56                 yieldCount = 0
57                 for row in csvReader:
58                         contactDetails = []
59                         for (phoneType, phoneColumn) in phoneColumns:
60                                 try:
61                                         if len(row[phoneColumn]) == 0:
62                                                 continue
63                                         contactDetails.append((phoneType, row[phoneColumn]))
64                                 except IndexError:
65                                         pass
66                         if len(contactDetails) != 0:
67                                 yield str(yieldCount), row[nameColumn], contactDetails
68                                 yieldCount += 1
69
70         @classmethod
71         def _guess_columns(cls, row):
72                 names = []
73                 phones = []
74                 for i, item in enumerate(row):
75                         if cls._nameRe.search(item) is not None:
76                                 names.append((item, i))
77                         elif cls._phoneRe.search(item) is not None:
78                                 phones.append((item, i))
79                         elif cls._mobileRe.search(item) is not None:
80                                 phones.append((item, i))
81                 if len(names) == 0:
82                         names.append(("Name", 0))
83                 if len(phones) == 0:
84                         phones.append(("Phone", 1))
85
86                 return names[0][1], phones
87
88         def clear_caches(self):
89                 pass
90
91         @staticmethod
92         def factory_name():
93                 return "csv"
94
95         @staticmethod
96         def contact_source_short_name(contactId):
97                 return "csv"
98
99         def get_contacts(self):
100                 """
101                 @returns Iterable of (contact id, contact name)
102                 """
103                 for contact in self.__contacts:
104                         yield contact[0:2]
105
106         def get_contact_details(self, contactId):
107                 """
108                 @returns Iterable of (Phone Type, Phone Number)
109                 """
110                 contactId = int(contactId)
111                 return iter(self.__contacts[contactId][2])
112
113
114 class FilesystemAddressBookFactory(object):
115
116         FILETYPE_SUPPORT = {
117                 "csv": CsvAddressBook,
118         }
119
120         def __init__(self, path):
121                 self.__path = path
122
123         def clear_caches(self):
124                 pass
125
126         def get_addressbooks(self):
127                 """
128                 @returns Iterable of (Address Book Factory, Book Id, Book Name)
129                 """
130                 for root, dirs, filenames in os.walk(self.__path):
131                         for filename in filenames:
132                                 name, ext = filename.rsplit(".", 1)
133                                 if ext in self.FILETYPE_SUPPORT:
134                                         yield self, os.path.join(root, filename), name
135
136         def open_addressbook(self, bookId):
137                 name, ext = bookId.rsplit(".", 1)
138                 assert ext in self.FILETYPE_SUPPORT
139                 return self.FILETYPE_SUPPORT[ext](bookId)
140
141         @staticmethod
142         def factory_name():
143                 return "File"
144
145
146 def print_filebooks(contactPath = None):
147         """
148         Included here for debugging.
149
150         Either insert it into the code or launch python with the "-i" flag
151         """
152         if contactPath is None:
153                 contactPath = os.path.join(os.path.expanduser("~"), ".dialcentral", "contacts")
154
155         abf = FilesystemAddressBookFactory(contactPath)
156         for book in abf.get_addressbooks():
157                 ab = abf.open_addressbook(book[1])
158                 print book
159                 for contact in ab.get_contacts():
160                         print "\t", contact
161                         for details in ab.get_contact_details(contact[0]):
162                                 print "\t\t", details