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