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