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