Warning: リポジトリと同期できません (サポートされていないバージョンコントロールシステム "svn です。 Python のライブラリに "svn" が正しくインストールされているか確認してください。)

バージョン 1 から バージョン 2 における更新: test

差分発生行の前後
無視リスト:
更新日時:
2007/02/15 23:53:35 (18 年 前)
更新者:
weekbuild (IP アドレス: 218.110.157.68)
コメント:

--

凡例:

変更なし
追加
削除
変更
  • test

    v1 v2  
    7373 
    7474    def decode_to_unicode(self, basestr): 
    75         #RFC2231の添付ファイル名はget_filenameではunicodeTypeでくるみたいだ 
    76         if type(basestr) == types.UnicodeType : 
    77             return basestr 
    78          
    7975        decodefrag = email.Header.decode_header(basestr) 
    8076        subj_fragments = ['',] 
     
    8480            subj_fragments.append(frag) 
    8581        return ''.join(subj_fragments) 
     82 
     83    def to_unicode(self,text,charset): 
     84        default_charset = self.env.config.get('mailarchive', 'default_charset',None) 
     85        if default_charset : 
     86            chaerset = default_charset 
     87         
     88        # to unicode with codecaliases 
     89        # codecaliases change mail charset to python charset 
     90        charset = charset.lower( )  
     91        aliases = {} 
     92        aliases_text = self.env.config.get('mailarchive', 'codecaliases') 
     93        for alias in aliases_text.split(','): 
     94            alias_s = alias.split(':') 
     95            if len(alias_s) >=2: 
     96                if alias_s[1] == 'cmd': 
     97                    aliases[alias_s[0].lower()] = ('cmd',alias_s[2]) 
     98                else: 
     99                    aliases[alias_s[0].lower()] = ('codec',alias_s[1]) 
     100         
     101        if aliases.has_key(charset): 
     102            (type,alias) = aliases[charset] 
     103            if type == 'codec': 
     104                text = unicode(text,alias) 
     105            elif type == 'cmd': 
     106                np = NaivePopen(alias, text, capturestderr=1) 
     107                if np.errorlevel or np.err: 
     108                    err = 'Running (%s) failed: %s, %s.' % (cmdline, np.errorlevel, 
     109                                                            np.err) 
     110                    raise Exception, err 
     111                text = unicode(np.out,'utf-8') 
     112        else: 
     113            text = unicode(text,charset) 
     114        return text 
     115 
     116    def import_message(self, msg, author,mlid, db): 
     117        OUTPUT_ENCODING = 'utf-8' 
     118        subject = '' 
     119        messageid = '' 
     120        utcdate = 0 
     121        localdate = 0 
     122        zoneoffset = 0 
     123        text = '' 
     124        fromtext = '' 
     125        body = '' 
     126        ref_messageid = '' 
     127 
     128        cursor = db.cursor() 
     129        is_newid = False 
     130         
     131        if 'message-id' in msg: 
     132            messageid = msg['message-id']  
     133            if messageid[:1] == '<': 
     134                messageid = messageid[1:] 
     135            if messageid[-1:] == '>': 
     136                messageid = messageid[:-1] 
     137            self.print_debug('Message-ID:%s' % messageid ) 
     138 
     139            #check messageid is unique 
     140            self.print_debug("Creating new mailarc '%s'" % 'mailarc') 
     141            cursor.execute("SELECT id from mailarc WHERE messageid=%s",(messageid,)) 
     142            row = cursor.fetchone() 
     143            id = None 
     144            if row: 
     145                id = row[0] 
     146            if id == None or id == "": 
     147                # why? get_last_id return 0 at first. 
     148                #id = db.get_last_id(cursor, 'mailarc') 
     149                is_newid = True 
     150                cursor.execute("SELECT Max(id)+1 as id from mailarc") 
     151                row = cursor.fetchone() 
     152                if row and row[0] != None: 
     153                    id = row[0] 
     154                else: 
     155                    id = 1 
     156            id = int(id) # Because id might be 'n.0', int() is called.  
     157 
     158 
     159        if 'date' in msg: 
     160            datetuple_tz = email.Utils.parsedate_tz(msg['date'])  
     161            localdate = calendar.timegm(datetuple_tz[:9]) #toDB 
     162            zoneoffset = datetuple_tz[9] # toDB 
     163            utcdate = localdate-zoneoffset # toDB 
     164            #make zone ( +HHMM or -HHMM 
     165            zone = '' 
     166            if zoneoffset >0: 
     167                zone = '+' + time.strftime('%H%M',time.gmtime(zoneoffset)) 
     168            elif zoneoffset < 0: 
     169                zone = '-' + time.strftime('%H%M',time.gmtime(-1*zoneoffset)) 
     170 
     171            #self.print_debug( time.strftime("%y/%m/%d %H:%M:%S %z",datetuple_tz[:9])) 
     172            self.print_debug( time.strftime("%Y/%m/%d %H:%M:%S",time.gmtime(utcdate))) 
     173            self.print_debug( time.strftime("%Y/%m/%d %H:%M:%S",time.gmtime(localdate))) 
     174            self.print_debug(zone) 
     175 
     176        fromname,fromaddr = email.Utils.parseaddr(msg['from']) 
     177        fromname = self.decode_to_unicode(fromname) 
     178        fromaddr = self.decode_to_unicode(fromaddr) 
     179 
     180        self.print_info( '  ' + time.strftime("%Y/%m/%d %H:%M:%S",time.gmtime(localdate))+' ' + zone +' '+ fromaddr) 
     181 
     182        if 'subject' in msg: 
     183            subject = self.decode_to_unicode(msg['subject']) 
     184            self.print_debug( subject.encode(OUTPUT_ENCODING)) 
     185 
     186        # make thread infomations 
     187        ref_messageid = '' 
     188        if 'in-reply-to' in msg: 
     189            ref_messageid = ref_messageid + msg['In-Reply-To'] + ' ' 
     190            self.print_debug('In-Reply-To:%s' % ref_messageid ) 
     191         
     192        if 'references' in msg: 
     193            ref_messageid = ref_messageid + msg['References'] + ' ' 
     194 
     195        m = re.findall(r'<(.+?)>', ref_messageid) 
     196        ref_messageid = '' 
     197        for text in m: 
     198            ref_messageid = ref_messageid + "'%s'," % text 
     199        ref_messageid = ref_messageid.strip(',') 
     200        self.print_debug('RefMessage-ID:%s' % ref_messageid ) 
     201         
     202 
     203        # multipart mail 
     204        if msg.is_multipart(): 
     205            body = '' 
     206            # delete all attachement at message-id 
     207            Attachment.delete_all(self.env, 'mailarchive', id, db) 
     208 
     209            for part in msg.walk(): 
     210                content_type = part.get_content_type() 
     211                self.print_debug('Content-Type:'+content_type) 
     212                file_counter = 1 
     213 
     214                if content_type == 'multipart/mixed': 
     215                    pass 
     216                elif content_type == 'text/html' and self.is_file(part) == False: 
     217                    body = part.get_payload(decode=1) 
     218                elif content_type == 'text/plain' and self.is_file(part) == False: 
     219                    body = part.get_payload(decode=1) 
     220                    charset = part.get_content_charset() 
     221                    self.print_debug('charset:'+str(charset)) 
     222                    # Todo:need try  
     223                    if charset != None: 
     224                        body = self.to_unicode(body,charset) 
     225                elif part.get_payload(decode=1) == None: 
     226                    pass 
     227                else: 
     228                    self.print_debug( part.get_content_type()) 
     229                    # get filename 
     230                    # Applications should really sanitize the given filename so that an 
     231                    # email message can't be used to overwrite important files 
     232                    filename = self.get_filename(part) 
     233                    if not filename: 
     234                        ext = mimetypes.guess_extension(part.get_content_type()) 
     235                        if not ext: 
     236                            # Use a generic bag-of-bits extension 
     237                            ext = '.bin' 
     238                        filename = 'part-%03d%s' % (file_counter, ext) 
     239                        file_counter += 1 
     240 
     241                    self.print_debug("filename:" + filename.encode(OUTPUT_ENCODING)) 
     242 
     243                    # make attachment  
     244                    tmp = os.tmpfile() 
     245                    tempsize =len(part.get_payload(decode=1)) 
     246                    tmp.write(part.get_payload(decode=1)) 
     247                     
     248                    tmp.flush() 
     249                    tmp.seek(0,0) 
     250 
     251                    attachment = Attachment(self.env,'mailarchive', id) 
     252 
     253                    attachment.description = '' # req.args.get('description', '') 
     254                    attachment.author = author #req.args.get('author', '') 
     255                    attachment.ipnr = '127.0.0.1' 
     256 
     257                    try: 
     258                        attachment.insert(filename,  
     259                                tmp, tempsize,None,db) 
     260                    except Exception, e: 
     261                        try: 
     262                            ext = filename.split('.')[-1] 
     263                            if ext == filename: 
     264                                ext = '.bin' 
     265                            else: 
     266                                ext = '.' + ext 
     267                            filename = 'part-%03d%s' % (file_counter, ext) 
     268                            file_counter += 1 
     269                            attachment.insert(filename,  
     270                                    tmp, tempsize,None,db) 
     271                            self.print_warning('As name is too long, the attached file is renamed : '+filename) 
     272 
     273                        except Exception, e: 
     274                            self.print_error('Exception at attach file of Message-ID:'+messageid) 
     275                            self.print_error( e ) 
     276 
     277                    tmp.close() 
     278 
     279        # not multipart mail 
     280        else: 
     281            # Todo:if Content-Type = text/html then convert htmlMail to text 
     282            content_type = msg.get_content_type() 
     283            self.print_debug('Content-Type:'+content_type) 
     284            if content_type == 'text/html': 
     285                body = 'html' 
     286            else: 
     287                #body 
     288                #self.print_debug(msg.get_content_type()) 
     289                body = msg.get_payload(decode=1) 
     290                charset = msg.get_content_charset() 
     291 
     292                # need try: 
     293                if charset != None: 
     294                    self.print_debug("charset:"+charset) 
     295                    body = self.to_unicode(body,charset) 
     296             
     297             
     298        #body = body.replace(os.linesep,'\n') 
     299        self.print_debug('Thread') 
     300 
     301        thread_parent = ref_messageid.replace("'",'').replace(',',' ') 
     302        thread_root = '' 
     303        if thread_parent !='': 
     304        # sarch first parent id 
     305            self.print_debug("SearchThread;"+thread_parent) 
     306            cursor = db.cursor() 
     307            sql = "SELECT threadroot,messageid FROM mailarc where messageid in (%s)" % ref_messageid 
     308            self.print_debug(sql) 
     309            cursor.execute(sql) 
     310 
     311            row = cursor.fetchone() 
     312            if row: 
     313                #thread_parent = row[1] 
     314                if row[0] == '': 
     315                    thread_root = thread_parent.split(' ').pop() 
     316                    self.print_debug("AddToThread;"+thread_root) 
     317                else: 
     318                    thread_root = row[0] 
     319                    self.print_debug("NewThread;"+thread_root) 
     320            else: 
     321                    self.print_debug("NoThread;"+thread_parent) 
     322        thread_root = thread_root.strip() 
     323         
     324        self.print_debug('Insert') 
     325             
     326        if messageid != '': 
     327 
     328            # insert or update  mailarc_category 
     329             
     330            yearmonth = time.strftime("%Y%m",time.gmtime(utcdate)) 
     331            category = mlid+yearmonth 
     332            cursor.execute("SELECT category,mlid,yearmonth,count FROM mailarc_category WHERE category=%s",(category.encode('utf-8'),)) 
     333            row = cursor.fetchone() 
     334            count = 0 
     335            if row: 
     336                count = row[3] 
     337                pass 
     338            else: 
     339                cursor.execute("INSERT INTO mailarc_category (category,mlid,yearmonth,count) VALUES(%s,%s,%s,%s)",(category.encode('utf-8'),mlid.encode('utf-8'),yearmonth,0)) 
     340            if is_newid == True: 
     341                count = count +1 
     342            cursor.execute("UPDATE mailarc_category SET count=%s WHERE category=%s" , 
     343                (count,category.encode('utf-8'))) 
     344 
     345            # insert or update mailarc 
     346                 
     347            #self.print_debug( 
     348            #    "VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)" %(str(id), 
     349            #    category.encode('utf-8'), 
     350            #    messageid, 
     351            #     utcdate, 
     352            #      zoneoffset, 
     353            #     subject.encode('utf-8'), fromname.encode('utf-8'), 
     354            #     fromaddr.encode('utf-8'),'','', 
     355            #     thread_root,thread_parent)) 
     356            cursor.execute("DELETE FROM mailarc where messageid=%s",(messageid,)) 
     357            cursor.execute("INSERT INTO mailarc (" 
     358                "id,category,messageid,utcdate,zoneoffset,subject," 
     359                "fromname,fromaddr,header,text, threadroot,threadparent ) " 
     360                "VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", 
     361                (str(id), 
     362                category.encode('utf-8'), 
     363                messageid, 
     364                 utcdate, 
     365                  zoneoffset, 
     366                 subject.encode('utf-8'), fromname.encode('utf-8'), 
     367                 fromaddr.encode('utf-8'),'',body.encode('utf-8'), 
     368                 thread_root,thread_parent)) 
     369 
     370        db.commit() 
     371 
     372    def do_refresh_category(self,line): 
     373        db = self.db_open() 
     374        self.env = self.env_open() 
     375        cursor = db.cursor() 
     376        cursor.execute("DELETE FROM mailarc_category") 
     377        cursor.execute("SELECT category, count(*) as cnt from mailarc GROUP BY category ") 
     378        for category,cnt in cursor: 
     379            cursor2 =  db.cursor() 
     380            cursor2.execute("INSERT INTO mailarc_category (category,mlid,yearmonth,count) VALUES(%s,%s,%s,%s)",(category,category[:-6],category[-6:],cnt)) 
     381        db.commit() 
     382 
     383    ## Help 
     384    _help_import = [('import <mlname> <filepath>', 'import UnixMail')] 
     385             
     386    def do_import(self,line): 
     387        arg = self.arg_tokenize(line) 
     388        if len(arg) < 2 : 
     389            print "import MLname filepath" 
     390        db = self.db_open() 
     391        self.env = self.env_open() 
     392        self._import_unixmailbox('cmd',db,arg[0],arg[1]) 
     393 
     394    ## Help 
     395    _help_pop3 = [('pop3 <mlname>', 'import from pop3 server')] 
     396 
     397    def do_pop3(self,line): 
     398        arg = self.arg_tokenize(line) 
     399        if len(arg) < 1 : 
     400            print "pop3 MLname" 
     401        db = self.db_open() 
     402        self.env = self.env_open() 
     403        self._import_from_pop3('cmd',db,arg[0]) 
     404 
     405    ## Help 
     406    _help_help = [('help', 'Show documentation')] 
     407 
     408    def do_help(self, line=None): 
     409        arg = self.arg_tokenize(line) 
     410        if arg[0]: 
     411            try: 
     412                doc = getattr(self, "_help_" + arg[0]) 
     413                self.print_doc (doc) 
     414            except AttributeError: 
     415                print "No documentation found for '%s'" % arg[0] 
     416        else: 
     417            docs = (#self._help_about + 
     418                    self._help_help + 
     419                    self._help_import + self._help_pop3  
     420                    ) 
     421            print 'mailarc-admin - The Trac MailArchivePlugin Administration Console '  
     422            if not self.interactive: 
     423                print 
     424                print "Usage: mailarc-admin </path/to/projenv> [command [subcommand] [option ...]]\n" 
     425                print "Invoking mailarc-admin without command starts "\ 
     426                      "interactive mode." 
     427            self.print_doc (docs) 
     428 
     429 
     430 
     431    def print_info(self,line): 
     432        print "%s" % line 
     433 
     434    def print_debug(self,line): 
     435        #print "[Debug] %s" % line 
     436        pass 
     437 
     438    def print_error(self,line): 
     439        print "[Error] %s" % line 
     440 
     441    def print_warning(self,line): 
     442        print "[Warning] %s" % line 
     443 
     444    def _import_unixmailbox(self,author, db, mlid, msgfile_path): 
     445        self.print_debug('import_mail') 
     446        if not db: 
     447            #db = self.env.get_db_cnx() 
     448            handle_ta = True 
     449        else: 
     450            handle_ta = False 
     451 
     452 
     453        #paser = Parser() 
     454 
     455        self.print_info("%s Start Importing %s ..." %  
     456            (time.strftime("%Y/%m/%d %H:%M:%S",time.gmtime()),msgfile_path)) 
     457 
     458        fp = open(msgfile_path,"rb") 
     459        mbox = mailbox.UnixMailbox(fp, self.msgfactory) 
     460         
     461        counter =1 
     462        msg = mbox.next() 
     463        while msg is not None: 
     464            messageid = '' 
     465            try: 
     466                messageid = msg['message-id']  
     467                self.import_message(msg,author,mlid,db) 
     468            except Exception, e: 
     469                exception_flag = True 
     470                self.print_error('Exception At Message-ID:'+messageid) 
     471                self.print_error( e ) 
     472                #traceback.print_exc() 
     473 
     474            if counter > 10000: 
     475                break 
     476            msg = mbox.next() 
     477            counter = counter + 1 
     478 
     479 
     480        fp.close() 
     481        #if handle_ta: 
     482        db.commit() 
     483        self.print_info("End Imporing %s. " % msgfile_path) 
     484 
     485    def _import_from_pop3(self,author, db, mlid): 
     486 
     487        pop_server = self.env.config.get('mailarchive', 'pop3_server') 
     488        pop_user = self.env.config.get('mailarchive', 'pop3_user') 
     489        pop_password = self.env.config.get('mailarchive', 'pop3_password') 
     490        pop_delete = self.env.config.get('mailarchive', 'pop3_delete','none') 
     491 
     492        if pop_server =='': 
     493            self.print_error('trac.ini mailarchive pop3_server is null!') 
     494        elif pop_user == '': 
     495            self.print_error('trac.ini mailarchive pop3_user is null!') 
     496        elif pop_password == '': 
     497            self.print_error('trac.ini mailarchive pop3_password is null!') 
     498 
     499        self.print_info("%s Start Connction pop3 %s:%s ..." %  
     500            (time.strftime("%Y/%m/%d %H:%M:%S",time.gmtime()), 
     501            pop_server,pop_user)) 
     502 
     503        pop = poplib.POP3(pop_server) 
     504        pop.user(pop_user) 
     505        pop.pass_(pop_password) 
     506        num_messages = len(pop.list()[1]) 
     507        counter = 1 
     508        for i in range(num_messages): 
     509            #lines = ['',] 
     510            #for j in pop.retr(i+1)[1]: 
     511            #    lines.append(j + os.linesep) 
     512            #mes_text = ''.join(lines) 
     513            mes_text = ''.join(['%s\n' % line for line in  pop.retr(i+1)[1]]) 
     514            messageid = '' 
     515            exception_flag = False 
     516            try: 
     517                msg = email.message_from_string(mes_text) 
     518                messageid = msg['message-id']  
     519                self.import_message(msg,author,mlid,db) 
     520            except Exception, e: 
     521                exception_flag = True 
     522                self.print_error('Exception At Message-ID:'+messageid) 
     523                self.print_error( e ) 
     524 
     525            #if exception_flag == False: 
     526            #    self.print_info("    Import Message Success") 
     527                 
     528             
     529            # delete mail 
     530            if pop_delete == 'all': 
     531                pop.dele(i+1) 
     532                self.print_info("    Delete MailServer Message ") 
     533            elif pop_delete == 'imported': 
     534                if exception_flag == False: 
     535                    pop.dele(i+1) 
     536                    self.print_info("    Delete MailServer Message ") 
     537            else: 
     538                pass 
     539 
     540            if counter > 10000: 
     541                break 
     542            counter = counter + 1 
     543 
     544        pop.quit() 
     545 
     546        #if handle_ta: 
     547        db.commit() 
     548        self.print_info("End Reciving. "  ) 
     549 
     550    def is_file(self,part ): 
     551        """Return True:filename associated with the payload if present. 
     552        """ 
     553        missing = object() 
     554        filename = part.get_param('filename', missing, 'content-disposition') 
     555        if filename is missing: 
     556            filename = part.get_param('name', missing, 'content-disposition') 
     557        if filename is missing: 
     558            return False 
     559        return True 
     560 
     561    def get_filename(self,part , failobj=None): 
     562        """Return the filename associated with the payload if present. 
     563 
     564        The filename is extracted from the Content-Disposition header's 
     565        `filename' parameter, and it is unquoted.  If that header is missing 
     566        the `filename' parameter, this method falls back to looking for the 
     567        `name' parameter. 
     568        """ 
     569        missing = object() 
     570        filename = part.get_param('filename', missing, 'content-disposition') 
     571        if filename is missing: 
     572            filename = part.get_param('name', missing, 'content-disposition') 
     573        if filename is missing: 
     574            return failobj 
     575         
     576        errors='replace' 
     577        fallback_charset='us-ascii' 
     578        if isinstance(filename, tuple): 
     579            rawval = self.unquote(filename[2]) 
     580            charset = filename[0] or 'us-ascii' 
     581            try: 
     582                return self.to_unicode(rawval, charset) 
     583            except LookupError: 
     584                # XXX charset is unknown to Python. 
     585                return unicode(rawval, fallback_charset, errors) 
     586        else: 
     587            return self.decode_to_unicode(self.unquote(value)) 
     588 
     589    def unquote(self,str): 
     590        """Remove quotes from a string.""" 
     591        if len(str) > 1: 
     592            if str.startswith('"') and str.endswith('"'): 
     593                return str[1:-1].replace('\\\\', '\\').replace('\\"', '"') 
     594            if str.startswith('<') and str.endswith('>'): 
     595                return str[1:-1] 
     596        return str 
     597 
     598    def _delete_message(self,db,id): 
     599        pass 
     600 
     601def run(args): 
     602    """Main entry point.""" 
     603    admin = MailArchiveAdmin() 
     604    if len(args) > 0: 
     605        if args[0] in ('-h', '--help', 'help'): 
     606            return admin.onecmd("help") 
     607        elif args[0] in ('-v','--version','about'): 
     608            return admin.onecmd("about") 
     609        else: 
     610            admin.env_set(os.path.abspath(args[0])) 
     611            if len(args) > 1: 
     612                s_args = ' '.join(["'%s'" % c for c in args[2:]]) 
     613                command = args[1] + ' ' +s_args 
     614                return admin.onecmd(command) 
     615            else: 
     616                while True: 
     617                    admin.run() 
     618    else: 
     619        return admin.onecmd("help") 
     620 
     621sys.exit(run(sys.argv[1:])) 
    86622}}}