Initial commit
Benjamin Renard

Benjamin Renard commited on 2011-11-24 16:55:40
Showing 10 changed files, with 760 additions and 0 deletions.

... ...
@@ -0,0 +1 @@
1
+*.pyc
... ...
@@ -0,0 +1,95 @@
1
+##### Mantis SMTP Gateway #####
2
+
3
+Mantis SMTP Gateway is an email gateway for Mantis Bug Tracker.
4
+
5
+Run as a SMTP server, Mantis SMTP try to add email informations to Mantis Bug Tracker through its SOAP API.
6
+
7
+Process :
8
+---------
9
+
10
+Parsing subject to detect issue id : if present, the email will be processed as a note. Also, create a new issue in project corresponding to email recipient.
11
+
12
+Features :
13
+----------
14
+
15
+- detect issue id from subject
16
+- add note to existing issue
17
+- create new issue in project
18
+- multiple project support with different email recipient
19
+- add email attachment as issue attachment
20
+- email warning sender on error
21
+- daemon mode (init script provide)
22
+
23
+#### Installation ####
24
+
25
+### Python Requirements ###
26
+
27
+# System lib :
28
+- sys
29
+- os
30
+- signal
31
+
32
+# Mail lib :
33
+- email
34
+- smtplib
35
+- smtpd
36
+
37
+# SOAP lib :
38
+- suds
39
+
40
+# Daemon lib :
41
+- logging
42
+- simplejson : to load config file
43
+- asyncore
44
+
45
+# Utils lib :
46
+- re
47
+- string
48
+- optparse.OptionParser : to parse command line parameters
49
+
50
+### Redhat/Debian Packages Requirements ###
51
+
52
+- python-simplejson
53
+- python-suds
54
+
55
+### Scripted installation ###
56
+
57
+An installation script is provided :
58
+
59
+  ~/mantisbt-smtp-gateway/$ ./install.sh install
60
+
61
+### Manual installation ###
62
+
63
+- Install requirements
64
+- Copy all file in src directory in root :
65
+
66
+    ~/mantisbt-smtp-gateway/$ cd src/
67
+    ~/mantisbt-smtp-gateway/src/$ cp -r * /
68
+
69
+#### Configuration ####
70
+
71
+Mantis SMTP Gateway use an single JSON configuration file :
72
+
73
+  /etc/mantis-smtp.conf
74
+
75
+Example :
76
+---------
77
+
78
+{
79
+"mail_from": "postmaster-mantis@example.net",
80
+"ws_url": "http://mantis.example.net/api/soap/mantisconnect.php?wsdl",
81
+"ws_user": "MAIL",
82
+"ws_pwd": "password",
83
+"ws_default_category": "other",
84
+"projects": {
85
+	"mantis-project1@example.net": {
86
+		"project_name": "Project 1"
87
+	},
88
+	"mantis-dev@example.net": {
89
+		"project_name": "Development",
90
+		"category": "dev"
91
+	}
92
+}
93
+}
94
+
95
+
... ...
@@ -0,0 +1,74 @@
1
+#!/bin/bash
2
+
3
+cd $( dirname $0 )
4
+dir=$( pwd )
5
+
6
+files="
7
+/etc/mantis-smtp.conf
8
+/etc/init.d/mantis-smtp
9
+/usr/bin/mantis-smtp
10
+/usr/share/mantis-smtp
11
+"
12
+
13
+function install_file() {
14
+	from=$1
15
+	dst=$2
16
+	if [ -e "$dst" ]
17
+	then
18
+		echo -e "\t- backuping $file in ${file}.old"
19
+		mv $dst $dst.old
20
+	fi
21
+	echo -e "\t- $file"
22
+	ln -s "$from" "$dst"
23
+}
24
+
25
+
26
+case "$1" in
27
+	install-req)
28
+		echo "Install requirements :"
29
+
30
+		if [ -f /usr/bin/apt-get ]
31
+		then
32
+			apt-get install python-suds python-simplejson
33
+		elif [ -x /usr/bin/yum ]
34
+		then
35
+			yum install python-suds python-simplejson
36
+		else
37
+			echo "Can't package manager."
38
+			exit 1
39
+		fi
40
+
41
+	;;
42
+	install)
43
+		$0 install-req 
44
+			
45
+		echo "Files installation :"
46
+	
47
+		for file in $files
48
+		do
49
+			install_file ${dir}/src${file} ${file}
50
+		done
51
+		if [ -f /etc/redhat-release ]
52
+		then
53
+			install_file ${dir}/src/etc/default/mantis-smtp /etc/sysconfig/mantis-smtp
54
+		elif [ -f /etc/debian_version ]
55
+		then
56
+			install_file ${dir}/src/etc/default/mantis-smtp /etc/default/mantis-smtp
57
+		fi
58
+
59
+		echo done.
60
+	;;
61
+	uninstall)
62
+		echo "Uninstalling files :"
63
+		for file in $files /etc/sysconfig/mantis-smtp /etc/default/mantis-smtp
64
+		do
65
+			[ ! -e $file ] && continue
66
+			echo -e "\t- Uninstall file $file :"
67
+			rm -rf "$file"
68
+		done
69
+
70
+		echo done.
71
+	;;
72
+	*)
73
+		echo "Usage : $0 {install|install-req|uninstall}"
74
+esac
... ...
@@ -0,0 +1,17 @@
1
+# Mantis SMTP Server configuration file
2
+#
3
+
4
+# PID file
5
+#pidfile=/var/run/mantis-smtp.pid
6
+
7
+# Config file
8
+configfile=/etc/mantis-smtp.conf
9
+
10
+# Log file
11
+#logfile=/var/log/mantis-smtp.log
12
+
13
+# Command line mantis-smtp options
14
+OPTIONS="-c $configfile --daemon --pid ${pidfile} -l $logfile -H 127.0.0.1 -p 10029"
15
+
16
+# Stop timeout
17
+#STOP_TIMEOUT=10
... ...
@@ -0,0 +1,110 @@
1
+#!/bin/bash
2
+### BEGIN INIT INFO
3
+# Provides:          mantis-smtp
4
+# Required-Start:    $local_fs $network
5
+# Required-Stop:     $local_fs $network
6
+# Default-Start:     2 3 4 5
7
+# Default-Stop:      0 1 6
8
+# Short-Description: Start/stop Mantis SMTP gateway server
9
+# Description: Mantis SMTP Server is a SMTP Gateway for Mantis
10
+#              bug tracker
11
+### END INIT INFO
12
+# mantis-smtp        Startup script for the Mantis SMTP Server
13
+#
14
+# chkconfig: 2345 80 30
15
+# description: Mantis SMTP Server is a SMTP Gateway for Mantis 
16
+#              bug tracker
17
+# processname: mantis-smtp
18
+# config: /etc/sysconfig/mantis-smtp
19
+# config: /etc/mantis-smtp.conf
20
+# pidfile: /var/run/mantis-smtp.pid
21
+
22
+# Source function library.
23
+if [ -f /etc/redhat-release ]
24
+then
25
+	. /etc/rc.d/init.d/functions
26
+elif [ -f /etc/debian_version ]
27
+then
28
+	. /lib/lsb/init-functions
29
+fi
30
+
31
+prog="Mantis SMTP Server"
32
+pidfile=/var/run/mantis-smtp.pid
33
+mantis_smtp_bin=/usr/bin/mantis-smtp
34
+configfile=/etc/mantis-smtp.conf
35
+logfile=/var/log/mantis-smtp.log
36
+
37
+OPTIONS="-c $configfile --daemon --pid ${pidfile} -l $logfile -H 127.0.0.1 -p 10029"
38
+STOP_TIMEOUT=10
39
+
40
+if [ -f /etc/redhat-release -a -f /etc/sysconfig/mantis-smtp ]
41
+then
42
+        . /etc/sysconfig/mantis-smtp
43
+elif [ -f /etc/debian_version ]
44
+then
45
+	. /etc/default/mantis-smtp
46
+fi
47
+
48
+start() {
49
+	if [ -f /etc/redhat-release ]
50
+	then
51
+		echo -n $"Starting $prog: "
52
+	        daemon --pidfile=${pidfile} $mantis_smtp_bin $OPTIONS
53
+		echo
54
+	elif [ -f /etc/debian_version ]
55
+	then
56
+		log_daemon_msg "Starting $prog" $( basename $mantis_smtp_bin )
57
+		start-stop-daemon --start --quiet --pidfile ${pidfile} --exec $mantis_smtp_bin -- $OPTIONS
58
+		log_end_msg $?
59
+	fi
60
+}
61
+
62
+stop() {
63
+	if [ -f /etc/redhat-release ]
64
+	then
65
+	        echo -n $"Stopping $prog: "
66
+		killproc -p ${pidfile} -d ${STOP_TIMEOUT} $mantis_smtp_bin
67
+	        [ $? = 0 ] && rm -f ${pidfile}
68
+		echo
69
+	elif [ -f /etc/debian_version ]
70
+	then
71
+		log_daemon_msg "Stopping $prog" $( basename $mantis_smtp_bin )
72
+		start-stop-daemon --stop --quiet --pidfile ${pidfile}
73
+		log_end_msg $?
74
+	fi
75
+}
76
+
77
+show_status() {
78
+	if [ -f /etc/redhat-release ]
79
+	then
80
+		status -p ${pidfile} $mantis_smtp_bin
81
+	elif [ -f /etc/debian_version ]
82
+	then
83
+		status_of_proc -p ${pidfile} $( basename $mantis_smtp_bin ) "$prog"
84
+	fi
85
+}
86
+
87
+case "$1" in
88
+  start)
89
+        start
90
+        ;;
91
+  stop)
92
+        stop
93
+        ;;
94
+  status)
95
+	show_status
96
+        ;;
97
+  restart|reload|force-reload)
98
+        stop
99
+        start
100
+        ;;
101
+  condrestart|cond-restart)
102
+        if [ -f ${pidfile} ] ; then
103
+                stop
104
+                start
105
+        fi
106
+        ;;
107
+  *)
108
+        echo $"Usage: $prog {start|stop|restart|force-reload|condrestart|reload|status}"
109
+        exit 1
110
+esac
... ...
@@ -0,0 +1,16 @@
1
+{
2
+"mail_from": "postmaster-mantis@example.net",
3
+"ws_url": "http://mantis.example.net/api/soap/mantisconnect.php?wsdl",
4
+"ws_user": "MAIL",
5
+"ws_pwd": "password",
6
+"ws_default_category": "other",
7
+"projects": {
8
+	"mantis-project1@example.net": {
9
+		"project_name": "Project 1"
10
+	},
11
+	"mantis-dev@example.net": {
12
+		"project_name": "Development",
13
+		"category": "dev"
14
+	}
15
+}
16
+}
... ...
@@ -0,0 +1,128 @@
1
+#!/usr/bin/python
2
+
3
+import sys
4
+
5
+sys.path.append('/usr/local/share/mantis-smtp')
6
+sys.path.append('/usr/share/mantis-smtp')
7
+
8
+import MantisSMTPServer
9
+import logging
10
+from optparse import OptionParser
11
+import simplejson as json
12
+
13
+parser = OptionParser()
14
+
15
+parser.add_option('-v',
16
+                  '--verbose',
17
+                  action="store_true",
18
+                  dest="verbose",
19
+                  help="Enable verbose mode")
20
+
21
+parser.add_option('-d',
22
+                  '--daemon',
23
+                  action="store_true",
24
+                  dest="daemon",
25
+                  help="Start in daemon mode")
26
+
27
+parser.add_option('--pid',
28
+                  action="store",
29
+                  type="string",
30
+                  dest="pidfile",
31
+                  help="The logfile path",
32
+                  default=None)
33
+
34
+parser.add_option('-c',
35
+                  '--configfile',
36
+                  action="store",
37
+                  type="string",
38
+                  dest="configfile",
39
+                  help="The logfile path",
40
+                  default=None)
41
+
42
+parser.add_option('-l',
43
+                  '--logfile',
44
+                  action="store",
45
+                  type="string",
46
+                  dest="logfile",
47
+                  help="The logfile path",
48
+                  default=None)
49
+
50
+parser.add_option('-H',
51
+                  '--address',
52
+                  action="store",
53
+                  type="string",
54
+                  dest="bind_address",
55
+                  help="The bind address",
56
+                  default="127.0.0.1")
57
+
58
+parser.add_option('-p',
59
+                  '--port',
60
+                  action="store",
61
+                  type="int",
62
+                  dest="port",
63
+                  help="The bind port",
64
+                  default=1025)
65
+
66
+(options, args) = parser.parse_args()
67
+
68
+
69
+logformat = '%(asctime)s - MantisMailServer - %(levelname)s - %(message)s'
70
+if options.verbose:
71
+	loglevel = logging.DEBUG
72
+else:
73
+	loglevel = logging.INFO
74
+
75
+if options.logfile:
76
+	logging.basicConfig(filename=options.logfile,level=loglevel,format=logformat)
77
+else:
78
+	logging.basicConfig(level=loglevel,format=logformat)
79
+
80
+server = MantisSMTPServer.MantisSMTPServer((options.bind_address, options.port), None)
81
+
82
+
83
+if options.daemon and options.pidfile is None:
84
+	logging.error("Can't daemonize without pid file parameter (--pid)")
85
+	sys.exit(3)
86
+
87
+if options.configfile:
88
+	try:
89
+		fd=open(options.configfile,'rb')
90
+		config_text=fd.read()
91
+		fd.close()
92
+	except:
93
+		logging.error('Error reading config file %s.' % options.configfile)
94
+		sys.exit(1)
95
+
96
+	try:
97
+		config=json.loads(config_text)
98
+	except:
99
+		logging.error('Error parsing config file %s.' % options.configfile)
100
+		sys.exit(2)
101
+
102
+	try:
103
+		for param in ['mail_from','ws_url','ws_user','ws_pwd','ws_default_category']:
104
+			if param in config:
105
+				server.set_option(param,config[param])
106
+
107
+		if 'projects' in config:
108
+			for project in config['projects']:
109
+				if 'project_name' not in config['projects'][project]:
110
+					logging.warning('Project %s in config file does not have "project_name" parameter. Pass.' % project)
111
+					continue
112
+				if 'category' in config['projects'][project]:
113
+					server.add_project(project,config['projects'][project]['project_name'],category=config['projects'][project]['category'])
114
+				else:
115
+					 server.add_project(project,config['projects'][project]['project_name'])
116
+	except:
117
+		logging.error('Error loading config parameters from %s' % options.configfile)
118
+		sys.exit(3)
119
+else:
120
+	logging.warning('No config file supply. Running with default configuration...')
121
+
122
+try:
123
+	if options.daemon:
124
+		server.startDaemon(options.pidfile)
125
+	else:
126
+		server.start()		
127
+except KeyboardInterrupt:
128
+	server.stop()
... ...
@@ -0,0 +1,70 @@
1
+#!/usr/bin/python
2
+
3
+import email
4
+import re
5
+import string
6
+from email.MIMEText import MIMEText
7
+import smtplib
8
+import logging
9
+
10
+
11
+class MantisMail(object):
12
+
13
+	def __init__(self,mailfrom,mailto,data):
14
+		self.mailfrom = mailfrom
15
+		self.mailto = mailto
16
+		self.msg = email.message_from_string(data)
17
+
18
+	def get_issue_id_from_subject(self):
19
+		res=re.search('\[[^\]]* ([0-9]*)\]',self.subject())
20
+		if res:
21
+			issue_id=res.group(1)
22
+			return string.atoi(issue_id)
23
+		return None
24
+
25
+	def subject(self):
26
+		return self.msg['Subject']	
27
+	
28
+	def get_text(self):
29
+		content='From : %s' % self.msg['From']
30
+		for part in self.msg.walk():
31
+			if part.get_content_maintype() == 'text':
32
+				content='%s\n\n---------------------------\n\n%s' % (content,part.get_payload(decode=True))
33
+		return content
34
+	
35
+	def get_attachments(self):
36
+		attachments=[]
37
+		counter=1
38
+		for part in self.msg.walk():
39
+			part_type = part.get_content_maintype()
40
+			if part_type == 'text' or part_type == 'multipart':
41
+				continue
42
+			filename = part.get_filename()
43
+			if not filename:
44
+				ext = mimetypes.guess_extension(part.get_content_type())
45
+				if not ext:
46
+					ext = '.bin'
47
+				filename = 'part-%03d%s' % (counter, ext)
48
+			counter += 1
49
+			content=part.get_payload(decode=False)
50
+			attachments.append({
51
+				'filename':	filename,
52
+				'type':		part_type,
53
+				'content':	content
54
+			})
55
+		return attachments
56
+
57
+def send(mail_from,to,subject,content,smtp_host='127.0.0.1',smtp_port=25):
58
+	msg = MIMEText(content)
59
+	msg['To'] = to
60
+	msg['From'] = mail_from
61
+	msg['Subject'] = subject
62
+
63
+	server = smtplib.SMTP(smtp_host,smtp_port)
64
+
65
+	try:
66
+		server.sendmail(mail_from, [to], msg.as_string())
67
+	except:
68
+		logging.error('Error sending mail to %s - %s : %s' % (to,subject,sys.exc_info()[0]))
69
+                return
70
+
... ...
@@ -0,0 +1,165 @@
1
+#!/usr/bin/python
2
+
3
+import smtpd
4
+import logging
5
+import sys
6
+import smtplib
7
+import MantisMail
8
+import MantisWS
9
+import asyncore
10
+import os
11
+import signal
12
+
13
+class MantisSMTPServer(smtpd.SMTPServer):
14
+
15
+	_mail2project = {}
16
+
17
+	_options={}
18
+	_options['mail_from']='postmaster-mantis@example.net'
19
+	_options['smtp_host']='127.0.0.1'
20
+	_options['smtp_port']='25'
21
+	_options['ws_url']='http://mantis.example.net/api/soap/mantisconnect.php?wsdl'
22
+	_options['ws_user']='mantis'
23
+	_options['ws_pwd']='password'
24
+	_options['ws_default_category']='other'
25
+
26
+	ws=None
27
+
28
+	_pidfile = None
29
+
30
+	def start(self):
31
+		logging.info('Start Mantis SMTP Server')
32
+		self._start()
33
+
34
+	def startDaemon(self,pidfile):
35
+		self._pidfile=pidfile
36
+		try:
37
+			pid = os.fork()
38
+			if pid > 0:
39
+				# Exit parent
40
+				sys.exit(0)
41
+		except OSError, e:
42
+			sys.stderr.write("Daemonize failed: %d (%s)\n" % (e.errno, e.strerror))
43
+                        sys.exit(1)
44
+
45
+		logging.info('Start Mantis SMTP Server as daemon')
46
+		pid = str(os.getpid())
47
+		file(self._pidfile,'w+').write("%s\n" % pid)
48
+		signal.signal(signal.SIGTERM,self.stopDaemon)
49
+		self._start()
50
+
51
+	def stopDaemon(self,signum, frame):
52
+		logging.info('Stop Mantis SMTP Server by SIGTERM')
53
+		os.remove(self._pidfile)
54
+		sys.exit(0)
55
+		
56
+	def _start(self):
57
+		asyncore.loop()
58
+		
59
+	def stop(self):
60
+		logging.info('Stop Mantis SMTP Server')
61
+
62
+	def process_message(self, peer, mailfrom, rcpttos, data):
63
+
64
+		logging.info('Message receive from %s, send by %s to %s' % (peer,mailfrom,rcpttos))
65
+		
66
+		try:
67
+			msg = MantisMail.MantisMail(mailfrom,rcpttos,data)
68
+		except:
69
+			logging.error('Error parsing message receive from %s, send by %s to %s : %s' % (peer,mailfrom,rcpttos,sys.exc_info()[0]))
70
+			return
71
+
72
+		issue_id=msg.get_issue_id_from_subject()
73
+
74
+		if issue_id:
75
+			logging.info("Answer to issue #%s" % issue_id)
76
+			self.add_note_to_issue_from_msg(msg)
77
+		else:
78
+			project_infos=self.get_mantis_project_infos_from_recipient(rcpttos)
79
+			if project_infos is None:
80
+				logging.warning("Unknown recipient : Can't determine project to create issue. This email can't be processed. Warning message will be send to sender.")
81
+				MantisMail.send(
82
+					self._options['mail_from'],
83
+					msg.mailfrom,
84
+					'[Mantis] Unknown recipient %s' % rcpttos[0],
85
+					"Your email can't be inserted in Mantis because the recipient address of your message can't be recognized.\n\nPlease call your system administrator.",
86
+					smtp_host=self._options['smtp_host'],
87
+					smtp_port=self._options['smtp_port']
88
+				)
89
+			else:
90
+				project=project_infos['project']
91
+				logging.info("New issue for project %s" % project)
92
+				self.add_new_issue_to_project_from_msg(project_infos,msg)
93
+ 
94
+		return
95
+
96
+	def add_project(self,email,project,category=None):
97
+		self._mail2project[email]={
98
+			'project':	project
99
+		}
100
+		if category is not None:
101
+			self._mail2project[email]['category']=category
102
+
103
+	def get_mantis_project_infos_from_recipient(self,tos):
104
+		for to in tos:
105
+			if to in self._mail2project:
106
+				return self._mail2project[to]
107
+		return None
108
+
109
+
110
+	def set_option(self,option,value):
111
+		if option in self._options:
112
+			self._options[option]=value
113
+
114
+	def start_ws(self):
115
+		self.ws=MantisWS.MantisWS(self._options['ws_url'],self._options['ws_user'],self._options['ws_pwd'])
116
+
117
+		self.ws.set_option('default_category',self._options['ws_default_category'])
118
+
119
+		for option in ['mail_from','smtp_host','smtp_port']:
120
+			self.ws.set_option(option,self._options[option])
121
+
122
+
123
+	def add_new_issue_to_project_from_msg(self,project_infos,msg):
124
+		if self.ws is None:
125
+			self.start_ws()
126
+		issue_id = self.ws.add_issue_to_project(msg.mailfrom,project_infos,msg.subject(),msg.get_text())
127
+		if issue_id:
128
+			logging.info('Issue added with id %s' % issue_id)
129
+			return issue_id
130
+		else:
131
+			logging.error('Error during add issue')
132
+
133
+	def add_note_to_issue_from_msg(self,msg):
134
+		if self.ws is None:
135
+			self.start_ws()
136
+
137
+		issue_id=msg.get_issue_id_from_subject()
138
+
139
+		note_id = self.ws.add_note_to_issue(issue_id,msg.get_text())
140
+		if note_id:
141
+			logging.info('Note add to issue %s with id %s' % (issue_id,note_id))
142
+
143
+			for attachment in msg.get_attachments():
144
+				try:
145
+					logging.info('Add attachment to issue %s : %s' % (issue_id,attachment['filename']))
146
+					self.ws.add_attachment_to_issue(issue_id,attachment)
147
+				except MantisWS.MantisWSError, e:
148
+					if e.type == 'duplicate_attachment_filename':
149
+						logging.error('Duplicate filename %s in issue %s. Warning sender by mail.' % (attachment['filename'],issue_id))
150
+						MantisMail.send(
151
+							self._options['mail_from'],
152
+							msg.mailfrom,
153
+							'[Mantis] Duplicate filename %s in issue %s' % (attachment['filename'],issue_id),
154
+							"Your file %s attach in your email '%s' can't be attached to Mantis issue %s because a file with the same name is currently attached to this issue." % (attachment['filename'],msg.subject(),issue_id),
155
+							smtp_host=self._options['smtp_host'],
156
+							smtp_port=self._options['smtp_port']
157
+						)
158
+	
159
+				except:
160
+					logging.error('Error adding attachment %s to issue %s' % (attachment['filename'],issue_id))
161
+#				
162
+
163
+			return issue_id
164
+		else:
165
+			logging.error('Error during add issue')
... ...
@@ -0,0 +1,84 @@
1
+#!/usr/bin/python
2
+
3
+import suds
4
+import logging
5
+import re
6
+import MantisMail
7
+
8
+class MantisWS(object):
9
+
10
+	_options = {}
11
+	_options['default_category']='other'
12
+        _options['mail_from']='postmaster-mantis@example.net'
13
+        _options['smtp_host']='127.0.0.1'
14
+        _options['smtp_port']='25'
15
+
16
+	def __init__(self,url,user,password):
17
+		self.url = url
18
+		self.user = user
19
+		self.password = password
20
+
21
+		try:
22
+			self.client = suds.client.Client(url)
23
+		except:
24
+			logging.error('Error connecting to Mantis WS with URL %s' % url)
25
+
26
+	def add_issue_to_project(self,reporter_email,project_infos,summary,description):
27
+		issue = self.client.factory.create('IssueData')
28
+		issue.reporter.email = reporter_email
29
+		issue.project.name = project_infos['project']
30
+		issue.project.id = 0 # Auto-detect
31
+
32
+		if 'category' in project_infos:
33
+			issue.category = project_infos['category']
34
+		else:
35
+			issue.category = self._options['default_category']
36
+		issue.summary = summary
37
+		issue.description = description
38
+		try:
39
+			res = self.client.service.mc_issue_add(self.user,self.password,issue)
40
+			return res
41
+		except:
42
+			logging.error('Problem adding issue')
43
+			return None
44
+
45
+	def add_note_to_issue(self,issue_id,text):
46
+		note = self.client.factory.create('IssueNoteData')
47
+		note.text=text
48
+
49
+		try:
50
+			res = self.client.service.mc_issue_note_add(self.user,self.password,issue_id,note)
51
+			return res
52
+		except:
53
+			logging.error('Problem adding note to issue %s' % issue_id)
54
+			return None
55
+	def add_attachment_to_issue(self,issue_id,attachment):
56
+		try:
57
+			res = self.client.service.mc_issue_attachment_add(
58
+				self.user,
59
+				self.password,
60
+				issue_id,
61
+				attachment['filename'],
62
+				attachment['type'],
63
+				attachment['content']
64
+			)
65
+			return res
66
+		except suds.WebFault, e:
67
+			logging.error('Problem adding attachment %s to issue %s : %s' % (attachment['filename'],issue_id,e))
68
+			err=str(e)
69
+			if re.search('Duplicate filename',err):
70
+				raise MantisWSError('duplicate_attachment_filename','Duplicate attachment filename %s in issue %s' % (attachment['filename'],issue_id))
71
+		except:
72
+			logging.error('Problem adding attachment %s to issue %s' % (attachment['filename'],issue_id))
73
+			return None
74
+
75
+        def set_option(self,option,value):
76
+                if option in self._options:
77
+                        self._options[option]=value
78
+
79
+class MantisWSError(Exception):
80
+
81
+	def __init__(self,type,msg):
82
+		Exception.__init__(self, msg)
83
+		self.type = type
84
+		
0 85