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, eTPM
12 from Tools import Notifications
15 from twisted.mail import smtp, relaymanager
16 import MimeWriter, mimetools, StringIO
17 from __init__ import bin2long, long2bin, rsa_pub1024, decrypt_block, validate_cert, read_random
19 config.plugins.crashlogautosubmit = ConfigSubsection()
20 config.plugins.crashlogautosubmit.sendmail = ConfigSelection(default = "send", choices = [
21 ("send", _("Always ask before sending")), ("send_always", _("Don't ask, just send")), ("send_never", _("Disable crashlog reporting"))])
22 config.plugins.crashlogautosubmit.sendlog = ConfigSelection(default = "rename", choices = [
23 ("delete", _("Delete crashlogs")), ("rename", _("Rename crashlogs"))])
24 config.plugins.crashlogautosubmit.attachemail = ConfigYesNo(default = False)
25 config.plugins.crashlogautosubmit.email = ConfigText(default = "myemail@home.com", fixed_size = False)
26 config.plugins.crashlogautosubmit.name = ConfigText(default = "Dreambox User", fixed_size = False)
27 config.plugins.crashlogautosubmit.sendAnonCrashlog = ConfigYesNo(default = True)
28 config.plugins.crashlogautosubmit.addNetwork = ConfigYesNo(default = False)
29 config.plugins.crashlogautosubmit.addWlan = ConfigYesNo(default = False)
31 class CrashlogAutoSubmitConfiguration(Screen, ConfigListScreen):
33 oldMailEntryValue = config.plugins.crashlogautosubmit.sendmail.value
36 <screen name="CrashlogAutoSubmitConfiguration" position="center,center" size="560,440" title="CrashlogAutoSubmit settings" >
37 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
38 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
39 <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" />
40 <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" />
41 <widget name="config" zPosition="2" position="5,50" size="550,300" scrollbarMode="showOnDemand" transparent="1" />
42 <ePixmap pixmap="skin_default/div-h.png" position="0,390" zPosition="10" size="560,2" transparent="1" alphatest="on" />
43 <widget source="status" render="Label" position="10,400" size="540,40" zPosition="10" font="Regular;20" halign="center" valign="center" backgroundColor="#25062748" transparent="1"/>
44 <widget name="VKeyIcon" pixmap="skin_default/buttons/key_text.png" position="10,420" zPosition="10" size="35,25" transparent="1" alphatest="on" />
45 <widget name="HelpWindow" pixmap="skin_default/vkey_icon.png" position="160,325" zPosition="1" size="1,1" transparent="1" alphatest="on" />
48 def __init__(self, session):
49 Screen.__init__(self, session)
50 self.session = session
53 self.addEmailEntry = None
54 self.EmailEntry = None
56 self.AnonCrashlogEntry = None
57 self.NetworkEntry = None
59 self.msgCrashlogMailer = False
61 self["shortcuts"] = ActionMap(["ShortcutActions", "SetupActions" ],
64 "cancel": self.keyCancel,
65 "red": self.keyCancel,
66 "green": self.keySave,
69 self["VirtualKB"] = ActionMap(["VirtualKeyboardActions" ],
71 "showVirtualKeyboard": self.KeyText,
75 ConfigListScreen.__init__(self, self.list,session = self.session)
78 self["key_red"] = StaticText(_("Close"))
79 self["key_green"] = StaticText(_("Save"))
80 self["status"] = StaticText()
81 self["VKeyIcon"] = Pixmap()
82 self["HelpWindow"] = Pixmap()
84 self["VKeyIcon"].hide()
85 self["VirtualKB"].setEnabled(False)
86 self.onShown.append(self.setWindowTitle)
87 self.onClose.append(self.msgCrashlogNotifier)
90 def setWindowTitle(self):
91 self.setTitle(_("CrashlogAutoSubmit settings..."))
94 ConfigListScreen.keyLeft(self)
98 ConfigListScreen.keyRight(self)
102 if self["config"].getCurrent() == self.EmailEntry:
103 self.session.openWithCallback(self.EmailCallback, VirtualKeyBoard, title = (_("Please enter your email address here:")), text = config.plugins.crashlogautosubmit.email.value)
104 if self["config"].getCurrent() == self.NameEntry:
105 self.session.openWithCallback(self.NameCallback, VirtualKeyBoard, title = (_("Please enter your name here (optional):")), text = config.plugins.crashlogautosubmit.name.value)
107 def EmailCallback(self, callback = None):
108 if callback is not None and len(callback):
109 config.plugins.crashlogautosubmit.email.setValue(callback)
110 self["config"].invalidate(self.EmailEntry)
112 def NameCallback(self, callback = None):
113 if callback is not None and len(callback):
114 config.plugins.crashlogautosubmit.name.setValue(callback)
115 self["config"].invalidate(self.NameEntry)
117 def createSetup(self):
119 self.MailEntry = getConfigListEntry(_("How to handle found crashlogs?"), config.plugins.crashlogautosubmit.sendmail)
120 self.LogEntry = getConfigListEntry(_("What to do with submitted crashlogs?"), config.plugins.crashlogautosubmit.sendlog)
121 self.addEmailEntry = getConfigListEntry(_("Include your email and name (optional) in the mail?"), config.plugins.crashlogautosubmit.attachemail)
122 self.EmailEntry = getConfigListEntry(_("Your email address:"), config.plugins.crashlogautosubmit.email)
123 self.NameEntry = getConfigListEntry(_("Your name (optional):"), config.plugins.crashlogautosubmit.name)
124 self.AnonCrashlogEntry = getConfigListEntry(_("Anonymize crashlog?"), config.plugins.crashlogautosubmit.sendAnonCrashlog)
125 self.NetworkEntry = getConfigListEntry(_("Add network configuration?"), config.plugins.crashlogautosubmit.addNetwork)
126 self.WlanEntry = getConfigListEntry(_("Add WLAN configuration?"), config.plugins.crashlogautosubmit.addWlan)
128 self.list.append( self.MailEntry )
129 if config.plugins.crashlogautosubmit.sendmail.value is not "send_never":
130 self.list.append( self.LogEntry )
131 self.list.append( self.addEmailEntry )
132 if config.plugins.crashlogautosubmit.attachemail.value is True:
133 self.list.append( self.EmailEntry )
134 self.list.append( self.NameEntry )
135 self.list.append( self.AnonCrashlogEntry )
136 self.list.append( self.NetworkEntry )
137 self.list.append( self.WlanEntry )
139 self["config"].list = self.list
140 self["config"].l.setList(self.list)
141 if not self.selectionChanged in self["config"].onSelectionChanged:
142 self["config"].onSelectionChanged.append(self.selectionChanged)
144 if not self.sendmailChanged in config.plugins.crashlogautosubmit.sendmail.notifiers:
145 config.plugins.crashlogautosubmit.sendmail.notifiers.append(self.sendmailChanged)
147 def sendmailChanged(self, configElement):
148 if configElement.value != CrashlogAutoSubmitConfiguration.oldMailEntryValue:
149 self.msgCrashlogMailer = True
151 self.msgCrashlogMailer = False
154 if self["config"].getCurrent() == self.MailEntry:
156 if self["config"].getCurrent() == self.addEmailEntry:
159 def selectionChanged(self):
160 current = self["config"].getCurrent()
161 if current == self.MailEntry:
162 self["status"].setText(_("Decide what should be done when crashlogs are found."))
163 self.disableVKeyIcon()
164 elif current == self.LogEntry:
165 self["status"].setText(_("Decide what should happen to the crashlogs after submission."))
166 self.disableVKeyIcon()
167 elif current == self.addEmailEntry:
168 self["status"].setText(_("Do you want to submit your email address and name so that we can contact you if needed?"))
169 self.disableVKeyIcon()
170 elif current == self.EmailEntry:
171 self["status"].setText(_("Enter your email address so that we can contact you if needed."))
172 self.enableVKeyIcon()
174 elif current == self.NameEntry:
175 self["status"].setText(_("Optionally enter your name if you want to."))
176 self.enableVKeyIcon()
178 elif current == self.AnonCrashlogEntry:
179 self["status"].setText(_("Adds enigma2 settings and dreambox model informations like SN, rev... if enabled."))
180 self.disableVKeyIcon()
181 elif current == self.NetworkEntry:
182 self["status"].setText(_("Adds network configuration if enabled."))
183 self.disableVKeyIcon()
184 elif current == self.WlanEntry:
185 self["status"].setText(_("Adds wlan configuration if enabled."))
186 self.disableVKeyIcon()
188 def enableVKeyIcon(self):
189 self["VKeyIcon"].show()
190 self["VirtualKB"].setEnabled(True)
192 def showKeypad(self):
193 current = self["config"].getCurrent()
194 helpwindowpos = self["HelpWindow"].getPosition()
195 if hasattr(current[1], 'help_window'):
196 if current[1].help_window.instance is not None:
197 current[1].help_window.instance.show()
198 current[1].help_window.instance.move(ePoint(helpwindowpos[0],helpwindowpos[1]))
200 def disableVKeyIcon(self):
201 self["VKeyIcon"].hide()
202 self["VirtualKB"].setEnabled(False)
204 def hideKeypad(self):
205 current = self["config"].getCurrent()
206 if hasattr(current[1], 'help_window'):
207 if current[1].help_window.instance is not None:
208 current[1].help_window.instance.hide()
210 def cancelConfirm(self, result):
214 for x in self["config"].list:
220 if self["config"].isChanged():
222 self.session.openWithCallback(self.cancelConfirm, MessageBox, _("Really close without saving settings?"))
228 CrashlogAutoSubmitConfiguration.oldMailEntryValue = config.plugins.crashlogautosubmit.sendmail.value
229 ConfigListScreen.keySave(self)
231 def msgCrashlogNotifier(self):
232 if self.msgCrashlogMailer is True:
234 callCrashMailer(True, self.session)
235 except AttributeError:
236 print "error, not restarting crashlogmailer"
239 def mxServerFound(mxServer,session):
240 print "[CrashlogAutoSubmit] - mxServerFound -->", mxServer
241 crashLogFilelist = []
242 message = StringIO.StringIO()
243 writer = MimeWriter.MimeWriter(message)
244 mailFrom = "enigma2@crashlog.dream-multimedia-tv.de"
245 mailTo = "enigma2@crashlog.dream-multimedia-tv.de"
246 subject = "Automatically generated crashlogmail"
247 # Define the main body headers.
248 writer.addheader('To', "dream-multimedia-crashlogs <enigma2@crashlog.dream-multimedia-tv.de>")
249 writer.addheader('From', "CrashlogAutoSubmitter <enigma2@crashlog.dream-multimedia-tv.de>")
250 writer.addheader('Subject', str(subject))
251 writer.addheader('Date', smtp.rfc822date())
252 if config.plugins.crashlogautosubmit.attachemail.value is True:
253 if str(config.plugins.crashlogautosubmit.email.value) != "myemail@home.com":
254 writer.addheader('Reply-To', str(str(config.plugins.crashlogautosubmit.email.value)))
255 writer.addheader('MIME-Version', '1.0')
256 writer.startmultipartbody('mixed')
257 # start with a text/plain part
258 part = writer.nextpart()
259 body = part.startbody('text/plain')
261 # Define the message body
262 body_text1 = "\nHello\n\nHere are some crashlogs i found for you.\n"
263 if str(config.plugins.crashlogautosubmit.email.value) == "myemail@home.com":
266 user_email = "\nUser supplied email address: " + str(config.plugins.crashlogautosubmit.email.value)
267 if str(config.plugins.crashlogautosubmit.name.value) == "Dreambox User":
270 user_name = "\n\nOptional supplied name: " + str(config.plugins.crashlogautosubmit.name.value)
271 body_text2 = "\n\nThis is an automatically generated email from the CrashlogAutoSubmit plugin.\n\n\nHave a nice day.\n"
272 body_text = body_text1 + user_email + user_name + body_text2
273 body.write(body_text)
277 (_("Yes, and don't ask again"), "send_always"),
278 (_("No, not now"), "send_not"),
279 (_("No, send them never"), "send_never")
282 def handleError(error):
283 print "[CrashlogAutoSubmit] - Message send Error -->", error.getErrorMessage()
285 def handleSuccess(result):
286 print "[CrashlogAutoSubmit] - Message sent successfully -->",result
287 if len(crashLogFilelist):
288 for crashlog in crashLogFilelist:
289 if config.plugins.crashlogautosubmit.sendlog.value == "delete":
291 elif config.plugins.crashlogautosubmit.sendlog.value == "rename":
292 currfilename = str(os.path.basename(crashlog))
293 newfilename = "/media/hdd/" + currfilename + ".sent"
294 os.rename(crashlog,newfilename)
297 print "[CrashlogAutoSubmit] - send_mail"
298 if len(crashLogFilelist):
299 for crashlog in crashLogFilelist:
300 filename = str(os.path.basename(crashlog))
301 subpart = writer.nextpart()
302 subpart.addheader("Content-Transfer-Encoding", 'base64')
303 subpart.addheader("Content-Disposition",'attachment; filename="%s"' % filename)
304 subpart.addheader('Content-Description', 'Enigma2 crashlog')
305 body = subpart.startbody("%s; name=%s" % ('application/octet-stream', filename))
306 mimetools.encode(open(crashlog, 'rb'), body, 'base64')
308 sending = smtp.sendmail(str(mxServer), mailFrom, mailTo, message.getvalue())
309 sending.addCallback(handleSuccess).addErrback(handleError)
311 def handleAnswer(answer):
312 answer = answer and answer[1]
313 print "[CrashlogAutoSubmit] - handleAnswer --> ",answer
316 elif answer == "send_always":
317 config.plugins.crashlogautosubmit.sendmail.value = "send_always"
318 config.plugins.crashlogautosubmit.sendmail.save()
319 config.plugins.crashlogautosubmit.save()
320 config.plugins.save()
323 elif answer in ( None, "send_never"):
324 config.plugins.crashlogautosubmit.sendmail.value = "send_never"
325 config.plugins.crashlogautosubmit.sendmail.save()
326 config.plugins.crashlogautosubmit.save()
327 config.plugins.save()
329 elif answer == "send_not":
330 print "[CrashlogAutoSubmit] - not sending crashlogs for this time."
332 for crashlog in os.listdir('/media/hdd'):
333 if crashlog.startswith("enigma2_crash_") and crashlog.endswith(".log"):
334 print "[CrashlogAutoSubmit] - found crashlog: ",os.path.basename(crashlog)
335 crashLogFilelist.append('/media/hdd/' + crashlog)
337 if len(crashLogFilelist):
338 if config.plugins.crashlogautosubmit.sendmail.value == "send":
339 Notifications.AddNotificationWithCallback(handleAnswer, ChoiceBox, title=_("Crashlogs found!\nSend them to Dream Multimedia?"), list = list)
340 elif config.plugins.crashlogautosubmit.sendmail.value == "send_always":
343 print "[CrashlogAutoSubmit] - no crashlogs found."
346 def getMailExchange(host):
347 print "[CrashlogAutoSubmit] - getMailExchange"
348 return relaymanager.MXCalculator().getMX(host).addCallback(_gotMXRecord)
350 def _gotMXRecord(mxRecord):
351 return str(mxRecord.name)
354 def startMailer(session):
355 if config.plugins.crashlogautosubmit.sendmail.value == "send_never":
356 print "[CrashlogAutoSubmit] - not starting CrashlogAutoSubmit"
359 def gotMXServer(mxServer):
360 print "[CrashlogAutoSubmit] gotMXServer: ",mxServer
361 mxServerFound(mxServer,session)
363 def handleMXError(error):
364 print "[CrashlogAutoSubmit] - MX resolve ERROR:", error.getErrorMessage()
366 if not config.misc.firstrun.value:
367 getMailExchange('crashlog.dream-multimedia-tv.de').addCallback(gotMXServer).addErrback(handleMXError)
370 def callCrashMailer(result,session):
372 print "[CrashlogAutoSubmit] - config changed"
375 print "[CrashlogAutoSubmit] - config not changed"
378 def autostart(reason, **kwargs):
379 print "[CrashlogAutoSubmit] - autostart"
381 device = open("/proc/stb/info/model", "r").readline().strip()
384 if device != "dm7025":
385 rootkey = ['\x9f', '|', '\xe4', 'G', '\xc9', '\xb4', '\xf4', '#', '&', '\xce', '\xb3', '\xfe', '\xda', '\xc9', 'U', '`', '\xd8', '\x8c', 's', 'o', '\x90', '\x9b', '\\', 'b', '\xc0', '\x89', '\xd1', '\x8c', '\x9e', 'J', 'T', '\xc5', 'X', '\xa1', '\xb8', '\x13', '5', 'E', '\x02', '\xc9', '\xb2', '\xe6', 't', '\x89', '\xde', '\xcd', '\x9d', '\x11', '\xdd', '\xc7', '\xf4', '\xe4', '\xe4', '\xbc', '\xdb', '\x9c', '\xea', '}', '\xad', '\xda', 't', 'r', '\x9b', '\xdc', '\xbc', '\x18', '3', '\xe7', '\xaf', '|', '\xae', '\x0c', '\xe3', '\xb5', '\x84', '\x8d', '\r', '\x8d', '\x9d', '2', '\xd0', '\xce', '\xd5', 'q', '\t', '\x84', 'c', '\xa8', ')', '\x99', '\xdc', '<', '"', 'x', '\xe8', '\x87', '\x8f', '\x02', ';', 'S', 'm', '\xd5', '\xf0', '\xa3', '_', '\xb7', 'T', '\t', '\xde', '\xa7', '\xf1', '\xc9', '\xae', '\x8a', '\xd7', '\xd2', '\xcf', '\xb2', '.', '\x13', '\xfb', '\xac', 'j', '\xdf', '\xb1', '\x1d', ':', '?']
387 l2cert = etpm.getCert(eTPM.TPMD_DT_LEVEL2_CERT)
390 l2key = validate_cert(l2cert, rootkey)
393 l3cert = etpm.getCert(eTPM.TPMD_DT_LEVEL3_CERT)
396 l3key = validate_cert(l3cert, l2key)
402 val = etpm.challenge(rnd)
403 result = decrypt_block(val, l3key)
404 if device == "dm7025" or result[80:88] == rnd:
405 if "session" in kwargs:
407 startMailer(kwargs["session"])
408 except ImportError, e:
409 print "[CrashlogAutoSubmit] Twisted-mail not available, not starting CrashlogAutoSubmitter", e
412 def openconfig(session, **kwargs):
413 session.open(CrashlogAutoSubmitConfiguration)
416 def selSetup(menuid, **kwargs):
417 if menuid != "system":
420 return [(_("Crashlog settings"), openconfig, "crashlog_config", 70)]
423 def Plugins(**kwargs):
424 return [PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], needsRestart = False, fnc = autostart),
425 PluginDescriptor(name=_("CrashlogAutoSubmit"), description=_("CrashlogAutoSubmit settings"),where=PluginDescriptor.WHERE_MENU, needsRestart = False, fnc=selSetup)]