f550665605
class. As announced, SystemSettings is going to host all the Entropy global variables. With this big commit, proxy config (and the rest of entropy.conf data) has been moved under SystemSettings['system']
745 lines
24 KiB
Python
745 lines
24 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
# DESCRIPTION:
|
|
# Entropy Object Oriented Interface
|
|
|
|
Copyright (C) 2007-2009 Fabio Erculiani
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
"""
|
|
# pylink ok - doc
|
|
from __future__ import with_statement
|
|
import os
|
|
import sys
|
|
import time
|
|
import urllib2
|
|
import threading
|
|
from entropy.const import etpConst, etpUi
|
|
from entropy.core import SystemSettings
|
|
|
|
class Lifo:
|
|
|
|
def __init__(self):
|
|
self.__counter = -1
|
|
self.__buf = {}
|
|
self.__lock = threading.Lock()
|
|
|
|
def push(self, item):
|
|
with self.__lock:
|
|
self.__counter += 1
|
|
self.__buf[self.__counter] = item
|
|
|
|
def clear(self):
|
|
with self.__lock:
|
|
self.__counter = -1
|
|
self.__buf.clear()
|
|
|
|
def is_filled(self):
|
|
if self.__counter == -1:
|
|
return False
|
|
return True
|
|
|
|
def pop(self):
|
|
with self.__lock:
|
|
if self.__counter == -1:
|
|
return None
|
|
self.__counter -= 1
|
|
try:
|
|
return self.__buf.pop(self.__counter+1)
|
|
except KeyError:
|
|
pass
|
|
|
|
class TimeScheduled(threading.Thread):
|
|
|
|
def __init__(self, delay, *args, **kwargs):
|
|
threading.Thread.__init__(self)
|
|
self.__f = args[0]
|
|
self.__delay = delay
|
|
self.__args = args[1:][:]
|
|
self.__kwargs = kwargs.copy()
|
|
# never enable this by default
|
|
# otherwise kill() and thread
|
|
# check will hang until
|
|
# time.sleep() is done
|
|
self.__accurate = False
|
|
self.__delay_before = False
|
|
self.__alive = 0
|
|
|
|
def set_delay(self, delay):
|
|
self.__delay = delay
|
|
|
|
def set_delay_before(self, bool_do):
|
|
self.__delay_before = bool(bool_do)
|
|
|
|
def set_accuracy(self, bool_do):
|
|
self.__accurate = bool(bool_do)
|
|
|
|
def run(self):
|
|
self.__alive = 1
|
|
while self.__alive:
|
|
|
|
if self.__delay_before:
|
|
do_break = self.__do_delay()
|
|
if do_break:
|
|
break
|
|
|
|
if self.__f == None:
|
|
break
|
|
self.__f(*self.__args, **self.__kwargs)
|
|
|
|
if not self.__delay_before:
|
|
do_break = self.__do_delay()
|
|
if do_break:
|
|
break
|
|
|
|
|
|
def __do_delay(self):
|
|
|
|
if not self.__accurate:
|
|
|
|
if float == None:
|
|
return True
|
|
mydelay = float(self.__delay)
|
|
t_frac = 0.3
|
|
while mydelay > 0.0:
|
|
if not self.__alive:
|
|
return True
|
|
if time == None:
|
|
return True # shut down?
|
|
time.sleep(t_frac)
|
|
mydelay -= t_frac
|
|
|
|
else:
|
|
|
|
if time == None:
|
|
return True # shut down?
|
|
time.sleep(self.__delay)
|
|
|
|
return False
|
|
|
|
def kill(self):
|
|
self.__alive = 0
|
|
|
|
class ParallelTask(threading.Thread):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
threading.Thread.__init__(self)
|
|
self.__function = args[0]
|
|
self.__args = args[1:][:]
|
|
self.__kwargs = kwargs.copy()
|
|
self.__rc = None
|
|
|
|
def run(self):
|
|
self.__rc = self.__function(*self.__args, **self.__kwargs)
|
|
|
|
def get_function(self):
|
|
return self.__function
|
|
|
|
def get_rc(self):
|
|
return self.__rc
|
|
|
|
class EmailSender:
|
|
|
|
def __init__(self):
|
|
import smtplib
|
|
self.smtplib = smtplib
|
|
from email.mime.audio import MIMEAudio
|
|
from email.mime.image import MIMEImage
|
|
from email.mime.text import MIMEText
|
|
from email.mime.base import MIMEBase
|
|
from email.mime.multipart import MIMEMultipart
|
|
from email import encoders
|
|
from email.message import Message
|
|
import mimetypes
|
|
self.smtpuser = None
|
|
self.smtppassword = None
|
|
self.smtphost = 'localhost'
|
|
self.smtpport = 25
|
|
self.text = MIMEText
|
|
self.mimefile = MIMEBase
|
|
self.audio = MIMEAudio
|
|
self.image = MIMEImage
|
|
self.multipart = MIMEMultipart
|
|
self.default_sender = self.smtp_send
|
|
self.mimetypes = mimetypes
|
|
self.encoders = encoders
|
|
self.message = Message
|
|
|
|
def smtp_send(self, sender, destinations, message):
|
|
s_srv = self.smtplib.SMTP(self.smtphost, self.smtpport)
|
|
if self.smtpuser and self.smtppassword:
|
|
s_srv.login(self.smtpuser, self.smtppassword)
|
|
s_srv.sendmail(sender, destinations, message)
|
|
s_srv.quit()
|
|
|
|
def send_text_email(self, sender_email, destination_emails, subject,
|
|
content):
|
|
|
|
# Create a text/plain message
|
|
if isinstance(content, unicode):
|
|
content = content.encode('utf-8')
|
|
if isinstance(subject, unicode):
|
|
subject = subject.encode('utf-8')
|
|
|
|
msg = self.text(content)
|
|
msg['Subject'] = subject
|
|
msg['From'] = sender_email
|
|
msg['To'] = ', '.join(destination_emails)
|
|
return self.default_sender(sender_email, destination_emails,
|
|
msg.as_string())
|
|
|
|
def send_mime_email(self, sender_email, destination_emails, subject,
|
|
content, files):
|
|
|
|
outer = self.multipart()
|
|
outer['Subject'] = subject
|
|
outer['From'] = sender_email
|
|
outer['To'] = ', '.join(destination_emails)
|
|
outer.preamble = subject
|
|
|
|
mymsg = self.text(content)
|
|
outer.attach(mymsg)
|
|
|
|
# attach files
|
|
for myfile in files:
|
|
if not (os.path.isfile(myfile) and os.access(myfile, os.R_OK)):
|
|
continue
|
|
|
|
ctype, encoding = self.mimetypes.guess_type(myfile)
|
|
if ctype is None or encoding is not None:
|
|
ctype = 'application/octet-stream'
|
|
maintype, subtype = ctype.split('/', 1)
|
|
|
|
if maintype == 'image':
|
|
img_f = open(myfile, 'rb')
|
|
msg = self.image(img_f.read(), _subtype = subtype)
|
|
img_f.close()
|
|
elif maintype == 'audio':
|
|
audio_f = open(myfile, 'rb')
|
|
msg = self.audio(audio_f.read(), _subtype = subtype)
|
|
audio_f.close()
|
|
else:
|
|
gen_f = open(myfile, 'rb')
|
|
msg = self.mimefile(maintype, subtype)
|
|
msg.set_payload(gen_f.read())
|
|
gen_f.close()
|
|
self.encoders.encode_base64(msg)
|
|
|
|
msg.add_header('Content-Disposition', 'attachment',
|
|
filename = os.path.basename(myfile))
|
|
outer.attach(msg)
|
|
|
|
composed = outer.as_string()
|
|
return self.default_sender(sender_email, destination_emails, composed)
|
|
|
|
class EntropyGeoIP:
|
|
|
|
"""
|
|
Entropy geo-tagging interface containing useful
|
|
methods to ease metadata management and transfor-
|
|
mation.
|
|
It's a wrapper over GeoIP at the moment
|
|
dev-python/geoip-python required
|
|
"""
|
|
|
|
def __init__(self, geoip_dbfile):
|
|
|
|
"""
|
|
@param1: valid GeoIP (Maxmind) database file (.dat)
|
|
"""
|
|
|
|
import GeoIP
|
|
self.__geoip = GeoIP
|
|
# http://www.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
|
|
if not (os.path.isfile(geoip_dbfile) and \
|
|
os.access(geoip_dbfile, os.R_OK)):
|
|
raise AttributeError(
|
|
"expecting a valid filepath for geoip_dbfile, got: %s" % (
|
|
repr(geoip_dbfile),
|
|
)
|
|
)
|
|
self.__geoip_dbfile = geoip_dbfile
|
|
|
|
def __get_geo_ip_generic(self):
|
|
return self.__geoip.new(self.__geoip.GEOIP_MEMORY_CACHE)
|
|
|
|
def __get_geo_ip_open(self):
|
|
return self.__geoip.open(self.__geoip_dbfile,
|
|
self.__geoip.GEOIP_STANDARD)
|
|
|
|
def get_geoip_country_name_from_ip(self, ip_address):
|
|
"""
|
|
@return: string or None
|
|
@param1: ip address string
|
|
"""
|
|
gi_a = self.__get_geo_ip_generic()
|
|
return gi_a.country_name_by_addr(ip_address)
|
|
|
|
def get_geoip_country_code_from_ip(self, ip_address):
|
|
"""
|
|
@return: string or None
|
|
@param1: ip address string
|
|
"""
|
|
gi_a = self.__get_geo_ip_generic()
|
|
return gi_a.country_code_by_addr(ip_address)
|
|
|
|
def get_geoip_record_from_ip(self, ip_address):
|
|
"""
|
|
@return: dict() or None
|
|
@param1: ip address string
|
|
dict data:
|
|
{
|
|
'city': 'Treviso',
|
|
'region': '20',
|
|
'area_code': 0,
|
|
'longitude': 12.244999885559082,
|
|
'country_code3': 'ITA',
|
|
'latitude': 45.666698455810547,
|
|
'postal_code': None,
|
|
'dma_code': 0,
|
|
'country_code': 'IT',
|
|
'country_name': 'Italy'
|
|
}
|
|
"""
|
|
go_a = self.__get_geo_ip_open()
|
|
return go_a.record_by_addr(ip_address)
|
|
|
|
def get_geoip_record_from_hostname(self, hostname):
|
|
"""
|
|
@return: dict() or None
|
|
@param1: hostname
|
|
"""
|
|
go_a = self.__get_geo_ip_open()
|
|
return go_a.record_by_name(hostname)
|
|
|
|
|
|
class rssFeed:
|
|
|
|
# this is a relative import to avoid circular deps
|
|
import tools as entropyTools
|
|
def __init__(self, filename, title, description, maxentries = 100):
|
|
|
|
self.__system_settings = SystemSettings()
|
|
self.__feed_title = title
|
|
self.__feed_title = self.__feed_title.strip()
|
|
self.__feed_description = description
|
|
self.__feed_language = "en-EN"
|
|
self.__feed_editor = etpConst['rss-managing-editor']
|
|
self.__feed_copyright = "%s - (C) %s" % (
|
|
self.__system_settings['system']['name'],
|
|
self.entropyTools.get_year(),
|
|
)
|
|
|
|
self.__file = filename
|
|
self.__items = {}
|
|
self.__itemscounter = 0
|
|
self.__maxentries = maxentries
|
|
from xml.dom import minidom
|
|
self.minidom = minidom
|
|
|
|
# sanity check
|
|
broken = False
|
|
if os.path.isfile(self.__file):
|
|
try:
|
|
self.xmldoc = self.minidom.parse(self.__file)
|
|
except:
|
|
broken = True
|
|
|
|
if not os.path.isfile(self.__file) or broken:
|
|
self.__title = self.__feed_title
|
|
self.__description = self.__feed_description
|
|
self.__language = self.__feed_language
|
|
self.__cright = self.__feed_copyright
|
|
self.__editor = self.__feed_editor
|
|
self.__link = etpConst['rss-website-url']
|
|
rss_f = open(self.__file, "w")
|
|
rss_f.write('')
|
|
rss_f.flush()
|
|
rss_f.close()
|
|
else:
|
|
self.__rssdoc = self.xmldoc.getElementsByTagName("rss")[0]
|
|
self.__channel = self.__rssdoc.getElementsByTagName("channel")[0]
|
|
title_obj = self.__channel.getElementsByTagName("title")[0]
|
|
self.__title = title_obj.firstChild.data.strip()
|
|
link_obj = self.__channel.getElementsByTagName("link")[0]
|
|
self.__link = link_obj.firstChild.data.strip()
|
|
desc_obj = self.__channel.getElementsByTagName("description")[0]
|
|
description = desc_obj.firstChild
|
|
if hasattr(description, "data"):
|
|
self.__description = description.data.strip()
|
|
else:
|
|
self.__description = ''
|
|
try:
|
|
lang_obj = self.__channel.getElementsByTagName("language")[0]
|
|
self.__language = lang_obj.firstChild.data.strip()
|
|
except IndexError:
|
|
self.__language = 'en'
|
|
try:
|
|
cright_obj = self.__channel.getElementsByTagName("copyright")[0]
|
|
self.__cright = cright_obj.firstChild.data.strip()
|
|
except IndexError:
|
|
self.__cright = ''
|
|
try:
|
|
e_obj = self.__channel.getElementsByTagName("managingEditor")[0]
|
|
self.__editor = e_obj.firstChild.data.strip()
|
|
except IndexError:
|
|
self.__editor = ''
|
|
entries = self.__channel.getElementsByTagName("item")
|
|
self.__itemscounter = len(entries)
|
|
if self.__itemscounter > self.__maxentries:
|
|
self.__itemscounter = self.__maxentries
|
|
mycounter = self.__itemscounter
|
|
for item in entries:
|
|
if mycounter == 0: # max entries reached
|
|
break
|
|
mycounter -= 1
|
|
self.__items[mycounter] = {}
|
|
title_obj = item.getElementsByTagName("title")[0]
|
|
self.__items[mycounter]['title'] = \
|
|
title_obj.firstChild.data.strip()
|
|
desc_obj = item.getElementsByTagName("description")[0]
|
|
description = desc_obj.firstChild
|
|
if description:
|
|
self.__items[mycounter]['description'] = \
|
|
description.data.strip()
|
|
else:
|
|
self.__items[mycounter]['description'] = ""
|
|
|
|
link = item.getElementsByTagName("link")[0].firstChild
|
|
if link:
|
|
self.__items[mycounter]['link'] = link.data.strip()
|
|
else:
|
|
self.__items[mycounter]['link'] = ""
|
|
|
|
guid_obj = item.getElementsByTagName("guid")[0]
|
|
self.__items[mycounter]['guid'] = \
|
|
guid_obj.firstChild.data.strip()
|
|
pub_date_obj = item.getElementsByTagName("pubDate")[0]
|
|
self.__items[mycounter]['pubDate'] = \
|
|
pub_date_obj.firstChild.data.strip()
|
|
dcs = item.getElementsByTagName("dc:creator")
|
|
if dcs:
|
|
self.__items[mycounter]['dc:creator'] = \
|
|
dcs[0].firstChild.data.strip()
|
|
|
|
def addItem(self, title, link = '', description = '', pubDate = ''):
|
|
self.__itemscounter += 1
|
|
self.__items[self.__itemscounter] = {}
|
|
self.__items[self.__itemscounter]['title'] = title
|
|
if pubDate:
|
|
self.__items[self.__itemscounter]['pubDate'] = pubDate
|
|
else:
|
|
self.__items[self.__itemscounter]['pubDate'] = \
|
|
time.strftime("%a, %d %b %Y %X +0000")
|
|
self.__items[self.__itemscounter]['description'] = description
|
|
self.__items[self.__itemscounter]['link'] = link
|
|
if link:
|
|
self.__items[self.__itemscounter]['guid'] = link
|
|
else:
|
|
myguid = self.__system_settings['system']['name'].lower()
|
|
myguid = myguid.replace(" ", "")
|
|
self.__items[self.__itemscounter]['guid'] = myguid+"~" + \
|
|
description + str(self.__itemscounter)
|
|
return self.__itemscounter
|
|
|
|
def removeEntry(self, key):
|
|
if key in self.__items:
|
|
del self.__items[key]
|
|
self.__itemscounter -= 1
|
|
return self.__itemscounter
|
|
|
|
def getEntries(self):
|
|
return self.__items, self.__itemscounter
|
|
|
|
def writeChanges(self, reverse = True):
|
|
|
|
# filter entries to fit in maxentries
|
|
if self.__itemscounter > self.__maxentries:
|
|
tobefiltered = self.__itemscounter - self.__maxentries
|
|
for index in range(tobefiltered):
|
|
try:
|
|
del self.__items[index]
|
|
except KeyError:
|
|
pass
|
|
|
|
doc = self.minidom.Document()
|
|
|
|
rss = doc.createElement("rss")
|
|
rss.setAttribute("version", "2.0")
|
|
rss.setAttribute("xmlns:atom", "http://www.w3.org/2005/Atom")
|
|
|
|
channel = doc.createElement("channel")
|
|
|
|
# title
|
|
title = doc.createElement("title")
|
|
title_text = doc.createTextNode(unicode(self.__title))
|
|
title.appendChild(title_text)
|
|
channel.appendChild(title)
|
|
# link
|
|
link = doc.createElement("link")
|
|
link_text = doc.createTextNode(unicode(self.__link))
|
|
link.appendChild(link_text)
|
|
channel.appendChild(link)
|
|
# description
|
|
description = doc.createElement("description")
|
|
desc_text = doc.createTextNode(unicode(self.__description))
|
|
description.appendChild(desc_text)
|
|
channel.appendChild(description)
|
|
# language
|
|
language = doc.createElement("language")
|
|
lang_text = doc.createTextNode(unicode(self.__language))
|
|
language.appendChild(lang_text)
|
|
channel.appendChild(language)
|
|
# copyright
|
|
cright = doc.createElement("copyright")
|
|
cr_text = doc.createTextNode(unicode(self.__cright))
|
|
cright.appendChild(cr_text)
|
|
channel.appendChild(cright)
|
|
# managingEditor
|
|
managing_editor = doc.createElement("managingEditor")
|
|
ed_text = doc.createTextNode(unicode(self.__editor))
|
|
managing_editor.appendChild(ed_text)
|
|
channel.appendChild(managing_editor)
|
|
|
|
keys = self.__items.keys()
|
|
if reverse:
|
|
keys.reverse()
|
|
for key in keys:
|
|
|
|
# sanity check, you never know
|
|
if not self.__items.has_key(key):
|
|
self.removeEntry(key)
|
|
continue
|
|
k_error = False
|
|
for item in ('title', 'link', 'guid', 'description', 'pubDate',):
|
|
if not self.__items[key].has_key(item):
|
|
k_error = True
|
|
break
|
|
if k_error:
|
|
self.removeEntry(key)
|
|
continue
|
|
|
|
# item
|
|
item = doc.createElement("item")
|
|
# title
|
|
item_title = doc.createElement("title")
|
|
item_title_text = doc.createTextNode(
|
|
unicode(self.__items[key]['title']))
|
|
item_title.appendChild(item_title_text)
|
|
item.appendChild(item_title)
|
|
# link
|
|
item_link = doc.createElement("link")
|
|
item_link_text = doc.createTextNode(
|
|
unicode(self.__items[key]['link']))
|
|
item_link.appendChild(item_link_text)
|
|
item.appendChild(item_link)
|
|
# guid
|
|
item_guid = doc.createElement("guid")
|
|
item_guid.setAttribute("isPermaLink", "true")
|
|
item_guid_text = doc.createTextNode(
|
|
unicode(self.__items[key]['guid']))
|
|
item_guid.appendChild(item_guid_text)
|
|
item.appendChild(item_guid)
|
|
# description
|
|
item_desc = doc.createElement("description")
|
|
item_desc_text = doc.createTextNode(
|
|
unicode(self.__items[key]['description']))
|
|
item_desc.appendChild(item_desc_text)
|
|
item.appendChild(item_desc)
|
|
# pubdate
|
|
item_date = doc.createElement("pubDate")
|
|
item_date_text = doc.createTextNode(
|
|
unicode(self.__items[key]['pubDate']))
|
|
item_date.appendChild(item_date_text)
|
|
item.appendChild(item_date)
|
|
|
|
# add item to channel
|
|
channel.appendChild(item)
|
|
|
|
# add channel to rss
|
|
rss.appendChild(channel)
|
|
doc.appendChild(rss)
|
|
rss_f = open(self.__file, "w")
|
|
rss_f.writelines(doc.toprettyxml(indent=" ").encode('utf-8'))
|
|
rss_f.flush()
|
|
rss_f.close()
|
|
|
|
class LogFile:
|
|
|
|
def __init__(self, level = 0, filename = None, header = "[LOG]"):
|
|
self.handler = self.default_handler
|
|
self.level = level
|
|
self.header = header
|
|
self.__logfile = None
|
|
self.open(filename)
|
|
self.__filename = filename
|
|
|
|
def __del__(self):
|
|
self.close()
|
|
|
|
def close(self):
|
|
try:
|
|
self.__logfile.close()
|
|
except (IOError, OSError,):
|
|
pass
|
|
|
|
def get_fpath(self):
|
|
return self.__filename
|
|
|
|
def flush(self):
|
|
self.__logfile.flush()
|
|
|
|
def fileno(self):
|
|
return self.__get_file()
|
|
|
|
def isatty(self):
|
|
return False
|
|
|
|
def read(self, *args):
|
|
return ''
|
|
|
|
def readline(self):
|
|
return ''
|
|
|
|
def readlines(self):
|
|
return []
|
|
|
|
def seek(self, offset):
|
|
return self.__logfile.seek(offset)
|
|
|
|
def tell(self):
|
|
return self.__logfile.tell()
|
|
|
|
def truncate(self):
|
|
return self.__logfile.truncate()
|
|
|
|
def open(self, file_path = None):
|
|
|
|
if isinstance(file_path, basestring):
|
|
if os.access(file_path, os.W_OK) and os.path.isfile(file_path):
|
|
self.__logfile = open(file_path, "aw")
|
|
else:
|
|
self.__logfile = open("/dev/null", "aw")
|
|
elif hasattr(file_path, 'write'):
|
|
self.__logfile = file_path
|
|
else:
|
|
self.__logfile = sys.stderr
|
|
|
|
def __get_file(self):
|
|
return self.__logfile.fileno()
|
|
|
|
def __call__(self, format, *args):
|
|
self.handler (format % args)
|
|
|
|
def default_handler (self, mystr):
|
|
try:
|
|
self.__logfile.write ("* %s\n" % (mystr))
|
|
except UnicodeEncodeError:
|
|
self.__logfile.write ("* %s\n" % (mystr.encode('utf-8'),))
|
|
self.__logfile.flush()
|
|
|
|
def set_loglevel(self, level):
|
|
self.level = level
|
|
|
|
def log(self, messagetype, level, message):
|
|
if self.level >= level and not etpUi['nolog']:
|
|
self.handler("%s %s %s %s" % (self.__get_header(),
|
|
messagetype, self.header, message,))
|
|
|
|
def write(self, line):
|
|
self.handler(line)
|
|
|
|
def writelines(self, lst):
|
|
for line in lst:
|
|
self.write(line)
|
|
|
|
def __get_header(self):
|
|
return time.strftime('[%H:%M:%S %d/%m/%Y %Z]')
|
|
|
|
class Callable:
|
|
def __init__(self, anycallable):
|
|
self.__call__ = anycallable
|
|
|
|
class MultipartPostHandler(urllib2.BaseHandler):
|
|
|
|
handler_order = urllib2.HTTPHandler.handler_order - 10 # needs to run first
|
|
|
|
def __init__(self):
|
|
pass
|
|
|
|
def http_request(self, request):
|
|
|
|
import urllib
|
|
doseq = 1
|
|
|
|
data = request.get_data()
|
|
if data is not None and type(data) != str:
|
|
v_files = []
|
|
v_vars = []
|
|
try:
|
|
for (key, value) in data.items():
|
|
if type(value) == file:
|
|
v_files.append((key, value))
|
|
else:
|
|
v_vars.append((key, value))
|
|
except TypeError:
|
|
raise TypeError, "not a valid non-string sequence" \
|
|
" or mapping object"
|
|
|
|
if len(v_files) == 0:
|
|
data = urllib.urlencode(v_vars, doseq)
|
|
else:
|
|
boundary, data = self.multipart_encode(v_vars, v_files)
|
|
contenttype = 'multipart/form-data; boundary=%s' % boundary
|
|
request.add_unredirected_header('Content-Type', contenttype)
|
|
|
|
request.add_data(data)
|
|
return request
|
|
|
|
def multipart_encode(self, myvars, files, boundary = None, buf = None):
|
|
|
|
from cStringIO import StringIO
|
|
import mimetools, mimetypes
|
|
#import stat
|
|
|
|
if boundary is None:
|
|
boundary = mimetools.choose_boundary()
|
|
if buf is None:
|
|
buf = StringIO()
|
|
for(key, value) in myvars:
|
|
buf.write('--%s\r\n' % boundary)
|
|
buf.write('Content-Disposition: form-data; name="%s"' % key)
|
|
buf.write('\r\n\r\n' + value + '\r\n')
|
|
for(key, fdesc) in files:
|
|
#file_size = os.fstat(fdesc.fileno())[stat.ST_SIZE]
|
|
filename = fdesc.name.split('/')[-1]
|
|
contenttype = mimetypes.guess_type(filename)[0] or \
|
|
'application/octet-stream'
|
|
buf.write('--%s\r\n' % boundary)
|
|
buf.write('Content-Disposition: form-data; name="%s"; ' \
|
|
'filename="%s"\r\n' % (key, filename))
|
|
buf.write('Content-Type: %s\r\n' % contenttype)
|
|
# buffer += 'Content-Length: %s\r\n' % file_size
|
|
fdesc.seek(0)
|
|
buf.write('\r\n' + fdesc.read() + '\r\n')
|
|
buf.write('--' + boundary + '--\r\n\r\n')
|
|
buf = buf.getvalue()
|
|
return boundary, buf
|
|
|
|
multipart_encode = Callable(multipart_encode)
|
|
|
|
https_request = http_request
|
|
|