@@ -205,119 +205,58 @@ def munge_from_header(mlist, msg, msgdata):
205205 change_header ('From' , new_from , mlist , msg , msgdata )
206206
207207def prefix_subject (mlist , msg , msgdata ):
208- # Add the subject prefix unless the message is a digest or is being fast
209- # tracked (e.g. internally crafted, delivered to a single user such as the
210- # list admin).
208+ """Add the list's subject prefix to the message's Subject: header."""
209+ # Get the subject and charset
210+ subject = msg .get ('subject' , '' )
211+ if not subject :
212+ return
213+
214+ # Get the list's charset
215+ cset = mlist .preferred_language
216+
217+ # Get the prefix
211218 prefix = mlist .subject_prefix .strip ()
212219 if not prefix :
213220 return
214- subject = msg .get ('subject' , '' )
215- # Try to figure out what the continuation_ws is for the header
216- if isinstance (subject , Header ):
217- lines = str (subject ).splitlines ()
218- else :
219- lines = subject .splitlines ()
220- ws = ' '
221- if len (lines ) > 1 and lines [1 ] and lines [1 ][0 ] in ' \t ' :
222- ws = lines [1 ][0 ]
223- msgdata ['origsubj' ] = subject
224- # The subject may be multilingual but we take the first charset as major
225- # one and try to decode. If it is decodable, returned subject is in one
226- # line and cset is properly set. If fail, subject is mime-encoded and
227- # cset is set as us-ascii. See detail for ch_oneline() (CookHeaders one
228- # line function).
229- subject , cset = ch_oneline (subject )
230- # TK: Python interpreter has evolved to be strict on ascii charset code
231- # range. It is safe to use unicode string when manupilating header
232- # contents with re module. It would be best to return unicode in
233- # ch_oneline() but here is temporary solution.
234- subject = str (subject , cset )
235- # If the subject_prefix contains '%d', it is replaced with the
236- # mailing list sequential number. Sequential number format allows
237- # '%d' or '%05d' like pattern.
238- prefix_pattern = re .escape (prefix )
239- # unescape '%' :-<
240- prefix_pattern = '%' .join (prefix_pattern .split (r'\%' ))
241- p = re .compile (r'%\d*d' )
242- if p .search (prefix , 1 ):
243- # prefix have number, so we should search prefix w/number in subject.
244- # Also, force new style.
245- prefix_pattern = p .sub (r'\s*\d+\s*' , prefix_pattern )
246- old_style = False
247- else :
248- old_style = mm_cfg .OLD_STYLE_PREFIXING
249- subject = re .sub (prefix_pattern , '' , subject )
250- # Previously the following re didn't have the first \s*. It would fail
251- # if the incoming Subject: was like '[prefix] Re: Re: Re:' because of the
252- # leading space after stripping the prefix. It is not known what MUA would
253- # create such a Subject:, but the issue was reported.
254- rematch = re .match (
255- r'(\s*(RE|AW|SV|VS)\s*(\[\d+\])?\s*:\s*)+' ,
256- subject , re .I )
257- if rematch :
258- subject = subject [rematch .end ():]
259- recolon = 'Re:'
260- else :
261- recolon = ''
262- # Strip leading and trailing whitespace from subject.
263- subject = subject .strip ()
264- # At this point, subject may become null if someone post mail with
265- # Subject: [subject prefix]
266- if subject == '' :
267- # We want the i18n context to be the list's preferred_language. It
268- # could be the poster's.
269- otrans = i18n .get_translation ()
270- i18n .set_language (mlist .preferred_language )
271- subject = _ ('(no subject)' )
272- i18n .set_translation (otrans )
273- cset = Utils .GetCharSet (mlist .preferred_language )
274- subject = str (subject , cset )
275- # and substitute %d in prefix with post_id
221+
222+ # Handle the subject encoding
276223 try :
277- prefix = prefix % mlist .post_id
278- except TypeError :
279- pass
280- # If charset is 'us-ascii', try to concatnate as string because there
281- # is some weirdness in Header module (TK)
282- if cset == 'us-ascii' :
283- try :
284- if old_style :
285- h = u' ' .join ([recolon , prefix , subject ])
286- else :
287- if recolon :
288- h = u' ' .join ([prefix , recolon , subject ])
289- else :
290- h = u' ' .join ([prefix , subject ])
291- h = h .encode ('us-ascii' )
292- h = uheader (mlist , h , 'Subject' , continuation_ws = ws )
293- change_header ('Subject' , h , mlist , msg , msgdata )
294- ss = u' ' .join ([recolon , subject ])
295- ss = ss .encode ('us-ascii' )
296- ss = uheader (mlist , ss , 'Subject' , continuation_ws = ws )
297- msgdata ['stripped_subject' ] = ss
298- return
299- except UnicodeError :
300- pass
301- # Get the header as a Header instance, with proper unicode conversion
302- # Because of rfc2047 encoding, spaces between encoded words can be
303- # insignificant, so we need to append spaces to our encoded stuff.
304- prefix += ' '
305- if recolon :
306- recolon += ' '
307- if old_style :
308- h = uheader (mlist , recolon , 'Subject' , continuation_ws = ws )
309- h .append (prefix )
310- else :
311- h = uheader (mlist , prefix , 'Subject' , continuation_ws = ws )
312- h .append (recolon )
313- # TK: Subject is concatenated and unicode string.
314- subject = subject .encode (cset , 'replace' )
315- h .append (subject , cset )
316- change_header ('Subject' , h , mlist , msg , msgdata )
317- ss = uheader (mlist , recolon , 'Subject' , continuation_ws = ws )
318- ss .append (subject , cset )
319- msgdata ['stripped_subject' ] = ss
320-
224+ # If subject is already a string, use it directly
225+ if isinstance (subject , str ):
226+ subject_str = subject
227+ else :
228+ # Try to decode the subject
229+ try :
230+ subject_str = str (subject , cset )
231+ except (UnicodeError , LookupError ):
232+ # If that fails, try utf-8
233+ subject_str = str (subject , 'utf-8' , 'replace' )
234+ except Exception as e :
235+ mailman_log ('error' , 'Error decoding subject: %s' , str (e ))
236+ return
237+
238+ # Add the prefix if it's not already there
239+ if not subject_str .startswith (prefix ):
240+ msg ['Subject' ] = prefix + ' ' + subject_str
241+
242+ # Mark message as processed
243+ mailman_log ('debug' , 'CookHeaders: Adding X-BeenThere header for message %s' , msgid )
244+ change_header ('X-BeenThere' , mlist .GetListEmail (),
245+ mlist , msg , msgdata , delete = False )
246+
247+ # Add standard headers
248+ mailman_log ('debug' , 'CookHeaders: Adding standard headers for message %s' , msgid )
249+ change_header ('X-Mailman-Version' , mm_cfg .VERSION ,
250+ mlist , msg , msgdata , repl = False )
251+ change_header ('Precedence' , 'list' ,
252+ mlist , msg , msgdata , repl = False )
253+
254+ # Handle From: header munging if needed
255+ if (msgdata .get ('from_is_list' ) or mlist .from_is_list ) and not msgdata .get ('_fasttrack' ):
256+ mailman_log ('debug' , 'CookHeaders: Munging From header for message %s' , msgid )
257+ munge_from_header (mlist , msg , msgdata )
258+
259+ mailman_log ('debug' , 'CookHeaders: Finished processing message %s' , msgid )
321260
322261def ch_oneline (headerstr ):
323262 # Decode header string in one line and convert into single charset
0 commit comments