FIX: grey for seen messages
[enigma2-plugins.git] / emailclient / src / plugin.py
1 from Components.ActionMap import ActionMap
2 from Components.GUIComponent import GUIComponent
3 from Components.HTMLComponent import HTMLComponent
4 from Components.Label import Label
5 from Screens.MessageBox import MessageBox
6 from Components.MenuList import MenuList
7 from Components.MultiContent import MultiContentEntryText, MultiContentTemplateColor
8 from Components.ScrollLabel import ScrollLabel
9 from Components.Button import Button
10 from Components.config import config, ConfigSubsection, ConfigInteger, ConfigText, ConfigEnableDisable
11 from EmailConfig import EmailConfigScreen
12 from Plugins.Plugin import PluginDescriptor
13 from Screens.ChoiceBox import ChoiceBox
14 from Screens.Screen import Screen
15 from enigma import eListboxPythonMultiContent, eListbox, gFont
16 from twisted.mail import imap4
17 from zope.interface import implements
18 import email
19 import email.Parser
20 from email.header import decode_header
21 from TagStrip import strip_readable
22 from protocol import createFactory
23
24 config.plugins.emailimap = ConfigSubsection()
25 config.plugins.emailimap.username = ConfigText("user", fixed_size=False)
26 config.plugins.emailimap.password = ConfigText("password", fixed_size=False)
27 config.plugins.emailimap.server = ConfigText("please.config.first", fixed_size=False)
28 config.plugins.emailimap.port = ConfigInteger(143, limits = (1, 65536))
29 config.plugins.emailimap.showDeleted = ConfigEnableDisable(default=False)
30
31 # 0= fetch all header , 10= fetch only the last 10 headers/messages of a mailbox
32 config.plugins.emailimap.maxheadertoload = ConfigInteger(0, limits = (1, 100))
33
34 from enigma import getDesktop
35 DESKTOP_WIDTH = getDesktop(0).size().width()
36 DESKTOP_HEIGHT = getDesktop(0).size().height()
37 #
38 # this is pure magic.
39 # It returns the first value, if HD (1280x720),
40 # the second if SD (720x576),
41 # else something scaled accordingly
42 # if one of the parameters is -1, scale proportionally
43 #
44 def scaleH(y2, y1):
45         if y2 == -1:
46                 y2 = y1*1280/720
47         elif y1 == -1:
48                 y1 = y2*720/1280
49         return scale(y2, y1, 1280, 720, DESKTOP_WIDTH)
50 def scaleV(y2, y1):
51         if y2 == -1:
52                 y2 = y1*720/576
53         elif y1 == -1:
54                 y1 = y2*576/720
55         return scale(y2, y1, 720, 576, DESKTOP_HEIGHT)
56 def scale(y2, y1, x2, x1, x):
57         return (y2 - y1) * (x - x1) / (x2 - x1) + y1
58
59 def decodeHeader(text, default=''):
60         if text is None:
61                 return _(default)
62         text = text.replace('\r',' ').replace('\n',' ').replace('\t',' ')
63         while text.find('  ') != -1:
64                 text = text.replace('  ',' ')
65         textNew = ""
66         for part in decode_header(text):
67                 (content, charset) = part
68                 # print("decodeHeader content/charset: %s/%s" %(repr(content),charset))
69                 if charset:
70                         textNew += content.decode(charset)
71                 else:
72                         textNew += content
73         try:
74                 return textNew.encode('utf-8')
75         except: # for faulty mail software systems
76                 return textNew.decode('iso-8859-1').encode('utf-8')
77
78 IS_UNSEEN = 0
79 IS_SEEN = 1
80 IS_DELETED = 2 
81
82 class EmailHandler:
83         def __init__(self):
84                 pass
85         def onConnect(self, proto):
86                 pass
87
88 class EmailScreen(Screen, EmailHandler):
89         implements(imap4.IMailboxListener)
90
91         width = scaleH(-1,530)
92         height = scaleV(-1,430)
93         boxlistWidth = scaleH(-1,150)
94         messagelistWidth = width-boxlistWidth
95         infolabelHeight = scaleV(-1,30)
96         skin = """
97                 <screen position="%d,%d" size="%d,%d" title="Email" >
98                         <widget name="boxlist" position="0,0" size="%d,%d" scrollbarMode="showOnDemand" />
99                         <widget name="messagelist" position="%d,%d" size="%d,%d" scrollbarMode="showOnDemand" />
100                         <widget name="infolabel" position="%d,%d" size="%d,%d"   foregroundColor=\"white\" font=\"Regular;%d\" />
101                 </screen>""" %(
102                                            (DESKTOP_WIDTH-width)/2, (DESKTOP_HEIGHT-height)/2, width, height,
103                                            boxlistWidth, height-infolabelHeight,
104                                            boxlistWidth, 0, messagelistWidth, height-infolabelHeight,
105                                            0, height-infolabelHeight, width, infolabelHeight, scaleV(20,18)
106                                            )
107
108         currentmailbox = None
109         proto = None
110
111         def __init__(self, session, args = 0):
112                 EmailHandler.__init__(self)
113                 self.session = session
114
115                 self.skin = EmailScreen.skin
116                 Screen.__init__(self, session)
117                 createFactory(self, config.plugins.emailimap.username.value, config.plugins.emailimap.server.value, config.plugins.emailimap.port.value)
118
119                 self["actions"] = ActionMap(["InfobarChannelSelection", "WizardActions", "DirectionActions", "MenuActions", "ShortcutActions", "GlobalActions", "HelpActions", "NumberActions", "ChannelSelectBaseActions"],
120                         {
121                          "ok": self.action_ok,
122                          "back": self.action_exit,
123                          "historyNext": self.selectMessagelist,
124                          "historyBack": self.selectBoxlist,
125                          "nextBouquet": self.selectMessagelist,
126                          "prevBouquet": self.selectBoxlist,
127                          "down":                self.down,
128                          "up":            self.up,
129                          "left":                self.left,
130                          "right":          self.right,
131                          "menu":                self.action_menu,
132                          }, -1)
133                 self["boxlist"] = MenuList([])
134                 self["messagelist"] = MailList([])
135                 self["infolabel"] = Label("")
136                 self.onLayoutFinish.append(self.selectBoxlist)
137
138         def action_menu(self):
139                 self.session.open(EmailConfigScreen).onHide.append(self.onBoxSelected)
140
141         def selectBoxlist(self):
142                 self.currList = "boxlist"
143                 self["boxlist"].selectionEnabled(1)
144                 self["messagelist"].selectionEnabled(0)
145
146         def selectMessagelist(self):
147                 self.currList = "messagelist"
148                 self["boxlist"].selectionEnabled(0)
149                 self["messagelist"].selectionEnabled(1)
150
151         def up(self):
152                 self[self.currList].up()
153
154         def down(self):
155                 self[self.currList].down()
156
157         def left(self):
158                 self[self.currList].pageUp()
159
160         def right(self):
161                 self[self.currList].pageDown()
162
163         def action_ok(self):
164                 if self.currList == "boxlist":
165                         self.onBoxSelected()
166                 else:
167                         self.onMessageSelected()
168
169         def onBoxSelected(self):
170                 c = self["boxlist"].getCurrent()
171                 if c is not None:
172                         self.proto.select(UTF7toUTF8(c[1][2]) # select instead of examine to get write access
173                                                            ).addCallback(self.onExamine, c[0] , self.proto
174                                                           ).addErrback(self.onExamineFailed, self.proto
175                                                           )
176
177         def onMessageSelected(self):
178                 c = self["messagelist"].getCurrent()
179                 if c is not None:
180                         self.fetchMessageSize(c[0])
181
182         def fetchMessageSize(self, message):
183                 print "fetchMessageSize",message
184                 self.proto.fetchSize(message.uid
185                         ).addCallback(self.onMessageSizeLoaded, message, self.proto
186                         ).addErrback(self.onMessageLoadFailed, message, self.proto
187                         )
188
189         def onMessageSizeLoaded(self, result, message, proto):
190                 print "onMessageSizeLoaded", result, message
191                 size = int(result[message.uid]['RFC822.SIZE'])
192                 self.MAX_MESSAGE_SIZE_TO_OPEN = 4000000
193                 if size >= self.MAX_MESSAGE_SIZE_TO_OPEN:
194                         #ask here to open message
195                         print "message to large to open (size=", size, ")"
196                 else:
197                         self.loadMessage(message)
198
199 #       def fetchBodyStructure(self, message):
200 #               print "fetchBodyStructure",message
201 #               self.proto.fetchBodyStructure(message.uid
202 #                       ).addCallback(self.onBodystructureLoaded, message, self.proto
203 #                       ).addErrback(self.onMessageLoadFailed, message, self.proto
204 #                       )
205
206         def loadMessage(self, message):
207                 print "loadMessage",message
208                 self["infolabel"].setText("loading message")
209
210                 self.proto.fetchMessage(message.uid
211                         ).addCallback(self.onMessageLoaded, message, self.proto
212                         ).addErrback(self.onMessageLoadFailed, message, self.proto
213                         )
214
215         def onMessageLoaded(self, result, message, proto):
216                 self["infolabel"].setText("parsing message")
217                 print "onMessageLoaded"#,result,message
218                 try:
219                         msgstr = result[message.uid]['RFC822']
220                 except KeyError:
221                         self.loadMessage(message)
222                         return
223                 msg = email.Parser.Parser().parsestr(msgstr)
224                 msg.messagebodys = []
225                 msg.attachments = []
226
227                 if msg.is_multipart():
228                         for part in msg.walk():
229                                 if part.get_content_maintype()=="multipart":
230                                         continue
231                                 if part.get_content_maintype() == 'text' and part.get_filename() is None:
232                                         if part.get_content_subtype() == "html":
233                                                 msg.messagebodys.append(EmailBody(part))
234                                         elif part.get_content_subtype() == "plain":
235                                                 msg.messagebodys.append(EmailBody(part))
236                                         else:
237                                                 print "unkown content type= ", part.get_content_maintype(), "/", part.get_content_subtype()
238                                 else:
239                                         print "found Attachment with  ", part.get_content_type(), "and name", part.get_filename()
240                                         msg.attachments.append(EmailAttachment(part.get_filename(), part.get_content_type(), part.get_payload()))
241                 else:
242                         msg.messagebodys.append(EmailBody(msg))
243                 self.session.open(ScreenMailView, msg, message.uid, proto, self.flagsList[message.uid]['FLAGS']).onHide.append(self.onBoxSelected)
244
245         def onMessageLoadFailed(self, failure, message, proto):
246                 print "onMessageLoadFailed", failure, message
247                 self["infolabel"].setText(failure.getErrorMessage())
248
249         def action_exit(self):
250                 if self.proto is not None:
251                         self.proto.logout().addCallback(self.onLogedOut, self.proto).addErrback(self.onLogedOut, self.proto)
252                 else:
253                         self.close()
254
255         def onLogedOut(self, result, proto):
256                 print "onLogedOut", result
257                 self.close()
258
259         def onConnect(self, proto):
260                 self["infolabel"].setText("connected")
261                 proto.getCapabilities(
262                                                 ).addCallback(self.cbCapabilities, proto
263                                                 ).addErrback(self.ebCapabilities, proto
264                                                 )
265
266         def cbCapabilities(self,reason,proto):
267                 print "#"*30
268                 print "# If you have problems to log into your imap-server, please send me the output of the following line"
269                 print "# cbCapabilities",reason
270                 print "#"*30
271                 self.doLogin(proto)
272
273         def ebCapabilities(self,reason,proto):
274                 print "ebCapabilities",reason
275
276         def onConnectFailed(self, reason):
277                 self["infolabel"].setText(reason.getErrorMessage())
278
279         def onAuthentication(self, result, proto):
280                 self.proto = proto
281                 self["infolabel"].setText("logged in")
282                 # better use LSUB here to get only the subscribed to mailboxes
283                 proto.lsub("", "*").addCallback(self.onMailboxList, proto)
284
285         def doLogin(self, proto):
286                 print "login secure"
287                 useTLS = False #True
288                 if useTLS:
289                         context = proto.context.getContext()
290                         d = proto.startTLS(context)
291                         d = d.addCallback(proto.authenticate, config.plugins.emailimap.password.value)
292                 else:
293                         d = proto.authenticate(config.plugins.emailimap.password.value)
294                 d.addCallback(self.onAuthentication, proto)
295                 d.addErrback(self.onAuthenticationFailed, proto)
296                 return d
297
298         def onAuthenticationFailed(self, failure, proto):
299                 # If it failed because no SASL mechanisms match
300                 print "onAuthenticationFailed", failure, proto
301                 self["infolabel"].setText(failure.getErrorMessage())
302                 try:
303                         failure.trap(imap4.NoSupportedAuthentication)
304                         self.doLoginInsecure(proto)
305                 except Exception,e:
306                         print e,e.message
307
308         def doLoginInsecure(self, proto):
309                 print "login INSECURE"
310                 proto.login(config.plugins.emailimap.username.value, config.plugins.emailimap.password.value
311                                 ).addCallback(self.onAuthentication, proto
312                                 ).addErrback(self.onInsecureAuthenticationFailed, proto
313                                 )
314
315         def onInsecureAuthenticationFailed(self, failure, proto):
316                 print "onInsecureAuthenticationFailed", failure, proto
317                 self["infolabel"].setText(failure.getErrorMessage())
318
319         def onMailboxList(self, result, proto):
320                 print "onMailboxList", result, proto
321                 list = []
322                 inboxPos = 0
323                 for i in result:
324                         flags, hierarchy_delimiter, name = i #@UnusedVariable
325                         list.append((UTF7toUTF8(name).encode('utf-8'), i))
326                         if name.lower() == 'inbox':
327                                 inboxPos = len(list)
328                 self["boxlist"].setList(list)
329                 self["boxlist"].moveToIndex(inboxPos-1)
330
331         def onExamine(self, result, mboxname, proto):
332                 print "onExamine", result, mboxname
333                 self.setTitle("Mailbox: "+mboxname)
334                 self.currentmailbox = mboxname
335                 numMessagesinFolder = int(result['EXISTS'])
336                 if numMessagesinFolder <= 0:
337                         self["infolabel"].setText("Box '"+mboxname+"' is empty")
338                         self["messagelist"].l.setList([])
339
340                 else:
341                         if config.plugins.emailimap.maxheadertoload.value > 0:
342                                 maxMessagesToFetch = config.plugins.emailimap.maxheadertoload.value
343                                 startmsg = numMessagesinFolder-maxMessagesToFetch+1
344                                 if startmsg <= 0:
345                                         startmsg = 1
346                                 rangeToFetch = [startmsg, numMessagesinFolder]
347                         else:
348                                 rangeToFetch = [1, numMessagesinFolder]
349                         self["infolabel"].setText("loading headers "+str(rangeToFetch[0])+"-"+str(rangeToFetch[1])+" of Box '"+mboxname+"'")
350
351                         try:
352 #                               proto.fetchEnvelope('%i:%i'%(rangeToFetch[0], rangeToFetch[1])  #'1:*'
353 #                                                  ).addCallback(self.onEnvelopeList, proto
354 #                                                  )
355                                 self.proto = proto
356                                 self.rangeToFetch = rangeToFetch
357                                 proto.fetchFlags('%i:%i'%(rangeToFetch[0], rangeToFetch[1])     #'1:*'
358                                                    ).addCallback(self.onFlagsList)
359
360                         except imap4.IllegalServerResponse, e:
361                                 print e
362                         self.selectMessagelist()
363
364         def onFlagsList(self, result):
365                 self.flagsList = result
366                 self.proto.fetchHeaders('%i:%i'%(self.rangeToFetch[0], self.rangeToFetch[1])    #'1:*'
367                                    ).addCallback(self.onHeaderList, self.proto
368                                    )
369
370         def onExamineFailed(self, failure, proto):
371                 print "onExamineFailed", failure, proto
372                 self["infolabel"].setText(failure.getErrorMessage())
373
374         def cbOk(self, result):
375                 print("cbOk result: %s" %repr(result))
376
377         def cbNotOk(self, result):
378                 print("cbNotOk result: %s" %(result))
379
380         def onHeaderList(self, result, proto):
381                 print "onHeaderList"#,result,proto
382                 self["infolabel"].setText("headers loaded, now parsing ...")
383                 list = []
384                 for m in result:
385                         state = IS_UNSEEN
386                         # print("onHeaderList :" + repr(self.flagsList[m]['FLAGS']))
387                         if '\\Seen' in self.flagsList[m]['FLAGS']:
388                                 state = IS_SEEN
389                         if '\\Deleted' in self.flagsList[m]['FLAGS']:
390                                 if not config.plugins.emailimap.showDeleted.value:
391                                         continue
392                                 else:
393                                         state = IS_DELETED
394                         try:
395                                 list.append(self.buildMessageListItem(MessageHeader(m, result[m]['RFC822.HEADER']), state))
396                         except Exception,e:
397                                 try:
398                                         list.append(self.buildMessageListItem(MessageHeader(m, result[m]['RFC822.HEADER'].decode('iso8859-1', 'replace'), state)))
399                                 except:
400                                         # this appear to be errors in the formatting of the mail itself...
401                                         print "onHeaderList error: %s with: %s" %(e,result[m]['RFC822.HEADER'])
402                 list.reverse()
403                 self["messagelist"].l.setList(list)
404                 self["infolabel"].setText("have "+str(len(list))+" messages ")
405
406         def buildMessageListItem(self, message, state):
407                 if state == IS_UNSEEN:
408                         font = 0
409                         color = 0x00FFFFFF # white
410                 elif state == IS_DELETED:
411                         font = 1 
412                         color = 0x00FF6666 # redish :)
413                 else:
414                         font = 2
415                         color = 0x00888888 # grey
416                 return [
417                         message,
418                         MultiContentEntryText(pos=(5, 0), size=(self.messagelistWidth, scaleV(20,18)+5), font=font, text=message.getSenderString(), color=color, color_sel=color),
419                         MultiContentEntryText(pos=(5, scaleV(20,18)+1), size=(self.messagelistWidth, scaleV(20,18)+5), font=font, text=message.get('date', default='kein Datum'), color=color, color_sel=color),
420                         MultiContentEntryText(pos=(5, 2*(scaleV(20,18)+1)), size=(self.messagelistWidth, scaleV(20,18)+5), font=font, text=message.getSubject(), color=color, color_sel=color)
421                 ]
422         #
423         # IMailboxListener methods
424         #
425         def modeChanged(self, writeable):
426                 print "modeChanged", writeable
427
428         def flagsChanged(self, newFlags):
429                 print "flagsChanged", newFlags
430
431         def newMessages(self, exists, recent):
432                 print "newMessages", exists, recent
433
434 class ScreenMailView(Screen):
435         skin=""
436         def __init__(self, session, email, uid, proto, flags):
437                 self.session = session
438                 self.email = email
439                 # print('ScreenMailView ' + repr(email) + ' dir: ' + repr(dir(email)))
440                 width = max(4*140,scaleH(-1,550))
441                 height = scaleV(-1,476)
442                 fontSize = scaleV(24,20)
443                 lineHeight = fontSize+5
444                 buttonsGap = (width-4*140)/5
445                 self.skin = """
446                 <screen position="%d,%d" size="%d,%d" title="view Email" >
447                         <widget name="from" position="%d,%d" size="%d,%d"  font="Regular;%d" />
448                         <widget name="date" position="%d,%d" size="%d,%d"  font="Regular;%d" />
449                         <widget name="subject" position="%d,%d" size="%d,%d"  font="Regular;%d" />
450                         <eLabel position="%d,%d" size="%d,2" backgroundColor="#aaaaaa" />
451                         <widget name="body" position="%d,%d" size="%d,%d"  font="Regular;%d" />
452                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
453                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
454                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
455                         <ePixmap position="%d,%d" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
456                         <widget name="buttonred" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
457                         <widget name="buttongreen" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
458                         <widget name="buttonyellow" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
459                         <widget name="buttonblue" position="%d,%d" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;%d" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
460                 </screen>""" %(
461                                            (DESKTOP_WIDTH-width)/2, (DESKTOP_HEIGHT-height)/2, width, height,
462                                            0, 0, width, lineHeight, fontSize-1, # from
463                                            0, lineHeight, width, lineHeight, fontSize-1, # date
464                                            0, 2*lineHeight, width, lineHeight, fontSize-1, # subject 
465                                            0, 3*lineHeight+1, width, # line 
466                                            0, 3*lineHeight+5, width, height-3*lineHeight-5-5-30-5, fontSize, # body
467                                            buttonsGap, height-30-5,
468                        2*buttonsGap+140, height-30-5,
469                        3*buttonsGap+2*140, height-30-5,
470                        4*buttonsGap+3*140, height-30-5,
471                        buttonsGap, height-30-5, scaleV(18,16),
472                        2*buttonsGap+140, height-30-5, scaleV(18,16),
473                        3*buttonsGap+2*140, height-30-5, scaleV(18,16),
474                        4*buttonsGap+3*140, height-30-5, scaleV(18,16),
475                                            )
476                 Screen.__init__(self, session)
477                 self["from"] = Label(decodeHeader(_("From") +": %s" %self.email.get('from', 'no-from')))
478                 self["date"] = Label(_("Date") +": %s" %self.email.get('date', 'no-date'))
479                 self["subject"] = Label(decodeHeader(_("Subject") +": %s" %self.email.get('subject', 'no-subject')))
480                 self["body"] = ScrollLabel(_(self.email.messagebodys[0].getData()))
481                 self["buttonred"] = Button(_(""))
482                 self["buttongreen"] = Button("")
483                 # TODO: show headers
484                 self["buttonyellow"] = Button("")
485                 if '\\Deleted' in flags:
486                         self["buttonblue"] = Button(_("undelete"))
487                 else:
488                         self["buttonblue"] = Button(_("delete"))
489                 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "MenuActions", "ShortcutActions"],
490                         {
491                          "back": self.close,
492                          "up": self["body"].pageUp,
493                          "down": self["body"].pageDown,
494                          # TODO: perhaps better use left/right for previous/next message
495                          "left": self["body"].pageUp,
496                          "right": self["body"].pageDown,
497                          "red": self.selectBody,
498                          "green": self.selectAttachment,
499                          "yellow": self.openMessagesHeaders,
500                          "blue": self.delete,
501
502                          }, -1)
503                 self.flags = flags
504                 self.proto = proto
505                 self.uid = uid
506                 proto.fetchFlags(self.uid).addCallback(self.cbOk).addErrback(self.cbNotOk)
507                 self.onLayoutFinish.append(self.updateButtons)
508
509         def cbOk(self, result):
510                 print("cbOk result: %s" %repr(result))
511
512         def cbNotOk(self, result):
513                 print("cbNotOk result: %s" %(result))
514
515         def delete(self):
516                 if '\\Deleted' in self.flags:
517                         self.session.openWithCallback(self.deleteCB, ChoiceBox, title=_("really undelete Mail?"), list=[(_("yes"), True),(_("no"), False)])
518                 else:
519                         self.session.openWithCallback(self.deleteCB, ChoiceBox, title=_("really delete Mail?"), list=[(_("yes"), True),(_("no"), False)])
520
521         def deleteCB(self, returnValue):
522                 if returnValue[1] is True:
523                         if '\\Deleted' in self.flags:
524                                 self.proto.removeFlags(self.uid, ["\\Deleted"]).addCallback(self.cbOk).addErrback(self.cbNotOk)
525                         else:
526                                 self.proto.addFlags(self.uid, ["\\Deleted"]).addCallback(self.cbOk).addErrback(self.cbNotOk)
527                         print("deleteCB: %s"  %repr(self.email))
528                         self.close()
529
530         def openMessagesHeaders(self):
531                 pass #self.session.open(ScreenMailViewHeader,self.profil,self.email)
532
533         def updateButtons(self):
534                 self["buttonred"].setText(_("Bodys"))
535                 if len(self.email.attachments):
536                         self["buttongreen"].setText(_("Attachments"))
537                 else:
538                         self["buttongreen"].setText("")
539
540         def selectBody(self):
541                 if len(self.email.messagebodys):
542                         list = []
543                         for a in self.email.messagebodys:
544                                 list.append((a.getContenttype(), a))
545                         self.session.openWithCallback(self.selectBodyCB, ChoiceBox, _("select Body"), list)
546
547         def selectBodyCB(self, choice):
548                 if choice is not None:
549                         self["body"].setText(choice[1].getData())
550
551         def selectAttachment(self):
552                 if len(self.email.attachments):
553                         list = []
554                         for a in self.email.attachments:
555                                 name = a.getFilename()
556                                 if name:
557                                         list.append((a.getFilename(), a))
558                                 else:
559                                         list.append((_("no filename"), a))
560                         print("selectAttachment : " + repr(list))
561                         self.session.openWithCallback(self.selectAttachmentCB, ChoiceBox, _("select Attachment"), list)
562
563         def selectAttachmentCB(self, choice):
564                 if choice is not None:
565                         print "Attachment selected", choice[1].getFilename()
566                         #showMessageBox(self.session)
567
568 class MailList(MenuList):
569         def __init__(self, list, enableWrapAround = False):
570                 MenuList.__init__(self, list, enableWrapAround, eListboxPythonMultiContent)
571                 self.l.setFont(0, gFont("Regular", scaleV(20,18))) # new
572                 self.l.setFont(1, gFont("Regular", scaleV(18,16))) # deleted
573                 self.l.setFont(2, gFont("Regular", scaleV(18,16))) # seen
574
575         def postWidgetCreate(self, instance):
576                 MenuList.postWidgetCreate(self, instance)
577                 instance.setItemHeight(scaleV(70,60))
578
579 class MessageHeader(object):
580         def __init__(self, uid, message):
581                 self.uid = uid #must be int
582                 self.message = email.Parser.Parser().parsestr(message)
583
584         def getSenderString(self):
585                 return decodeHeader(self.get("from"), _("no sender"))
586
587         def getSubject(self):
588                 return decodeHeader(self.get("subject"), _("no subject"))
589
590         def get(self, key, default=None):
591                 return self.message.get(key,failobj=default)
592
593         def __str__(self):
594                 return "<MessageHeader uid="+str(self.uid)+", subject="+self.get("subject","no-subject")+">"
595
596 ############
597 class EmailBody:
598         def __init__(self,data):
599                 self.data = data
600
601         def getEncoding(self):
602                 return self.data.get_content_charset()
603
604         def getData(self):
605                 text = self.data.get_payload(decode=True)
606                 if self.getEncoding():
607                         try:
608                                 text = text.decode(self.getEncoding())
609                         except UnicodeDecodeError:
610                                 pass    
611                 # print('EmailBody/getData text: ' +  text)
612                 #=======================================================================
613                 # if self.getEncoding():
614                 #       text = text.decode(self.getEncoding())
615                 #=======================================================================
616                 if self.getContenttype() == "text/html":
617                         print "stripping html"
618                         text = strip_readable(text)
619                         # print('EmailBody/getData text: ' +  text)
620
621                 try:
622                         return text.encode('utf-8')
623                 except UnicodeDecodeError:
624                         return text
625                 
626
627         def getContenttype(self):
628                 return self.data.get_content_type()
629
630 ############
631 class EmailAttachment:
632         def __init__(self, filename, contenttype, data):
633                 self.filename = filename
634                 self.contenttype = contenttype
635                 self.data = data
636
637         def save(self,folder):
638                 try:
639                         fp = open(folder+"/"+self.getFilename(),"wb")
640                         fp.write(self.data)
641                         fp.close()
642                 except Exception,e:
643                         print e
644                         return False
645                 return True
646
647         def getFilename(self):
648                 return self.filename
649
650         def getContenttype(self):
651                 return self.contenttype
652
653         def getData(self):
654                 return self.data
655
656 def UTF7toUTF8(str):
657         return imap4.decoder(str)[0]
658
659 def UTF8toUTF7(str):
660         return imap4.encoder(str.decode('utf-8'))[0]
661
662 def main(session, **kwargs):
663         import os,shutil
664         if os.path.isfile('/usr/lib/python2.5/uu.py') is not True:
665                 shutil.copy('/usr/lib/enigma2/python/Plugins/Extensions/EmailClient/uu.py', '/usr/lib/python2.5/uu.py')
666                 global session2
667                 session2 = session
668                 session.openWithCallback(MessageCB, MessageBox, 'In order of missing standart python library files\ni have copied the nessary files now.\nBut you have to restart your Box\n to apply this!', type = MessageBox.TYPE_INFO)
669         else:
670                 session.open(EmailScreen)
671
672 def MessageCB(*args):
673         global session2
674         session2.open(EmailScreen)
675
676 def Plugins(path, **kwargs):
677         global plugin_path
678         plugin_path = path
679         return [
680                          PluginDescriptor(name="Email Client", description="view Emails via IMAP4",
681                          where = PluginDescriptor.WHERE_PLUGINMENU,
682                          fnc = main,
683                          icon="plugin.png"
684                          ),
685                 ]