don't crash when video modes are broken
[enigma2.git] / lib / python / Plugins / SystemPlugins / CrashlogAutoSubmit / plugin.py
1 from Plugins.Plugin import PluginDescriptor
2 from Components.config import config, getConfigListEntry, ConfigSubsection, ConfigText, ConfigSelection, ConfigYesNo,ConfigText
3 from Components.ConfigList import ConfigListScreen
4 from Components.ActionMap import ActionMap
5 from Components.Label import Label
6 from Components.Pixmap import Pixmap
7 from Screens.Screen import Screen
8 from Screens.VirtualKeyBoard import VirtualKeyBoard
9 from Screens.ChoiceBox import ChoiceBox
10 from Screens.MessageBox import MessageBox
11 from enigma import ePoint
12 from Tools import Notifications
13
14 import os
15 from twisted.mail import smtp, relaymanager
16 import MimeWriter, mimetools, StringIO
17
18 config.plugins.crashlogautosubmit = ConfigSubsection()
19 config.plugins.crashlogautosubmit.sendmail = ConfigSelection(default = "send", choices = [
20         ("send", _("Always ask before sending")), ("send_always", _("Don't ask, just send")), ("send_never", _("Disable crashlog reporting"))])
21 config.plugins.crashlogautosubmit.sendlog = ConfigSelection(default = "rename", choices = [
22         ("delete", _("Delete crashlogs")), ("rename", _("Rename crashlogs"))])
23 config.plugins.crashlogautosubmit.attachemail = ConfigYesNo(default = False)
24 config.plugins.crashlogautosubmit.email = ConfigText(default = "myemail@home.com", fixed_size = False)
25 config.plugins.crashlogautosubmit.name = ConfigText(default = "Dreambox User", fixed_size = False)
26 config.plugins.crashlogautosubmit.sendAnonCrashlog = ConfigYesNo(default = False)
27 config.plugins.crashlogautosubmit.addNetwork = ConfigYesNo(default = False)
28 config.plugins.crashlogautosubmit.addWlan = ConfigYesNo(default = False)
29
30 class CrashlogAutoSubmitConfiguration(Screen, ConfigListScreen):
31
32         oldMailEntryValue = config.plugins.crashlogautosubmit.sendmail.value
33
34         skin = """
35                 <screen name="CrashlogAutoSubmitConfiguration" position="80,80" size="560,400" title="CrashlogAutoSubmit settings..." >
36                         <widget name="config" zPosition="2" position="5,5" size="550,360" scrollbarMode="showOnDemand" transparent="1" />
37                         <ePixmap pixmap="skin_default/div-h.png" position="0,300" zPosition="10" size="560,2" transparent="1" alphatest="on" />
38                         <widget name="status" position="10,300" zPosition="10" size="540,50" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
39                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,360" zPosition="2" size="140,40" transparent="1" alphatest="on" />
40                         <widget name="closetext" position="0,360" zPosition="10" size="140,40" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
41                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,360" zPosition="2" size="140,40" transparent="1" alphatest="on" />
42                         <widget name="installtext" position="140,360" zPosition="10" size="140,40" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
43                         <widget name="VKeyButton" pixmap="skin_default/buttons/button_yellow.png" position="285,370" zPosition="2" size="15,16" transparent="1" alphatest="on" />
44                         <widget name="VKeyIcon" pixmap="skin_default/vkey_icon.png" position="300,355" zPosition="10" size="60,48" transparent="1" alphatest="on" />
45                         <widget name="HelpWindow" position="175,250" zPosition="1" size="1,1" transparent="1" />
46                 </screen>"""
47
48         def __init__(self, session):
49                 Screen.__init__(self, session)
50                 self.session = session
51                 self.MailEntry = None
52                 self.LogEntry = None
53                 self.addEmailEntry = None
54                 self.EmailEntry = None
55                 self.NameEntry = None
56                 self.AnonCrashlogEntry = None
57                 self.NetworkEntry = None
58                 self.WlanEntry = None
59                 self.msgCrashlogMailer = False
60
61                 self["shortcuts"] = ActionMap(["ShortcutActions", "SetupActions" ],
62                 {
63                         "ok": self.keySave,
64                         "cancel": self.keyCancel,
65                         "red": self.keyCancel,
66                         "green": self.keySave,
67                 }, -2)
68
69                 self["VirtualKB"] = ActionMap(["ColorActions" ],
70                 {
71                         "yellow": self.KeyYellow,
72                 }, -1)
73
74                 self.list = []
75                 ConfigListScreen.__init__(self, self.list,session = self.session)
76                 self.createSetup()
77
78                 self["VKeyButton"] = Pixmap()
79                 self["VKeyIcon"] = Pixmap()
80                 self["closetext"] = Label(_("Close"))
81                 self["installtext"] = Label(_("Save"))
82                 self["HelpWindow"] = Label()
83                 self["status"] = Label()
84
85                 self["VKeyButton"].hide()
86                 self["VKeyIcon"].hide()
87                 self["VirtualKB"].setEnabled(False)
88                 self.onShown.append(self.setWindowTitle)
89                 self.onClose.append(self.msgCrashlogNotifier)
90
91
92         def setWindowTitle(self):
93                 self.setTitle(_("CrashlogAutoSubmit settings..."))
94
95         def keyLeft(self):
96                 ConfigListScreen.keyLeft(self)
97                 self.newConfig()
98
99         def keyRight(self):
100                 ConfigListScreen.keyRight(self)
101                 self.newConfig()
102
103         def KeyYellow(self):
104                         if self["config"].getCurrent() == self.EmailEntry:
105                                 self.session.openWithCallback(self.EmailCallback, VirtualKeyBoard, title = (_("Please enter your email address here:")), text = config.plugins.crashlogautosubmit.email.value)
106                         if self["config"].getCurrent() == self.NameEntry:
107                                 self.session.openWithCallback(self.NameCallback, VirtualKeyBoard, title = (_("Please enter your name here (optional):")), text = config.plugins.crashlogautosubmit.name.value)
108
109         def EmailCallback(self, callback = None):
110                 if callback is not None and len(callback):
111                         config.plugins.crashlogautosubmit.email.setValue(callback)
112                         self["config"].invalidate(self.EmailEntry)
113
114         def NameCallback(self, callback = None):
115                 if callback is not None and len(callback):
116                         config.plugins.crashlogautosubmit.name.setValue(callback)
117                         self["config"].invalidate(self.NameEntry)
118
119         def createSetup(self):
120                 self.list = []
121                 self.MailEntry = getConfigListEntry(_("How to handle found crashlogs?"), config.plugins.crashlogautosubmit.sendmail)
122                 self.LogEntry = getConfigListEntry(_("What to do with submitted crashlogs?"), config.plugins.crashlogautosubmit.sendlog)
123                 self.addEmailEntry = getConfigListEntry(_("Include your email and name (optional) in the mail?"), config.plugins.crashlogautosubmit.attachemail)
124                 self.EmailEntry = getConfigListEntry(_("Your email address:"), config.plugins.crashlogautosubmit.email)
125                 self.NameEntry = getConfigListEntry(_("Your name (optional):"), config.plugins.crashlogautosubmit.name)
126                 self.AnonCrashlogEntry = getConfigListEntry(_("Anonymize crashlog?"), config.plugins.crashlogautosubmit.sendAnonCrashlog)
127                 self.NetworkEntry = getConfigListEntry(_("Add network configuration?"), config.plugins.crashlogautosubmit.addNetwork)
128                 self.WlanEntry = getConfigListEntry(_("Add WLAN configuration?"), config.plugins.crashlogautosubmit.addWlan)
129
130                 self.list.append( self.MailEntry )
131                 if config.plugins.crashlogautosubmit.sendmail.value is not "send_never":
132                         self.list.append( self.LogEntry )
133                         self.list.append( self.addEmailEntry )
134                         if config.plugins.crashlogautosubmit.attachemail.value is True:
135                                 self.list.append( self.EmailEntry )
136                                 self.list.append( self.NameEntry )
137                         self.list.append( self.AnonCrashlogEntry )
138                         self.list.append( self.NetworkEntry )
139                         self.list.append( self.WlanEntry )
140
141                 self["config"].list = self.list
142                 self["config"].l.setList(self.list)
143                 if not self.selectionChanged in self["config"].onSelectionChanged:
144                         self["config"].onSelectionChanged.append(self.selectionChanged)
145
146                 if not self.sendmailChanged in config.plugins.crashlogautosubmit.sendmail.notifiers:
147                         config.plugins.crashlogautosubmit.sendmail.notifiers.append(self.sendmailChanged)
148
149         def sendmailChanged(self, configElement):
150                 if configElement.value != CrashlogAutoSubmitConfiguration.oldMailEntryValue:
151                         self.msgCrashlogMailer = True
152                 else:
153                         self.msgCrashlogMailer = False
154
155         def newConfig(self):
156                 if self["config"].getCurrent() == self.MailEntry:
157                         self.createSetup()
158                 if self["config"].getCurrent() == self.addEmailEntry:
159                         self.createSetup()
160
161         def selectionChanged(self):
162                 current = self["config"].getCurrent()
163                 if current == self.MailEntry:
164                         self["status"].setText(_("Decide what should be done when crashlogs are found."))
165                         self.disableVKeyIcon()
166                 elif current == self.LogEntry:
167                         self["status"].setText(_("Decide what should happen to the crashlogs after submission."))
168                         self.disableVKeyIcon()
169                 elif current == self.addEmailEntry:
170                         self["status"].setText(_("Do you want to submit your email address and name so that we can contact you if needed?"))
171                         self.disableVKeyIcon()
172                 elif current == self.EmailEntry:
173                         self["status"].setText(_("Enter your email address so that we can contact you if needed."))
174                         self.enableVKeyIcon()
175                         self.showKeypad()
176                 elif current == self.NameEntry:
177                         self["status"].setText(_("Optionally enter your name if you want to."))
178                         self.enableVKeyIcon()
179                         self.showKeypad()
180                 elif current == self.AnonCrashlogEntry:
181                         self["status"].setText(_("Adds enigma2 settings and dreambox model informations like SN, rev... if enabled."))
182                         self.disableVKeyIcon()
183                 elif current == self.NetworkEntry:
184                         self["status"].setText(_("Adds network configuration if enabled."))
185                         self.disableVKeyIcon()
186                 elif current == self.WlanEntry:
187                         self["status"].setText(_("Adds wlan configuration if enabled."))
188                         self.disableVKeyIcon()
189
190         def enableVKeyIcon(self):
191                 self["VKeyButton"].show()
192                 self["VKeyIcon"].show()
193                 self["VirtualKB"].setEnabled(True)
194
195         def showKeypad(self):
196                 current = self["config"].getCurrent()
197                 helpwindowpos = self["HelpWindow"].getPosition()
198                 if hasattr(current[1], 'help_window'):
199                         if current[1].help_window.instance is not None:
200                                 current[1].help_window.instance.show()
201                                 current[1].help_window.instance.move(ePoint(helpwindowpos[0],helpwindowpos[1]))
202
203         def disableVKeyIcon(self):
204                 self["VKeyButton"].hide()
205                 self["VKeyIcon"].hide()
206                 self["VirtualKB"].setEnabled(False)
207
208         def hideKeypad(self):
209                 current = self["config"].getCurrent()
210                 if hasattr(current[1], 'help_window'):
211                         if current[1].help_window.instance is not None:
212                                 current[1].help_window.instance.hide()
213
214         def cancelConfirm(self, result):
215                 if not result:
216                         self.showKeypad()
217                         return
218                 for x in self["config"].list:
219                         x[1].cancel()
220                 self.close()
221
222         def keyCancel(self):
223                 print "cancel"
224                 if self["config"].isChanged():
225                         self.hideKeypad()
226                         self.session.openWithCallback(self.cancelConfirm, MessageBox, _("Really close without saving settings?"))
227                 else:
228                         self.close()
229
230         def keySave(self):
231                 print "saving"
232                 CrashlogAutoSubmitConfiguration.oldMailEntryValue = config.plugins.crashlogautosubmit.sendmail.value
233                 ConfigListScreen.keySave(self)
234
235         def msgCrashlogNotifier(self):
236                 if self.msgCrashlogMailer is True:
237                         try:
238                                 callCrashMailer(True, self.session)
239                         except AttributeError:
240                                 print "error, not restarting crashlogmailer"
241
242
243 def mxServerFound(mxServer,session):
244         print "[CrashlogAutoSubmit] - mxServerFound -->", mxServer
245         crashLogFilelist = []
246         message = StringIO.StringIO()
247         writer = MimeWriter.MimeWriter(message)
248         mailFrom = "enigma2@crashlog.dream-multimedia-tv.de"
249         mailTo = "enigma2@crashlog.dream-multimedia-tv.de"
250         subject = "Automatically generated crashlogmail"
251         # Define the main body headers.
252         writer.addheader('To', "dream-multimedia-crashlogs <enigma2@crashlog.dream-multimedia-tv.de>")
253         writer.addheader('From', "CrashlogAutoSubmitter <enigma2@crashlog.dream-multimedia-tv.de>")
254         writer.addheader('Subject', str(subject))
255         writer.addheader('Date', smtp.rfc822date())
256         if config.plugins.crashlogautosubmit.attachemail.value is True:
257                 if  str(config.plugins.crashlogautosubmit.email.value) != "myemail@home.com":
258                         writer.addheader('Reply-To', str(str(config.plugins.crashlogautosubmit.email.value)))
259         writer.addheader('MIME-Version', '1.0')
260         writer.startmultipartbody('mixed')
261         # start with a text/plain part
262         part = writer.nextpart()
263         body = part.startbody('text/plain')
264         part.flushheaders()
265         # Define the message body
266         body_text1 = "\nHello\n\nHere are some crashlogs i found for you.\n"
267         if  str(config.plugins.crashlogautosubmit.email.value) == "myemail@home.com":
268                 user_email = ""
269         else:
270                 user_email = "\nUser supplied email address: " + str(config.plugins.crashlogautosubmit.email.value)
271         if str(config.plugins.crashlogautosubmit.name.value) ==  "Dreambox User":
272                 user_name = ""
273         else:
274                 user_name = "\n\nOptional supplied name: " + str(config.plugins.crashlogautosubmit.name.value)
275         body_text2 = "\n\nThis is an automatically generated email from the CrashlogAutoSubmit plugin.\n\n\nHave a nice day.\n"
276         body_text = body_text1 + user_email + user_name + body_text2
277         body.write(body_text)
278
279         list = (
280                 (_("Yes"), "send"),
281                 (_("Yes, and don't ask again"), "send_always"),
282                 (_("No, not now"), "send_not"),
283                 (_("No, send them never"), "send_never")
284         )
285
286         def handleError(error):
287                 print "[CrashlogAutoSubmit] - Message send Error -->", error.getErrorMessage()
288
289         def handleSuccess(result):
290                 print "[CrashlogAutoSubmit] - Message sent successfully -->",result
291                 if len(crashLogFilelist):
292                         for crashlog in crashLogFilelist:
293                                 if config.plugins.crashlogautosubmit.sendlog.value == "delete":
294                                         os.remove(crashlog)
295                                 elif config.plugins.crashlogautosubmit.sendlog.value == "rename":
296                                         currfilename = str(os.path.basename(crashlog))
297                                         newfilename = "/media/hdd/" + currfilename + ".sent"
298                                         os.rename(crashlog,newfilename)
299
300         def send_mail():
301                 print "[CrashlogAutoSubmit] - send_mail"
302                 if len(crashLogFilelist):
303                         for crashlog in crashLogFilelist:
304                                 filename = str(os.path.basename(crashlog))
305                                 subpart = writer.nextpart()
306                                 subpart.addheader("Content-Transfer-Encoding", 'base64')
307                                 subpart.addheader("Content-Disposition",'attachment; filename="%s"' % filename)
308                                 subpart.addheader('Content-Description', 'Enigma2 crashlog')
309                                 body = subpart.startbody("%s; name=%s" % ('application/octet-stream', filename))
310                                 mimetools.encode(open(crashlog, 'rb'), body, 'base64')
311                 writer.lastpart()
312                 sending = smtp.sendmail(str(mxServer), mailFrom, mailTo, message.getvalue())
313                 sending.addCallback(handleSuccess).addErrback(handleError)
314
315         def handleAnswer(answer):
316                 answer = answer and answer[1]
317                 print "[CrashlogAutoSubmit] - handleAnswer --> ",answer
318                 if answer == "send":
319                         send_mail()
320                 elif answer == "send_always":
321                         config.plugins.crashlogautosubmit.sendmail.value = "send_always"
322                         config.plugins.crashlogautosubmit.sendmail.save()
323                         config.plugins.crashlogautosubmit.save()
324                         config.plugins.save()
325                         config.save()
326                         send_mail()
327                 elif answer in ( None, "send_never"):
328                         config.plugins.crashlogautosubmit.sendmail.value = "send_never"
329                         config.plugins.crashlogautosubmit.sendmail.save()
330                         config.plugins.crashlogautosubmit.save()
331                         config.plugins.save()
332                         config.save()
333                 elif answer == "send_not":
334                         print "[CrashlogAutoSubmit] - not sending crashlogs for this time."
335
336         for crashlog in os.listdir('/media/hdd'):
337                 if crashlog.startswith("enigma2_crash_") and crashlog.endswith(".log"):
338                         print "[CrashlogAutoSubmit] - found crashlog: ",os.path.basename(crashlog)
339                         crashLogFilelist.append('/media/hdd/' + crashlog)
340
341         if len(crashLogFilelist):
342                 if config.plugins.crashlogautosubmit.sendmail.value == "send":
343                         Notifications.AddNotificationWithCallback(handleAnswer, ChoiceBox, title=_("Crashlogs found!\nSend them to Dream Multimedia?"), list = list)
344                 elif config.plugins.crashlogautosubmit.sendmail.value == "send_always":
345                         send_mail()
346         else:
347                 print "[CrashlogAutoSubmit] - no crashlogs found."
348
349
350 def getMailExchange(host):
351         print "[CrashlogAutoSubmit] - getMailExchange"
352         return relaymanager.MXCalculator().getMX(host).addCallback(_gotMXRecord)
353
354 def _gotMXRecord(mxRecord):
355         return str(mxRecord.name)
356
357
358 def startMailer(session):
359         if config.plugins.crashlogautosubmit.sendmail.value == "send_never":
360                 print "[CrashlogAutoSubmit] - not starting CrashlogAutoSubmit"
361                 return False
362
363         def gotMXServer(mxServer):
364                 print "[CrashlogAutoSubmit] gotMXServer: ",mxServer
365                 mxServerFound(mxServer,session)
366
367         def handleMXError(error):
368                 print "[CrashlogAutoSubmit] - MX resolve ERROR:", error.getErrorMessage()
369
370         if not config.misc.firstrun.value:
371                 getMailExchange('crashlog.dream-multimedia-tv.de').addCallback(gotMXServer).addErrback(handleMXError)
372
373
374 def callCrashMailer(result,session):
375         if result is True:
376                 print "[CrashlogAutoSubmit] - config changed"
377                 startMailer(session)
378         else:
379                 print "[CrashlogAutoSubmit] - config not changed"
380
381
382 def autostart(reason, **kwargs):
383         print "[CrashlogAutoSubmit] - autostart"
384         if "session" in kwargs:
385                 try:
386                         startMailer(kwargs["session"])
387                 except ImportError, e:
388                         print "[CrashlogAutoSubmit] Twisted-mail not available, not starting CrashlogAutoSubmitter", e
389
390
391 def openconfig(session, **kwargs):
392         session.open(CrashlogAutoSubmitConfiguration)
393
394
395 def selSetup(menuid, **kwargs):
396         if menuid != "system":
397                 return [ ]
398
399         return [(_("Crashlog settings") + "...", openconfig, "crashlog_config", 70)]
400
401
402 def Plugins(**kwargs):
403         return [PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc = autostart),
404                 PluginDescriptor(name=_("CrashlogAutoSubmit"), description=_("CrashlogAutoSubmit settings"),where=PluginDescriptor.WHERE_MENU, fnc=selSetup)]
405