Imitiating buttfly in being explicitly typed
[theonering] / src / channel / debug_prompt.py
1 from __future__ import with_statement
2
3 import os
4 import cmd
5 import StringIO
6 import time
7 import datetime
8 import logging
9
10 import telepathy
11
12 import constants
13 import tp
14 import util.misc as misc_utils
15 import util.go_utils as gobject_utils
16 import gvoice
17
18
19 _moduleLogger = logging.getLogger(__name__)
20
21
22 class DebugPromptChannel(tp.ChannelTypeText, cmd.Cmd):
23
24         def __init__(self, connection, manager, props, contactHandle):
25                 self.__manager = manager
26                 self.__props = props
27
28                 cmd.Cmd.__init__(self, "Debug Prompt")
29                 self.use_rawinput = False
30                 tp.ChannelTypeText.__init__(self, connection, manager, props)
31                 self.__nextRecievedId = 0
32                 self.__lastMessageTimestamp = datetime.datetime(1, 1, 1)
33
34                 self.__otherHandle = contactHandle
35
36         @misc_utils.log_exception(_moduleLogger)
37         def Send(self, messageType, text):
38                 if messageType != telepathy.CHANNEL_TEXT_MESSAGE_TYPE_NORMAL:
39                         raise telepathy.errors.NotImplemented("Unhandled message type: %r" % messageType)
40
41                 self.Sent(int(time.time()), messageType, text)
42
43                 oldStdin, oldStdout = self.stdin, self.stdout
44                 try:
45                         self.stdin = currentStdin = StringIO.StringIO()
46                         self.stdout = currentStdout = StringIO.StringIO()
47                         self.onecmd(text)
48                 finally:
49                         self.stdin, self.stdout = oldStdin, oldStdout
50
51                 stdoutData = currentStdout.getvalue().strip()
52                 if stdoutData:
53                         self._report_new_message(stdoutData)
54
55         @misc_utils.log_exception(_moduleLogger)
56         def Close(self):
57                 self.close()
58
59         def close(self):
60                 _moduleLogger.debug("Closing debug")
61                 tp.ChannelTypeText.Close(self)
62                 self.remove_from_connection()
63
64         def _report_new_message(self, message):
65                 currentReceivedId = self.__nextRecievedId
66
67                 timestamp = int(time.time())
68                 type = telepathy.CHANNEL_TEXT_MESSAGE_TYPE_NORMAL
69
70                 self.Received(currentReceivedId, timestamp, self.__otherHandle, type, 0, message.strip())
71
72                 self.__nextRecievedId += 1
73
74         def do_reset_state_machine(self, args):
75                 try:
76                         args = args.strip().lower()
77                         if not args:
78                                 args  = "all"
79                         if args == "all":
80                                 for machine in self._conn.session.stateMachine._machines:
81                                         machine.reset_timers()
82                         elif args == "contacts":
83                                 self._conn.session.addressbookStateMachine.reset_timers()
84                         elif args == "voicemail":
85                                 self._conn.session.voicemailsStateMachine.reset_timers()
86                         elif args == "texts":
87                                 self._conn.session.textsStateMachine.reset_timers()
88                         else:
89                                 self._report_new_message('Unknown machine "%s"' % (args, ))
90                 except Exception, e:
91                         self._report_new_message(str(e))
92
93         def help_reset_state_machine(self):
94                 self._report_new_message("""Reset the refreshing state machine.
95 "reset_state_machine" - resets all
96 "reset_state_machine all"
97 "reset_state_machine contacts"
98 "reset_state_machine voicemail"
99 "reset_state_machine texts"
100 """)
101
102         def do_get_state(self, args):
103                 if args:
104                         self._report_new_message("No arguments supported")
105                         return
106
107                 try:
108                         state = self._conn.session.stateMachine.state
109                         self._report_new_message(str(state))
110                 except Exception, e:
111                         self._report_new_message(str(e))
112
113         def help_get_state(self):
114                 self._report_new_message("Print the current state the refreshing state machine is in")
115
116         def do_get_polling(self, args):
117                 if args:
118                         self._report_new_message("No arguments supported")
119                         return
120                 self._report_new_message("\n".join((
121                         "Contacts:", repr(self._conn.session.addressbookStateMachine)
122                 )))
123                 self._report_new_message("\n".join((
124                         "Voicemail:", repr(self._conn.session.voicemailsStateMachine)
125                 )))
126                 self._report_new_message("\n".join((
127                         "Texts:", repr(self._conn.session.textsStateMachine)
128                 )))
129
130         def help_get_polling(self):
131                 self._report_new_message("Prints the frequency each of the state machines updates")
132
133         def do_get_state_status(self, args):
134                 if args:
135                         self._report_new_message("No arguments supported")
136                         return
137                 self._report_new_message("\n".join((
138                         "Contacts:", str(self._conn.session.addressbookStateMachine)
139                 )))
140                 self._report_new_message("\n".join((
141                         "Voicemail:", str(self._conn.session.voicemailsStateMachine)
142                 )))
143                 self._report_new_message("\n".join((
144                         "Texts:", str(self._conn.session.textsStateMachine)
145                 )))
146
147         def help_get_state_status(self):
148                 self._report_new_message("Prints the current setting for the state machines")
149
150         def do_is_authed(self, args):
151                 le = gobject_utils.AsyncLinearExecution(self._conn.session.pool, self._is_authed)
152                 le.start(args)
153
154         @misc_utils.log_exception(_moduleLogger)
155         def _is_authed(self, args):
156                 if args:
157                         self._report_new_message("No arguments supported")
158                         return
159
160                 try:
161                         isAuthed = yield (
162                                 self._conn.session.backend.is_authed,
163                                 (),
164                                 {}
165                         )
166                         self._report_new_message(str(isAuthed))
167                 except Exception, e:
168                         self._report_new_message(str(e))
169                         return
170
171         def help_is_authed(self):
172                 self._report_new_message("Print whether logged in to Google Voice")
173
174         def do_is_dnd(self, args):
175                 le = gobject_utils.AsyncLinearExecution(self._conn.session.pool, self._is_dnd)
176                 le.start(args)
177
178         @misc_utils.log_exception(_moduleLogger)
179         def _is_dnd(self, args):
180                 if args:
181                         self._report_new_message("No arguments supported")
182                         return
183
184                 try:
185                         isDnd = yield (
186                                 self._conn.session.backend.is_dnd,
187                                 (),
188                                 {}
189                         )
190                         self._report_new_message(str(isDnd))
191                 except Exception, e:
192                         self._report_new_message(str(e))
193                         return
194
195         def help_is_dnd(self):
196                 self._report_new_message("Print whether Do-Not-Disturb mode enabled on the Google Voice account")
197
198         def do_get_account_number(self, args):
199                 if args:
200                         self._report_new_message("No arguments supported")
201                         return
202
203                 try:
204                         number = self._conn.session.backend.get_account_number()
205                         self._report_new_message(number)
206                 except Exception, e:
207                         self._report_new_message(str(e))
208
209         def help_get_account_number(self):
210                 self._report_new_message("Print the Google Voice account number")
211
212         def do_get_callback_numbers(self, args):
213                 if args:
214                         self._report_new_message("No arguments supported")
215                         return
216
217                 try:
218                         numbers = self._conn.session.backend.get_callback_numbers()
219                         numbersDisplay = "\n".join(
220                                 "%s: %s" % (name, number)
221                                 for (number, name) in numbers.iteritems()
222                         )
223                         self._report_new_message(numbersDisplay)
224                 except Exception, e:
225                         self._report_new_message(str(e))
226
227         def help_get_callback_numbers(self):
228                 self._report_new_message("Print a list of all configured callback numbers")
229
230         def do_get_sane_callback_number(self, args):
231                 if args:
232                         self._report_new_message("No arguments supported")
233                         return
234
235                 try:
236                         number = gvoice.backend.get_sane_callback(self._conn.session.backend)
237                         self._report_new_message(number)
238                 except Exception, e:
239                         self._report_new_message(str(e))
240
241         def help_get_sane_callback_number(self):
242                 self._report_new_message("Print the best guess of callback numbers to use")
243
244         def do_get_callback_number(self, args):
245                 if args:
246                         self._report_new_message("No arguments supported")
247                         return
248
249                 try:
250                         number = self._conn.session.backend.get_callback_number()
251                         self._report_new_message(number)
252                 except Exception, e:
253                         self._report_new_message(str(e))
254
255         def help_get_callback_number(self):
256                 self._report_new_message("Print the callback number currently enabled")
257
258         def do_call(self, args):
259                 le = gobject_utils.AsyncLinearExecution(self._conn.session.pool, self._call)
260                 le.start(args)
261
262         @misc_utils.log_exception(_moduleLogger)
263         def _call(self, args):
264                 if not args:
265                         self._report_new_message("Must specify the phone number and only the phone nunber")
266                         return
267
268                 try:
269                         number = args
270                         yield (
271                                 self._conn.session.backend.call,
272                                 (number),
273                                 {}
274                         )
275                 except Exception, e:
276                         self._report_new_message(str(e))
277
278         def help_call(self):
279                 self._report_new_message("\n".join(["call NUMBER", "Initiate a callback, Google forwarding the call to the callback number"]))
280
281         def do_send_sms(self, args):
282                 le = gobject_utils.AsyncLinearExecution(self._conn.session.pool, self._send_sms)
283                 le.start(args)
284
285         @misc_utils.log_exception(_moduleLogger)
286         def _send_sms(self, args):
287                 args = args.split(" ")
288                 if 1 < len(args):
289                         self._report_new_message("Must specify the phone number and then message")
290                         return
291
292                 try:
293                         number = args[0]
294                         message = " ".join(args[1:])
295                         yield (
296                                 self._conn.session.backend.send_sms,
297                                 ([number], message),
298                                 {},
299                         )
300                 except Exception, e:
301                         self._report_new_message(str(e))
302
303         def help_send_sms(self):
304                 self._report_new_message("\n".join(["send_sms NUMBER MESSAGE0 MESSAGE1 ...", "Send an sms to number NUMBER"]))
305
306         def do_version(self, args):
307                 if args:
308                         self._report_new_message("No arguments supported")
309                         return
310                 self._report_new_message("%s-%s" % (constants.__version__, constants.__build__))
311
312         def help_version(self):
313                 self._report_new_message("Prints the version (hint: %s-%s)" % (constants.__version__, constants.__build__))
314
315         def do_grab_log(self, args):
316                 if args:
317                         self._report_new_message("No arguments supported")
318                         return
319
320                 try:
321                         publishProps = self._conn.generate_props(telepathy.CHANNEL_TYPE_FILE_TRANSFER, self.__otherHandle, False)
322                         self._conn._channel_manager.channel_for_props(publishProps, signal=True)
323                 except Exception, e:
324                         self._report_new_message(str(e))
325
326         def help_grab_log(self):
327                 self._report_new_message("Download the debug log for including with bug report")
328                 self._report_new_message("Warning: this may contain sensitive information")
329
330         def do_save_log(self, args):
331                 if not args:
332                         self._report_new_message("Must specify a filename to save the log to")
333                         return
334
335                 try:
336                         filename = os.path.expanduser(args)
337                         with open(constants._user_logpath_, "r") as f:
338                                 logLines = f.xreadlines()
339                                 log = "".join(logLines)
340                         with open(filename, "w") as f:
341                                 f.write(log)
342                 except Exception, e:
343                         self._report_new_message(str(e))
344
345         def help_save_log(self):
346                 self._report_new_message("Save the log to a specified location")