1
2 """
3 # DESCRIPTION:
4 # Entropy Object Oriented Interface
5
6 Copyright (C) 2007-2009 Fabio Erculiani
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 """
22
23 from __future__ import with_statement
24 import os
25 import sys
26 import time
27 import urllib2
28 import threading
29 from entropy.const import etpConst, etpUi
30 from entropy.core import SystemSettings
31
33
36
37 - def push(self, item):
38 try:
39 idx = max(self.__buf)+1
40 except ValueError:
41 idx = 0
42 self.__buf[idx] = item
43
46
48 if self.__buf:
49 return True
50 return False
51
53 for key, buf_entry in self.__buf.items():
54
55
56 if entry is buf_entry:
57 self.__buf.pop(key)
58 continue
59 if entry == buf_entry:
60 self.__buf.pop(key)
61 continue
62
64 try:
65 idx = max(self.__buf)
66 except (ValueError, TypeError,):
67 return None
68 return self.__buf.pop(idx)
69
71
72 - def __init__(self, delay, *args, **kwargs):
73 threading.Thread.__init__(self)
74 self.__f = args[0]
75 self.__delay = delay
76 self.__args = args[1:][:]
77 self.__kwargs = kwargs.copy()
78
79
80
81
82 self.__accurate = False
83 self.__delay_before = False
84 self.__alive = 0
85
88
90 self.__delay_before = bool(bool_do)
91
93 self.__accurate = bool(bool_do)
94
96 self.__alive = 1
97 while self.__alive:
98
99 if self.__delay_before:
100 do_break = self.__do_delay()
101 if do_break:
102 break
103
104 if self.__f == None:
105 break
106 self.__f(*self.__args, **self.__kwargs)
107
108 if not self.__delay_before:
109 do_break = self.__do_delay()
110 if do_break:
111 break
112
113
115
116 if not self.__accurate:
117
118 if float == None:
119 return True
120 mydelay = float(self.__delay)
121 t_frac = 0.3
122 while mydelay > 0.0:
123 if not self.__alive:
124 return True
125 if time == None:
126 return True
127 time.sleep(t_frac)
128 mydelay -= t_frac
129
130 else:
131
132 if time == None:
133 return True
134 time.sleep(self.__delay)
135
136 return False
137
140
142
144 threading.Thread.__init__(self)
145 self.__function = args[0]
146 self.__args = args[1:][:]
147 self.__kwargs = kwargs.copy()
148 self.__rc = None
149
151 self.__rc = self.__function(*self.__args, **self.__kwargs)
152
154 return self.__function
155
158
160
162 import smtplib
163 self.smtplib = smtplib
164 from email.mime.audio import MIMEAudio
165 from email.mime.image import MIMEImage
166 from email.mime.text import MIMEText
167 from email.mime.base import MIMEBase
168 from email.mime.multipart import MIMEMultipart
169 from email import encoders
170 from email.message import Message
171 import mimetypes
172 self.smtpuser = None
173 self.smtppassword = None
174 self.smtphost = 'localhost'
175 self.smtpport = 25
176 self.text = MIMEText
177 self.mimefile = MIMEBase
178 self.audio = MIMEAudio
179 self.image = MIMEImage
180 self.multipart = MIMEMultipart
181 self.default_sender = self.smtp_send
182 self.mimetypes = mimetypes
183 self.encoders = encoders
184 self.message = Message
185
186 - def smtp_send(self, sender, destinations, message):
187 s_srv = self.smtplib.SMTP(self.smtphost, self.smtpport)
188 if self.smtpuser and self.smtppassword:
189 s_srv.login(self.smtpuser, self.smtppassword)
190 s_srv.sendmail(sender, destinations, message)
191 s_srv.quit()
192
193 - def send_text_email(self, sender_email, destination_emails, subject,
194 content):
195
196
197 if isinstance(content, unicode):
198 content = content.encode('utf-8')
199 if isinstance(subject, unicode):
200 subject = subject.encode('utf-8')
201
202 msg = self.text(content)
203 msg['Subject'] = subject
204 msg['From'] = sender_email
205 msg['To'] = ', '.join(destination_emails)
206 return self.default_sender(sender_email, destination_emails,
207 msg.as_string())
208
209 - def send_mime_email(self, sender_email, destination_emails, subject,
210 content, files):
211
212 outer = self.multipart()
213 outer['Subject'] = subject
214 outer['From'] = sender_email
215 outer['To'] = ', '.join(destination_emails)
216 outer.preamble = subject
217
218 mymsg = self.text(content)
219 outer.attach(mymsg)
220
221
222 for myfile in files:
223 if not (os.path.isfile(myfile) and os.access(myfile, os.R_OK)):
224 continue
225
226 ctype, encoding = self.mimetypes.guess_type(myfile)
227 if ctype is None or encoding is not None:
228 ctype = 'application/octet-stream'
229 maintype, subtype = ctype.split('/', 1)
230
231 if maintype == 'image':
232 img_f = open(myfile, 'rb')
233 msg = self.image(img_f.read(), _subtype = subtype)
234 img_f.close()
235 elif maintype == 'audio':
236 audio_f = open(myfile, 'rb')
237 msg = self.audio(audio_f.read(), _subtype = subtype)
238 audio_f.close()
239 else:
240 gen_f = open(myfile, 'rb')
241 msg = self.mimefile(maintype, subtype)
242 msg.set_payload(gen_f.read())
243 gen_f.close()
244 self.encoders.encode_base64(msg)
245
246 msg.add_header('Content-Disposition', 'attachment',
247 filename = os.path.basename(myfile))
248 outer.attach(msg)
249
250 composed = outer.as_string()
251 return self.default_sender(sender_email, destination_emails, composed)
252
254
255 """
256 Entropy geo-tagging interface containing useful
257 methods to ease metadata management and transfor-
258 mation.
259 It's a wrapper over GeoIP at the moment
260 dev-python/geoip-python required
261 """
262
264
265 """
266 @param1: valid GeoIP (Maxmind) database file (.dat)
267 """
268
269 import GeoIP
270 self.__geoip = GeoIP
271
272 if not (os.path.isfile(geoip_dbfile) and \
273 os.access(geoip_dbfile, os.R_OK)):
274 raise AttributeError(
275 "expecting a valid filepath for geoip_dbfile, got: %s" % (
276 repr(geoip_dbfile),
277 )
278 )
279 self.__geoip_dbfile = geoip_dbfile
280
282 return self.__geoip.new(self.__geoip.GEOIP_MEMORY_CACHE)
283
285 return self.__geoip.open(self.__geoip_dbfile,
286 self.__geoip.GEOIP_STANDARD)
287
289 """
290 @return: string or None
291 @param1: ip address string
292 """
293 gi_a = self.__get_geo_ip_generic()
294 return gi_a.country_name_by_addr(ip_address)
295
297 """
298 @return: string or None
299 @param1: ip address string
300 """
301 gi_a = self.__get_geo_ip_generic()
302 return gi_a.country_code_by_addr(ip_address)
303
305 """
306 @return: dict() or None
307 @param1: ip address string
308 dict data:
309 {
310 'city': 'Treviso',
311 'region': '20',
312 'area_code': 0,
313 'longitude': 12.244999885559082,
314 'country_code3': 'ITA',
315 'latitude': 45.666698455810547,
316 'postal_code': None,
317 'dma_code': 0,
318 'country_code': 'IT',
319 'country_name': 'Italy'
320 }
321 """
322 go_a = self.__get_geo_ip_open()
323 return go_a.record_by_addr(ip_address)
324
326 """
327 @return: dict() or None
328 @param1: hostname
329 """
330 go_a = self.__get_geo_ip_open()
331 return go_a.record_by_name(hostname)
332
333
335
336
337 import tools as entropyTools
339
340 self.__system_settings = SystemSettings()
341 self.__feed_title = title
342 self.__feed_title = self.__feed_title.strip()
343 self.__feed_description = description
344 self.__feed_language = "en-EN"
345 self.__srv_settings_plugin_id = \
346 etpConst['system_settings_plugins_ids']['server_plugin']
347 srv_settings = self.__system_settings.get(self.__srv_settings_plugin_id)
348 if srv_settings is None:
349 self.__feed_editor = "N/A"
350 else:
351 self.__feed_editor = srv_settings['server']['rss']['editor']
352 self.__feed_copyright = "%s - (C) %s" % (
353 self.__system_settings['system']['name'],
354 self.entropyTools.get_year(),
355 )
356
357 self.__file = filename
358 self.__items = {}
359 self.__itemscounter = 0
360 self.__maxentries = maxentries
361 from xml.dom import minidom
362 self.minidom = minidom
363
364
365 broken = False
366 if os.path.isfile(self.__file):
367 try:
368 self.xmldoc = self.minidom.parse(self.__file)
369 except:
370 broken = True
371
372 if not os.path.isfile(self.__file) or broken:
373
374 self.__title = self.__feed_title
375 self.__description = self.__feed_description
376 self.__language = self.__feed_language
377 self.__cright = self.__feed_copyright
378 self.__editor = self.__feed_editor
379 sys_set = self.__system_settings[self.__srv_settings_plugin_id]
380 srv_set = sys_set['server']
381 self.__link = srv_set['rss']['website_url']
382 rss_f = open(self.__file, "w")
383 rss_f.write('')
384 rss_f.flush()
385 rss_f.close()
386
387 else:
388
389 self.__rssdoc = self.xmldoc.getElementsByTagName("rss")[0]
390 self.__channel = self.__rssdoc.getElementsByTagName("channel")[0]
391 title_obj = self.__channel.getElementsByTagName("title")[0]
392 self.__title = title_obj.firstChild.data.strip()
393 link_obj = self.__channel.getElementsByTagName("link")[0]
394 self.__link = link_obj.firstChild.data.strip()
395 desc_obj = self.__channel.getElementsByTagName("description")[0]
396 description = desc_obj.firstChild
397 if hasattr(description, "data"):
398 self.__description = description.data.strip()
399 else:
400 self.__description = ''
401 try:
402 lang_obj = self.__channel.getElementsByTagName("language")[0]
403 self.__language = lang_obj.firstChild.data.strip()
404 except IndexError:
405 self.__language = 'en'
406 try:
407 cright_obj = self.__channel.getElementsByTagName("copyright")[0]
408 self.__cright = cright_obj.firstChild.data.strip()
409 except IndexError:
410 self.__cright = ''
411 try:
412 e_obj = self.__channel.getElementsByTagName("managingEditor")[0]
413 self.__editor = e_obj.firstChild.data.strip()
414 except IndexError:
415 self.__editor = ''
416 entries = self.__channel.getElementsByTagName("item")
417 self.__itemscounter = len(entries)
418 if self.__itemscounter > self.__maxentries:
419 self.__itemscounter = self.__maxentries
420 mycounter = self.__itemscounter
421 for item in entries:
422 if mycounter == 0:
423 break
424 mycounter -= 1
425 self.__items[mycounter] = {}
426 title_obj = item.getElementsByTagName("title")[0]
427 self.__items[mycounter]['title'] = \
428 title_obj.firstChild.data.strip()
429 desc_obj = item.getElementsByTagName("description")[0]
430 description = desc_obj.firstChild
431 if description:
432 self.__items[mycounter]['description'] = \
433 description.data.strip()
434 else:
435 self.__items[mycounter]['description'] = ""
436
437 link = item.getElementsByTagName("link")[0].firstChild
438 if link:
439 self.__items[mycounter]['link'] = link.data.strip()
440 else:
441 self.__items[mycounter]['link'] = ""
442
443 guid_obj = item.getElementsByTagName("guid")[0]
444 self.__items[mycounter]['guid'] = \
445 guid_obj.firstChild.data.strip()
446 pub_date_obj = item.getElementsByTagName("pubDate")[0]
447 self.__items[mycounter]['pubDate'] = \
448 pub_date_obj.firstChild.data.strip()
449 dcs = item.getElementsByTagName("dc:creator")
450 if dcs:
451 self.__items[mycounter]['dc:creator'] = \
452 dcs[0].firstChild.data.strip()
453
454
456
457 self.__itemscounter += 1
458 self.__items[self.__itemscounter] = {}
459 self.__items[self.__itemscounter]['title'] = title
460 if pubDate:
461 self.__items[self.__itemscounter]['pubDate'] = pubDate
462 else:
463 self.__items[self.__itemscounter]['pubDate'] = \
464 time.strftime("%a, %d %b %Y %X +0000")
465 self.__items[self.__itemscounter]['description'] = description
466 self.__items[self.__itemscounter]['link'] = link
467 if link:
468 self.__items[self.__itemscounter]['guid'] = link
469 else:
470 myguid = self.__system_settings['system']['name'].lower()
471 myguid = myguid.replace(" ", "")
472 self.__items[self.__itemscounter]['guid'] = myguid+"~" + \
473 description + str(self.__itemscounter)
474 return self.__itemscounter
475
477 if key in self.__items:
478 del self.__items[key]
479 self.__itemscounter -= 1
480 return self.__itemscounter
481
483 return self.__items, self.__itemscounter
484
486
487
488 if self.__itemscounter > self.__maxentries:
489 tobefiltered = self.__itemscounter - self.__maxentries
490 for index in range(tobefiltered):
491 try:
492 del self.__items[index]
493 except KeyError:
494 pass
495
496 doc = self.minidom.Document()
497
498 rss = doc.createElement("rss")
499 rss.setAttribute("version", "2.0")
500 rss.setAttribute("xmlns:atom", "http://www.w3.org/2005/Atom")
501
502 channel = doc.createElement("channel")
503
504
505 title = doc.createElement("title")
506 title_text = doc.createTextNode(unicode(self.__title))
507 title.appendChild(title_text)
508 channel.appendChild(title)
509
510 link = doc.createElement("link")
511 link_text = doc.createTextNode(unicode(self.__link))
512 link.appendChild(link_text)
513 channel.appendChild(link)
514
515 description = doc.createElement("description")
516 desc_text = doc.createTextNode(unicode(self.__description))
517 description.appendChild(desc_text)
518 channel.appendChild(description)
519
520 language = doc.createElement("language")
521 lang_text = doc.createTextNode(unicode(self.__language))
522 language.appendChild(lang_text)
523 channel.appendChild(language)
524
525 cright = doc.createElement("copyright")
526 cr_text = doc.createTextNode(unicode(self.__cright))
527 cright.appendChild(cr_text)
528 channel.appendChild(cright)
529
530 managing_editor = doc.createElement("managingEditor")
531 ed_text = doc.createTextNode(unicode(self.__editor))
532 managing_editor.appendChild(ed_text)
533 channel.appendChild(managing_editor)
534
535 keys = self.__items.keys()
536 if reverse:
537 keys.reverse()
538 for key in keys:
539
540
541 if not self.__items.has_key(key):
542 self.remove_entry(key)
543 continue
544 k_error = False
545 for item in ('title', 'link', 'guid', 'description', 'pubDate',):
546 if not self.__items[key].has_key(item):
547 k_error = True
548 break
549 if k_error:
550 self.remove_entry(key)
551 continue
552
553
554 item = doc.createElement("item")
555
556 item_title = doc.createElement("title")
557 item_title_text = doc.createTextNode(
558 unicode(self.__items[key]['title']))
559 item_title.appendChild(item_title_text)
560 item.appendChild(item_title)
561
562 item_link = doc.createElement("link")
563 item_link_text = doc.createTextNode(
564 unicode(self.__items[key]['link']))
565 item_link.appendChild(item_link_text)
566 item.appendChild(item_link)
567
568 item_guid = doc.createElement("guid")
569 item_guid.setAttribute("isPermaLink", "true")
570 item_guid_text = doc.createTextNode(
571 unicode(self.__items[key]['guid']))
572 item_guid.appendChild(item_guid_text)
573 item.appendChild(item_guid)
574
575 item_desc = doc.createElement("description")
576 item_desc_text = doc.createTextNode(
577 unicode(self.__items[key]['description']))
578 item_desc.appendChild(item_desc_text)
579 item.appendChild(item_desc)
580
581 item_date = doc.createElement("pubDate")
582 item_date_text = doc.createTextNode(
583 unicode(self.__items[key]['pubDate']))
584 item_date.appendChild(item_date_text)
585 item.appendChild(item_date)
586
587
588 channel.appendChild(item)
589
590
591 rss.appendChild(channel)
592 doc.appendChild(rss)
593 rss_f = open(self.__file, "w")
594 rss_f.writelines(doc.toprettyxml(indent=" ").encode('utf-8'))
595 rss_f.flush()
596 rss_f.close()
597
599
600 - def __init__(self, level = 0, filename = None, header = "[LOG]"):
601 self.handler = self.default_handler
602 self.level = level
603 self.header = header
604 self.__logfile = None
605 self.open(filename)
606 self.__filename = filename
607
610
612 try:
613 self.__logfile.close()
614 except (IOError, OSError,):
615 pass
616
618 return self.__filename
619
621 self.__logfile.flush()
622
624 return self.__get_file()
625
628
629 - def read(self, *args):
631
634
637
638 - def seek(self, offset):
639 return self.__logfile.seek(offset)
640
642 return self.__logfile.tell()
643
646
647 - def open(self, file_path = None):
648
649 if isinstance(file_path, basestring):
650 if not os.access(file_path, os.F_OK) and os.access(
651 os.path.dirname(file_path), os.W_OK):
652 self.__logfile = open(file_path, "aw")
653 else:
654 if os.access(file_path, os.W_OK | os.F_OK):
655 self.__logfile = open(file_path, "aw")
656 else:
657 self.__logfile = open("/dev/null", "aw")
658 elif hasattr(file_path, 'write'):
659 self.__logfile = file_path
660 else:
661 self.__logfile = sys.stderr
662
664 return self.__logfile.fileno()
665
667 self.handler (format % args)
668
670 try:
671 self.__logfile.write ("* %s\n" % (mystr))
672 except UnicodeEncodeError:
673 self.__logfile.write ("* %s\n" % (mystr.encode('utf-8'),))
674 self.__logfile.flush()
675
678
679 - def log(self, messagetype, level, message):
680 if self.level >= level and not etpUi['nolog']:
681 self.handler("%s %s %s %s" % (self.__get_header(),
682 messagetype, self.header, message,))
683
686
688 for line in lst:
689 self.write(line)
690
692 return time.strftime('[%H:%M:%S %d/%m/%Y %Z]')
693
697
698 -class MultipartPostHandler(urllib2.BaseHandler):
699
700 handler_order = urllib2.HTTPHandler.handler_order - 10
701
702 - def __init__(self):
704
705 - def http_request(self, request):
706
707 import urllib
708 doseq = 1
709
710 data = request.get_data()
711 if data is not None and type(data) != str:
712 v_files = []
713 v_vars = []
714 try:
715 for (key, value) in data.items():
716 if type(value) == file:
717 v_files.append((key, value))
718 else:
719 v_vars.append((key, value))
720 except TypeError:
721 raise TypeError, "not a valid non-string sequence" \
722 " or mapping object"
723
724 if len(v_files) == 0:
725 data = urllib.urlencode(v_vars, doseq)
726 else:
727 boundary, data = self.multipart_encode(v_vars, v_files)
728 contenttype = 'multipart/form-data; boundary=%s' % boundary
729 request.add_unredirected_header('Content-Type', contenttype)
730
731 request.add_data(data)
732 return request
733
734 - def multipart_encode(self, myvars, files, boundary = None, buf = None):
735
736 from cStringIO import StringIO
737 import mimetools, mimetypes
738
739
740 if boundary is None:
741 boundary = mimetools.choose_boundary()
742 if buf is None:
743 buf = StringIO()
744 for(key, value) in myvars:
745 buf.write('--%s\r\n' % boundary)
746 buf.write('Content-Disposition: form-data; name="%s"' % key)
747 buf.write('\r\n\r\n' + value + '\r\n')
748 for(key, fdesc) in files:
749
750 filename = fdesc.name.split('/')[-1]
751 contenttype = mimetypes.guess_type(filename)[0] or \
752 'application/octet-stream'
753 buf.write('--%s\r\n' % boundary)
754 buf.write('Content-Disposition: form-data; name="%s"; ' \
755 'filename="%s"\r\n' % (key, filename))
756 buf.write('Content-Type: %s\r\n' % contenttype)
757
758 fdesc.seek(0)
759 buf.write('\r\n' + fdesc.read() + '\r\n')
760 buf.write('--' + boundary + '--\r\n\r\n')
761 buf = buf.getvalue()
762 return boundary, buf
763
764 multipart_encode = Callable(multipart_encode)
765
766 https_request = http_request
767