source: emailtotracscript/trunk/email2trac.py.in @ 140

Last change on this file since 140 was 140, checked in by bas, 17 years ago

EmailtoTracScript?:

email2trac.py.in:

  • Removed email2trac from ticket description field
  • Property svn:executable set to *
  • Property svn:keywords set to Id
File size: 22.5 KB
Line 
1#!@PYTHON@
2# Copyright (C) 2002
3#
4# This file is part of the email2trac utils
5#
6# This program is free software; you can redistribute it and/or modify it
7# under the terms of the GNU General Public License as published by the
8# Free Software Foundation; either version 2, or (at your option) any
9# later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
19#
20# For vi/emacs or other use tabstop=4 (vi: set ts=4)
21#
22"""
23email2trac.py -- Email tickets to Trac.
24
25A simple MTA filter to create Trac tickets from inbound emails.
26
27Copyright 2005, Daniel Lundin <daniel@edgewall.com>
28Copyright 2005, Edgewall Software
29
30Changed By: Bas van der Vlies <basv@sara.nl>
31Date      : 13 September 2005
32Descr.    : Added config file and command line options, spam level
33            detection, reply address and mailto option. Unicode support
34
35Changed By: Walter de Jong <walter@sara.nl>
36Descr.    : multipart-message code and trac attachments
37
38
39The scripts reads emails from stdin and inserts directly into a Trac database.
40MIME headers are mapped as follows:
41
42        * From:      => Reporter
43                     => CC (Optional via reply_address option)
44        * Subject:   => Summary
45        * Body       => Description
46        * Component  => Can be set to SPAM via spam_level option
47
48How to use
49----------
50 * Create an config file:
51        [DEFAULT]                      # REQUIRED
52        project      : /data/trac/test # REQUIRED
53        debug        : 1               # OPTIONAL, if set print some DEBUG info
54        spam_level   : 4               # OPTIONAL, if set check for SPAM mail
55        reply_address: 1               # OPTIONAL, if set then fill in ticket CC field
56        umask        : 022             # OPTIONAL, if set then use this umask for creation of the attachments
57        mailto_link  : 1               # OPTIONAL, if set then [mailto:<>] in description
58        mailto_cc    : basv@sara.nl    # OPTIONAL, use this address as CC in mailto line
59        ticket_update: 1               # OPTIONAL, if set then check if this is an update for a ticket
60        trac_version : 0.8             # OPTIONAL, default is 0.9
61
62        [jouvin]                         # OPTIONAL project declaration, if set both fields necessary
63        project      : /data/trac/jouvin # use -p|--project jouvin. 
64       
65 * default config file is : /etc/email2trac.conf
66
67 * Commandline opions:
68                -h | --help
69                -c <value> | --component=<value>
70                -f <config file> | --file=<config file>
71                -p <project name> | --project=<project name>
72
73SVN Info:
74        $Id: email2trac.py.in 140 2006-12-04 13:05:01Z bas $
75"""
76import os
77import sys
78import string
79import getopt
80import stat
81import time
82import email
83import email.Iterators
84import email.Header
85import re
86import urllib
87import unicodedata
88import ConfigParser
89from stat import *
90import mimetypes
91import syslog
92import traceback
93
94
95# Some global variables
96#
97trac_default_version = 0.9
98m = None
99
100
101class TicketEmailParser(object):
102        env = None
103        comment = '> '
104   
105        def __init__(self, env, parameters, version):
106                self.env = env
107
108                # Database connection
109                #
110                self.db = None
111
112                # Some useful mail constants
113                #
114                self.author = None
115                self.email_addr = None
116                self.email_field = None
117
118                self.VERSION = version
119                if self.VERSION == 0.8:
120                        self.get_config = self.env.get_config
121                else:
122                        self.get_config = self.env.config.get
123
124                if parameters.has_key('umask'):
125                        os.umask(int(parameters['umask'], 8))
126
127                if parameters.has_key('debug'):
128                        self.DEBUG = int(parameters['debug'])
129                else:
130                        self.DEBUG = 0
131
132                if parameters.has_key('mailto_link'):
133                        self.MAILTO = int(parameters['mailto_link'])
134                        if parameters.has_key('mailto_cc'):
135                                self.MAILTO_CC = parameters['mailto_cc']
136                        else:
137                                self.MAILTO_CC = ''
138                else:
139                        self.MAILTO = 0
140
141                if parameters.has_key('spam_level'):
142                        self.SPAM_LEVEL = int(parameters['spam_level'])
143                else:
144                        self.SPAM_LEVEL = 0
145
146                if parameters.has_key('email_comment'):
147                        self.comment = str(parameters['email_comment'])
148
149                if parameters.has_key('email_header'):
150                        self.EMAIL_HEADER = int(parameters['email_header'])
151                else:
152                        self.EMAIL_HEADER = 0
153
154                if parameters.has_key('alternate_notify_template'):
155                        self.notify_template = str(parameters['alternate_notify_template'])
156                else:
157                        self.notify_template = None
158
159                if parameters.has_key('reply_all'):
160                        self.REPLY_ALL = int(parameters['reply_all'])
161                else:
162                        self.REPLY_ALL = 0
163
164                if parameters.has_key('ticket_update'):
165                        self.TICKET_UPDATE = int(parameters['ticket_update'])
166                else:
167                        self.TICKET_UPDATE = 0
168
169                if parameters.has_key('drop_spam'):
170                        self.DROP_SPAM = int(parameters['drop_spam'])
171                else:
172                        self.DROP_SPAM = 0
173
174                if parameters.has_key('verbatim_format'):
175                        self.VERBATIM_FORMAT = int(parameters['verbatim_format'])
176                else:
177                        self.VERBATIM_FORMAT = 1
178
179                if parameters.has_key('strip_signature'):
180                        self.STRIP_SIGNATURE = int(parameters['strip_signature'])
181                else:
182                        self.STRIP_SIGNATURE = 0
183
184        # X-Spam-Score: *** (3.255) BAYES_50,DNS_FROM_AHBL_RHSBL,HTML_
185        # Note if Spam_level then '*' are included
186        def spam(self, message):
187                if message.has_key('X-Spam-Score'):
188                        spam_l = string.split(message['X-Spam-Score'])
189                        number = spam_l[0].count('*')
190
191                        if number >= self.SPAM_LEVEL:
192                                return 'Spam'
193
194                elif message.has_key('X-Virus-found'):                  # treat virus mails as spam
195                        return 'Spam'
196
197                return self.get_config('ticket', 'default_component')
198
199        def email_to_unicode(self, message_str):
200                """
201                Email has 7 bit ASCII code, convert it to unicode with the charset
202        that is encoded in 7-bit ASCII code and encode it as utf-8 so Trac
203                understands it.
204                """
205                results =  email.Header.decode_header(message_str)
206                str = None
207                for text,format in results:
208                        if format:
209                                try:
210                                        temp = unicode(text, format)
211                                except UnicodeError, detail:
212                                        # This always works
213                                        #
214                                        temp = unicode(text, 'iso-8859-15')
215                                except LookupError, detail:
216                                        #text = 'ERROR: Could not find charset: %s, please install' %format
217                                        #temp = unicode(text, 'iso-8859-15')
218                                        temp = message_str
219                                       
220                        else:
221                                temp = string.strip(text)
222                                temp = unicode(text, 'iso-8859-15')
223
224                        if str:
225                                str = '%s %s' %(str, temp)
226                        else:
227                                str = '%s' %temp
228
229                #str = str.encode('utf-8')
230                return str
231
232        def debug_attachments(self, message):
233                n = 0
234                for part in message.walk():
235                        if part.get_content_maintype() == 'multipart':      # multipart/* is just a container
236                                print 'TD: multipart container'
237                                continue
238
239                        n = n + 1
240                        print 'TD: part%d: Content-Type: %s' % (n, part.get_content_type())
241                        print 'TD: part%d: filename: %s' % (n, part.get_filename())
242
243                        if part.is_multipart():
244                                print 'TD: this part is multipart'
245                                payload = part.get_payload(decode=1)
246                                print 'TD: payload:', payload
247                        else:
248                                print 'TD: this part is not multipart'
249
250                        part_file = '/var/tmp/part%d' % n
251                        print 'TD: writing part%d (%s)' % (n,part_file)
252                        fx = open(part_file, 'wb')
253                        text = part.get_payload(decode=1)
254                        if not text:
255                                text = '(None)'
256                        fx.write(text)
257                        fx.close()
258                        try:
259                                os.chmod(part_file,S_IRWXU|S_IRWXG|S_IRWXO)
260                        except OSError:
261                                pass
262
263        def email_header_txt(self, m):
264                """
265                Display To and CC addresses in description field
266                """
267                str = ''
268                if m['To'] and len(m['To']) > 0 and m['To'] != 'hic@sara.nl':
269                        str = "'''To:''' %s [[BR]]" %(m['To'])
270                if m['Cc'] and len(m['Cc']) > 0:
271                        str = "%s'''Cc:''' %s [[BR]]" % (str, m['Cc'])
272
273                return  self.email_to_unicode(str)
274
275
276        def set_owner(self, ticket):
277                """
278                Select default owner for ticket component
279                """
280                cursor = self.db.cursor()
281                sql = "SELECT owner FROM component WHERE name='%s'" % ticket['component']
282                cursor.execute(sql)
283                try:
284                        ticket['owner'] = cursor.fetchone()[0]
285                except TypeError, detail:
286                        ticket['owner'] = "UNKNOWN"
287
288        def get_author_emailaddrs(self, message):
289                """
290                Get the default author name and email address from the message
291                """
292                self.author, self.email_addr  = email.Utils.parseaddr(message['from'])
293
294                # Look for email address in registered trac users
295                #
296                if self.VERSION == 0.8:
297                        users = []
298                else:
299                        users = [ u for (u, n, e) in self.env.get_known_users(self.db)
300                                if e == self.email_addr ]
301
302                if len(users) == 1:
303                        self.email_field = users[0]
304                else:
305                        self.email_field =  self.email_to_unicode(message['from'])
306
307        def set_reply_fields(self, ticket, message):
308                """
309                Set all the right fields for a new ticket
310                """
311                ticket['reporter'] = self.email_field
312
313                # Put all CC-addresses in ticket CC field
314                #
315                if self.REPLY_ALL:
316                        #tos = message.get_all('to', [])
317                        ccs = message.get_all('cc', [])
318
319                        addrs = email.Utils.getaddresses(ccs)
320                        if not addrs:
321                                return
322
323                        # Remove reporter email address if notification is
324                        # on
325                        #
326                        if self.notification:
327                                try:
328                                        addrs.remove((self.author, self.email_addr))
329                                except ValueError, detail:
330                                        pass
331
332                        for name,mail in addrs:
333                                try:
334                                        mail_list = '%s, %s' %(mail_list, mail)
335                                except:
336                                        mail_list = mail
337
338                        if mail_list:
339                                ticket['cc'] = self.email_to_unicode(mail_list)
340
341        def save_email_for_debug(self, message, tempfile=False):
342                if tempfile:
343                        import tempfile
344                        msg_file = tempfile.mktemp('.email2trac')
345                else:
346                        msg_file = '/var/tmp/msg.txt'
347                print 'TD: saving email to %s' % msg_file
348                fx = open(msg_file, 'wb')
349                fx.write('%s' % message)
350                fx.close()
351                try:
352                        os.chmod(msg_file,S_IRWXU|S_IRWXG|S_IRWXO)
353                except OSError:
354                        pass
355
356        def ticket_update(self, m):
357                """
358                If the current email is a reply to an existing ticket, this function
359                will append the contents of this email to that ticket, instead of
360                creating a new one.
361                """
362                if not m['Subject']:
363                        return False
364                else:
365                        subject  = self.email_to_unicode(m['Subject'])
366
367                TICKET_RE = re.compile(r"""
368                                        (?P<ticketnr>[#][0-9]+:)
369                                        """, re.VERBOSE)
370
371                result =  TICKET_RE.search(subject)
372                if not result:
373                        return False
374
375                body_text = self.get_body_text(m)
376
377                # Strip '#' and ':' from ticket_id
378                #
379                ticket_id = result.group('ticketnr')
380                ticket_id = int(ticket_id[1:-1])
381
382                # Get current time
383                #
384                when = int(time.time())
385
386                if self.VERSION  == 0.8:
387                        tkt = Ticket(self.db, ticket_id)
388                        tkt.save_changes(self.db, self.author, body_text, when)
389                else:
390                        try:
391                                tkt = Ticket(self.env, ticket_id, self.db)
392                        except util.TracError, detail:
393                                return False
394
395                        tkt.save_changes(self.author, body_text, when)
396                        tkt['id'] = ticket_id
397
398                if self.VERSION  == 0.9:
399                        self.attachments(m, tkt, True)
400                else:
401                        self.attachments(m, tkt)
402
403                if self.notification:
404                        self.notify(tkt, False, when)
405
406                return True
407
408        def new_ticket(self, msg):
409                """
410                Create a new ticket
411                """
412                tkt = Ticket(self.env)
413                tkt['status'] = 'new'
414
415                # Some defaults
416                #
417                tkt['milestone'] = self.get_config('ticket', 'default_milestone')
418                tkt['priority'] = self.get_config('ticket', 'default_priority')
419                tkt['severity'] = self.get_config('ticket', 'default_severity')
420                tkt['version'] = self.get_config('ticket', 'default_version')
421
422                if not msg['Subject']:
423                        tkt['summary'] = u'(geen subject)'
424                else:
425                        tkt['summary'] = self.email_to_unicode(msg['Subject'])
426
427
428                if settings.has_key('component'):
429                        tkt['component'] = settings['component']
430                else:
431                        tkt['component'] = self.spam(msg)
432
433                # Discard SPAM messages.
434                #
435                if self.DROP_SPAM and (tkt['component'] == 'Spam'):
436                        # print 'This message is a SPAM. Automatic ticket insertion refused (SPAM level > %d' % self.SPAM_LEVEL
437                        return False   
438
439                # Set default owner for component
440                #
441                self.set_owner(tkt)
442                self.set_reply_fields(tkt, msg)
443
444                # produce e-mail like header
445                #
446                head = ''
447                if self.EMAIL_HEADER > 0:
448                        head = self.email_header_txt(msg)
449                       
450
451                body_text = self.get_body_text(msg)
452
453                tkt['description'] = '\r\n%s\r\n%s' \
454                        %(head, body_text)
455
456                when = int(time.time())
457                if self.VERSION == 0.8:
458                        ticket_id = tkt.insert(self.db)
459                else:
460                        ticket_id = tkt.insert()
461                        tkt['id'] = ticket_id
462
463                changed = False
464                comment = ''
465
466                # Rewrite the description if we have mailto enabled
467                #
468                if self.MAILTO:
469                        changed = True
470                        comment = '\nadded mailto line\n'
471                        mailto = self.html_mailto_link(self.email_to_unicode(msg['subject']), ticket_id, body_text)
472                        tkt['description'] = 'email2trac:%s%s\r\n%s' %(head, mailto, body_text)
473
474                n =  self.attachments(msg, tkt)
475                if n:
476                        changed = True
477                        comment = '%s\nThis message has %d attachment(s)\n' %(comment, n)
478
479                if changed:
480                        if self.VERSION  == 0.8:
481                                tkt.save_changes(self.db, self.author, comment)
482                        else:
483                                tkt.save_changes(self.author, comment)
484
485                #print tkt.get_changelog(self.db, when)
486
487                if self.notification:
488                        self.notify(tkt, True)
489                        #self.notify(tkt, False)
490
491        def parse(self, fp):
492                global m
493
494                m = email.message_from_file(fp)
495                if not m:
496                        return
497
498                if self.DEBUG > 1:        # save the entire e-mail message text
499                        self.save_email_for_debug(m)
500                        self.debug_attachments(m)
501
502                self.db = self.env.get_db_cnx()
503                self.get_author_emailaddrs(m)
504
505                if self.get_config('notification', 'smtp_enabled') in ['true']:
506                        self.notification = 1
507                else:
508                        self.notification = 0
509
510                # Must we update existing tickets
511                #
512                if self.TICKET_UPDATE > 0:
513                        if self.ticket_update(m):
514                                return True
515
516                self.new_ticket(m)
517
518        def strip_signature(self, text):
519                """
520                Strip signature from message, inspired by Mailman software
521                """
522                body = []
523                for line in text.splitlines():
524                        if line == '-- ':
525                                break
526                        body.append(line)
527
528                return ('\n'.join(body))
529
530        def get_body_text(self, msg):
531                """
532                put the message text in the ticket description or in the changes field.
533                message text can be plain text or html or something else
534                """
535                has_description = 0
536                encoding = True
537                ubody_text = u'No plain text message'
538                for part in msg.walk():
539
540                        # 'multipart/*' is a container for multipart messages
541                        #
542                        if part.get_content_maintype() == 'multipart':
543                                continue
544
545                        if part.get_content_type() == 'text/plain':
546                                # Try to decode, if fails then do not decode
547                                #
548                                body_text = part.get_payload(decode=1)
549                                if not body_text:                       
550                                        body_text = part.get_payload(decode=0)
551               
552                                if self.STRIP_SIGNATURE:
553                                        body_text = self.strip_signature(body_text)
554
555                                # Get contents charset (iso-8859-15 if not defined in mail headers)
556                                #
557                                charset = part.get_content_charset()
558                                if not charset:
559                                        charset = 'iso-8859-15'
560
561                                try:
562                                        ubody_text = unicode(body_text, charset)
563
564                                except UnicodeError, detail:
565                                        ubody_text = unicode(body_text, 'iso-8859-15')
566
567                                except LookupError, detail:
568                                        ubody_text = 'ERROR: Could not find charset: %s, please install' %(charset)
569
570                        elif part.get_content_type() == 'text/html':
571                                ubody_text = '(see attachment for HTML mail message)'
572
573                        else:
574                                ubody_text = '(see attachment for message)'
575
576                        has_description = 1
577                        break           # we have the description, so break
578
579                if not has_description:
580                        ubody_text = '(see attachment for message)'
581
582                # A patch so that the web-interface will not update the description
583                # field of a ticket
584                #
585                ubody_text = ('\r\n'.join(ubody_text.splitlines()))
586
587                #  If we can unicode it try to encode it for trac
588                #  else we a lot of garbage
589                #
590                if encoding:
591                        ubody_text = ubody_text.encode('utf-8')
592
593                if self.VERBATIM_FORMAT:
594                        ubody_text = '{{{\r\n%s\r\n}}}' %ubody_text
595                else:
596                        ubody_text = '%s' %ubody_text
597
598                return ubody_text
599
600        def notify(self, tkt , new=True, modtime=0):
601                """
602                A wrapper for the TRAC notify function. So we can use templates
603                """
604                if tkt['component'] == 'Spam':
605                        return 
606
607                try:
608                        # create false {abs_}href properties, to trick Notify()
609                        #
610                        self.env.abs_href = Href(self.get_config('project', 'url'))
611                        self.env.href = Href(self.get_config('project', 'url'))
612
613                        tn = TicketNotifyEmail(self.env)
614                        if self.notify_template:
615                                tn.template_name = self.notify_template;
616
617                        tn.notify(tkt, new, modtime)
618
619                except Exception, e:
620                        print 'TD: Failure sending notification on creation of ticket #%s: %s' %(tkt['id'], e)
621
622        def mail_line(self, str):
623                return '%s %s' % (self.comment, str)
624
625
626        def html_mailto_link(self, subject, id, body):
627                if not self.author:
628                        author = self.email_addr
629                else:   
630                        author = self.email_to_unicode(self.author)
631
632                # Must find a fix
633                #
634                #arr = string.split(body, '\n')
635                #arr = map(self.mail_line, arr)
636                #body = string.join(arr, '\n')
637                #body = '%s wrote:\n%s' %(author, body)
638
639                # Temporary fix
640                str = 'mailto:%s?Subject=%s&Cc=%s' %(
641                       urllib.quote(self.email_addr),
642                           urllib.quote('Re: #%s: %s' %(id, subject)),
643                           urllib.quote(self.MAILTO_CC)
644                           )
645
646                str = '\r\n{{{\r\n#!html\r\n<a href="%s">Reply to: %s</a>\r\n}}}\r\n' %(str, author)
647
648                return str
649
650        def attachments(self, message, ticket, update=False):
651                '''
652                save any attachments as files in the ticket's directory
653                '''
654                count = 0
655                first = 0
656                number = 0
657                for part in message.walk():
658                        if part.get_content_maintype() == 'multipart':          # multipart/* is just a container
659                                continue
660
661                        if not first:                                                                           # first content is the message
662                                first = 1
663                                if part.get_content_type() == 'text/plain':             # if first is text, is was already put in the description
664                                        continue
665
666                        filename = part.get_filename()
667                        count = count + 1
668                        if not filename:
669                                number = number + 1
670                                filename = 'part%04d' % number
671
672                                ext = mimetypes.guess_extension(part.get_content_type())
673                                if not ext:
674                                        ext = '.bin'
675
676                                filename = '%s%s' % (filename, ext)
677                        else:
678                                filename = self.email_to_unicode(filename)
679
680                        # From the trac code
681                        #
682                        filename = filename.replace('\\', '/').replace(':', '/')
683                        filename = os.path.basename(filename)
684
685                        # We try to normalize the filename to utf-8 NFC if we can.
686                        # Files uploaded from OS X might be in NFD.
687                        # Check python version and then try it
688                        #
689                        if sys.version_info[0] > 2 or (sys.version_info[0] == 2 and sys.version_info[1] >= 3):
690                                try:
691                                        filename = unicodedata.normalize('NFC', unicode(filename, 'utf-8')).encode('utf-8') 
692                                except TypeError:
693                                        pass
694
695                        url_filename = urllib.quote(filename)
696                        if self.VERSION == 0.8:
697                                dir = os.path.join(self.env.get_attachments_dir(), 'ticket',
698                                                        urllib.quote(str(ticket['id'])))
699                                if not os.path.exists(dir):
700                                        mkdir_p(dir, 0755)
701                        else:
702                                dir = '/tmp'
703
704                        path, fd =  util.create_unique_file(os.path.join(dir, url_filename))
705                        text = part.get_payload(decode=1)
706                        if not text:
707                                text = '(None)'
708                        fd.write(text)
709                        fd.close()
710
711                        # get the filesize
712                        #
713                        stats = os.lstat(path)
714                        filesize = stats[stat.ST_SIZE]
715
716                        # Insert the attachment it differs for the different TRAC versions
717                        #
718                        if self.VERSION == 0.8:
719                                cursor = self.db.cursor()
720                                try:
721                                        cursor.execute('INSERT INTO attachment VALUES("%s","%s","%s",%d,%d,"%s","%s","%s")'
722                                                %('ticket', urllib.quote(str(ticket['id'])), filename + '?format=raw', filesize,
723                                                int(time.time()),'', self.author, 'e-mail') )
724
725                                # Attachment is already known
726                                #
727                                except sqlite.IntegrityError:   
728                                        #self.db.close()
729                                        return count
730
731                                self.db.commit()
732
733                        else:
734                                fd = open(path)
735                                att = attachment.Attachment(self.env, 'ticket', ticket['id'])
736
737                                # This will break the ticket_update system, the body_text is vaporized
738                                # ;-(
739                                #
740                                if not update:
741                                        att.author = self.author
742                                        att.description = self.email_to_unicode('Added by email2trac')
743
744                                att.insert(url_filename, fd, filesize)
745                                fd.close()
746
747                        # Remove the created temporary filename
748                        #
749                        os.unlink(path)
750
751                # Return how many attachments
752                #
753                return count
754
755
756def mkdir_p(dir, mode):
757        '''do a mkdir -p'''
758
759        arr = string.split(dir, '/')
760        path = ''
761        for part in arr:
762                path = '%s/%s' % (path, part)
763                try:
764                        stats = os.stat(path)
765                except OSError:
766                        os.mkdir(path, mode)
767
768
769def ReadConfig(file, name):
770        """
771        Parse the config file
772        """
773
774        if not os.path.isfile(file):
775                print 'File %s does not exist' %file
776                sys.exit(1)
777
778        config = ConfigParser.ConfigParser()
779        try:
780                config.read(file)
781        except ConfigParser.MissingSectionHeaderError,detail:
782                print detail
783                sys.exit(1)
784
785
786        # Use given project name else use defaults
787        #
788        if name:
789                if not config.has_section(name):
790                        print "Not a valid project name: %s" %name
791                        print "Valid names: %s" %config.sections()
792                        sys.exit(1)
793
794                project =  dict()
795                for option in  config.options(name):
796                        project[option] = config.get(name, option)
797
798        else:
799                project = config.defaults()
800
801        return project
802
803
804if __name__ == '__main__':
805        # Default config file
806        #
807        configfile = '@email2trac_conf@'
808        project = ''
809        component = ''
810        ENABLE_SYSLOG = 0
811               
812        try:
813                opts, args = getopt.getopt(sys.argv[1:], 'chf:p:', ['component=','help', 'file=', 'project='])
814        except getopt.error,detail:
815                print __doc__
816                print detail
817                sys.exit(1)
818       
819        project_name = None
820        for opt,value in opts:
821                if opt in [ '-h', '--help']:
822                        print __doc__
823                        sys.exit(0)
824                elif opt in ['-c', '--component']:
825                        component = value
826                elif opt in ['-f', '--file']:
827                        configfile = value
828                elif opt in ['-p', '--project']:
829                        project_name = value
830       
831        settings = ReadConfig(configfile, project_name)
832        if not settings.has_key('project'):
833                print __doc__
834                print 'No Trac project is defined in the email2trac config file.'
835                sys.exit(1)
836       
837        if component:
838                settings['component'] = component
839       
840        if settings.has_key('trac_version'):
841                version = float(settings['trac_version'])
842        else:
843                version = trac_default_version
844
845        if settings.has_key('enable_syslog'):
846                ENABLE_SYSLOG =  float(settings['enable_syslog'])
847                       
848        #debug HvB
849        #print settings
850       
851        try:
852                if version == 0.8:
853                        from trac.Environment import Environment
854                        from trac.Ticket import Ticket
855                        from trac.Notify import TicketNotifyEmail
856                        from trac.Href import Href
857                        from trac import util
858                        import sqlite
859                elif version == 0.9:
860                        from trac import attachment
861                        from trac.env import Environment
862                        from trac.ticket import Ticket
863                        from trac.web.href import Href
864                        from trac import util
865                        from trac.Notify import TicketNotifyEmail
866                elif version == 0.10:
867                        from trac import attachment
868                        from trac.env import Environment
869                        from trac.ticket import Ticket
870                        from trac.web.href import Href
871                        from trac import util
872                        #
873                        # return  util.text.to_unicode(str)
874                        #
875                        # see http://projects.edgewall.com/trac/changeset/2799
876                        from trac.ticket.notification import TicketNotifyEmail
877       
878                env = Environment(settings['project'], create=0)
879                tktparser = TicketEmailParser(env, settings, version)
880                tktparser.parse(sys.stdin)
881
882        # Catch all errors ans log to SYSLOG if we have enabled this
883        # else stdout
884        #
885        except Exception, error:
886                if ENABLE_SYSLOG:
887                        syslog.openlog('email2trac', syslog.LOG_NOWAIT)
888                        etype, evalue, etb = sys.exc_info()
889                        for e in traceback.format_exception(etype, evalue, etb):
890                                syslog.syslog(e)
891                        syslog.closelog()
892                else:
893                        traceback.print_exc()
894
895                if m:
896                        tktparser.save_email_for_debug(m, True)
897
898# EOB
Note: See TracBrowser for help on using the repository browser.