; )HEc@sdkZdkZdkZdklZlZlZlZlZlZl Z l Z dk Tdk l Z dklZdklZlZlZlZlZlZlZdklZlZdfdYZd fd YZdS( N(ssplitsjoinsfindslowersrfindsatoisstripslstrip(s*(s_(s TextFormatter(s html_unquotesBLATHERsformattedTracebacks stripLists isIpAddresssisEmailAddresss isUsername(s AUTO_UPGRADEs PAGE_METATYPEsPageSubscriptionSupportcBs4tZdZgZhdd<dd<ddjscCs|ddjS(Nsids subscribers(sx(sx((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pyslssidstypeslinessmodesws"upgraded %s folder subscriber listsfailed to delete %s.subscriberss failed to delete %s._subscriberssupgraded %s subscriber listN(schangedsselfsfoldersaq_basesfsNonesoldsubsshasattrstypes subscriberss StringTypessplitsressubsKeyErrorsBLATHERs _subscribersskeysssubscriber_listsmaps _propertiesspropssfiltersid(sselfsfschangedsoldsubssprops((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pys_upgradeSubscribersDs& %         2 & %         2cCscgi}t|i|D];}| p |ido|t i dd|qq~SdS(s" Return a list of this page's subscribers, without the :edits suffix. A subscriber is represented by a string containing an email address or a CMF username, and an optional :edits suffix indicating they have requested all edits. Note this method strips the :edits suffix. If edits flag is true, return only the subscribers who have requested all edits; otherwise, return all subscribers. If parent flag is true, query the parent folder's subscriber list instead. s:editss:edits$sN( sappends_[1]s stripListsselfs_getSubscriberssparentssseditssendswithsressub(sselfsparentseditss_[1]ss((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pyssubscriberListscCst|i||SdS(s Return the number of subscribers currently subscribed to this page. With parent flag, count the parent folder's subscriber list instead. With edits flag, count only subscribers who have requested all edits. N(slensselfssubscriberListsparentsedits(sselfsparentsedits((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pyssubscriberCountscCs|}|o|i|}|i|}xc|i|D]N}| oq;n|o|i||jp|o ||jodSq;q;WndSdS(sC Is this email address or member id subscribed to this page ? With parent flag, check the parent folder's subscriber list instead. Note "email" may be either an email address (case-insensitive) or a CMF member id. We'll accept either, and find subscriptions using either. iiN( semails subscribersselfsemailAddressFroms usernamesFroms usernamesssubscriberListsparentssub(sselfsemailsparents usernamesssubs subscriber((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pys isSubscribers1cCs|}|o|i|| otd|d|i|odpd|i|}|i ||odpd|i ||| o|i qqn|o,|ii|id|dd|nd S( s' Add an email subscriber to this page. subscriber may be an email address or a CMF member id. With parent flag, add to the parent folder's subscriber list instead. With edits flag, mark this subscriber as one who wants notification of all edits. s subscribedstos (all edits)ss:editss redirectURLsURL1s/subscribeform?email=N(semails subscribersselfs isSubscribersparentsBLATHERsidseditss_getSubscribersssubssappends_setSubscriberss index_objectsREQUESTsRESPONSEsredirectsget(sselfsemailsREQUESTsparentseditsssubss subscriber((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pys subscribescCsti|}|i||o|i|}xW|D]O}|i ||i |jo*t d|d|i |i |q8q8W|i||| o|iqn|o,|ii|id|dd|ndS(s Remove email from this page's subscriber list. email may be an email address or CMF username, we try to convert usernames to email addresses as needed. If parent flag is true, remove it from the parent folder's subscriber list instead. s unsubscribedsfroms redirectURLsURL1s/subscribeform?email=N(sstringslowersemails subscribersselfs isSubscribersparents_getSubscriberssslsssemailAddressFromsBLATHERsidsremoves_setSubscriberss index_objectsREQUESTsRESPONSEsredirectsget(sselfsemailsREQUESTsparents subscriberssssl((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pys unsubscribes cCs|iddd|SdS(s$whole-wiki version of subscriberListsparentiseditsN(sselfssubscriberListsedits(sselfsedits((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pyswikiSubscriberList scCs|iddd|SdS(s%whole-wiki version of subscriberCountsparentiseditsN(sselfssubscriberCountsedits(sselfsedits((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pyswikiSubscriberCountscCs|i|ddSdS(s"whole-wiki version of isSubscribersparentiN(sselfs isSubscribersemail(sselfsemail((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pysisWikiSubscriberscCs |i||ddd|SdS(swhole-wiki version of subscribesparentiseditsN(sselfs subscribesemailsREQUESTsedits(sselfsemailsREQUESTsedits((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pys wikiSubscribescCs|i||ddSdS(s!whole-wiki version of unsubscribesparentiN(sselfs unsubscribesemailsREQUEST(sselfsemailsREQUEST((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pyswikiUnsubscribescCs| odSn|iot|idp|iidt}|o|i|p |i | o|i |ndS(s Subscribe the current user to this page. We'll use their username if appropriate, otherwise their email address cookie. NsAUTHENTICATED_USERsemail( sREQUESTsselfsinCMFsstrsgetscookiessNonesusers isSubscribersisWikiSubscribers subscribe(sselfsREQUESTsuser((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pyssubscribeThisUser s 8(c Cs\|}g}|i|}|i|}|p| ogSn|i|o|idn|i ddgdgfo|i }x|D]n}xe|i D]Z}| oqn|o|i||jp|o ||jo|i|iqqWqWnKxG|iidtD]-\}}|i|o|i|q#q#W|SdS(s Return the ids of all pages to which a subscriber is subscribed ('whole_wiki' indicates a wiki subscription). XXX catalog case duplicates isSubscriber code s whole_wikis meta_typespathssubscriber_listsspecN(semails subscribers subscriptionssselfsemailAddressFroms usernamesFroms usernamessisWikiSubscribersappendshasCatalogIndexesMetadataspagesspagessubscriber_listssubsidsfolders objectItemss PAGE_METATYPEs isSubscriber( sselfsemails usernamesssubs subscriptionss subscribersidspagesspage((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pysallSubscriptionsFor-s0  1  cCse|}|i|}|i}||jo|i|nd|jo|idn|SdS(s Ack, this was too hard in DTML. Return the ids of all pages to which a subscriber is subscribed, excluding the current page and 'whole_wiki'. s whole_wikiN(semails subscribersselfsallSubscriptionsForssubssidsthispagesremove(sselfsemails subscribersthispagessubs((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pysotherPageSubscriptionsForRs   cCs#t|ddodSndSdS(Nsauto_subscribeii(sgetattrsself(sself((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pysautoSubscriptionEnabled_scCs]|io9t|ii}|o|ii o|SqFn|iidt SdS(s If the user is logged into the CMF, return his/her username else return his/her email address cookie. semailN( sselfsinCMFsstrsportal_membershipsgetAuthenticatedMembersusernamesisAnonymousUsersREQUESTsgetsNone(sselfsusername((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pysusernameOrEmailOfSubscriberes   cCs| pt|tjotSntidd|}t|o |}n|i odk l }||d}||d}|i|}| o-t|do|ii|t}qnt|dd}nd}ti|ptSdS( sl Convert a zwiki subscriber list entry to an email address. A zwiki subscriber list entry can be: an email address, or a CMF member id (if we are in a CMF/Plone site), or either of those with ':edits' appended. We figure out the bare email address and return it (lower-cased), or if we can't, return None. s:edits$s(s getToolByNamesportal_membershipsportal_memberdatas_memberssemailN(s subscriberstypes StringTypesNonesressubsisEmailAddresssemailsselfsinCMFsProducts.CMFCore.utilss getToolByNames memberships memberdatas getMemberByIdsmembershasattrs_memberssgetsgetattrsstringslower(sselfs subscribers memberdatas membershipsmembers getToolByNamesemail((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pysemailAddressFromss"    cCsFg}x5|D]-}|i|}|o|i|q q W|SdS(s Convert a list of subscribers to a list of email addresses. Any of these which are usernames for which we can't find an address are converted to an obvious bogus address to help troubleshooting. N(semailss subscriberssssselfsemailAddressFromsesappend(sselfs subscriberssssesemails((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pysemailAddressesFromscCs t|o |gSngSdS(s~ Convert subscriber to username(s) if needed and return as a list. Ie if subscriber is a username, return that username; if subscriber is an email address, return the usernames of any CMF members with that email address. XXX too expensive, disabled; on plone.org with 7k members, this maxed out cpu for 10 minutes. Refactor. N(s isUsernames subscriber(sselfs subscriber((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pys usernamesFroms   (s__name__s __module__s__doc__ssubscriber_lists _propertiess_getSubscriberss_setSubscriberss_resetSubscriberss_upgradeSubscribersssubscriberListssubscriberCounts isSubscribersNones subscribes unsubscribeswikiSubscriberListswikiSubscriberCountsisWikiSubscribers wikiSubscribeswikiUnsubscribessubscribeThisUsersallSubscriptionsForsotherPageSubscriptionsForsautoSubscriptionEnabledsusernameOrEmailOfSubscribersemailAddressFromsemailAddressesFroms usernamesFrom(((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pysPageSubscriptionSupports2 $   d      %   # sPageMailSupportcBstZdZdZdZdZdZdZedZ dZ dZ d Z d Z d Zd Zd d dZdZedZdZd d eeedZd d eeedZd d eeeedZRS(sP This mixin class provides mail-out support and general mail utilities. cCs7|io|ip |iodSndSdS(s/ Has mailout been configured ? iiN(sselfsmailhosts fromPropertysreplyToProperty(sself((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pysisMailoutEnableds'cCst|ddSdS(s> Get my mail-out policy - comments or edits ? smailout_policyscommentsN(sgetattrsself(sself((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pys mailoutPolicyscCst|ddSdS(sg Give the mail_from property for this page. Usually acquires from the folder. s mail_fromsN(sgetattrsself(sself((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pys fromPropertyscCst|ddSdS(sj Give the mail_replyto property for this page. Usually acquires from the folder. s mail_replytosN(sgetattrsself(sself((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pysreplyToPropertyscCst|ddSdS(se Give the mail_to property for this page. Usually acquires from the folder. smail_tosN(sgetattrsself(sself((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pys toPropertyscCsM|ip |i}|i|ddp td}d||fSdS(s Give the appropriate From: header for mail-outs from this page. Tries to give the best attribution based on configuration and available information. XXX todo: use an authenticated CMF member's email property s ip_addressis anonymouss%s (%s)N(sselfs fromPropertysreplyToPropertysaddresss usernameFromsREQUESTs_srealname(sselfsREQUESTsrealnamesaddress((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pys fromHeaders"cCs|ip |iSdS(sU Give the appropriate Reply-to: header for mail-outs from this page. N(sselfsreplyToPropertys fromProperty(sself((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pys replyToHeaderscCs|ip |iSdS(sB Give the "list id" for mail-outs from this page. N(sselfs fromPropertysreplyToProperty(sself((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pyslistIdscCsd|iSdS(sV Give the appropriate List-Post: header for mail-outs from this page. s N(sselfslistId(sself((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pyslistPostHeader scCs!d|ii|ifSdS(sT Give the appropriate List-ID: header for mail-outs from this page. s%s <%s>N(sselfsfolderstitleslistId(sself((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pys listIdHeaderscCs|iSdS(sY Give the appropriate X-Been-There: header for mail-outs from this page. N(sselfslistId(sself((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pysxBeenThereHeaderscCstt|dSdS(s Give the appropriate Bcc: header for mail-outs from this page. Expects a list of recipient addresses. s, N(sjoins stripLists recipients(sselfs recipients((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pys bccHeadersscCst|iddo~|ioF|ii|iddddjot|idd od|i}qd |i}nd }t t|id d ||t |Sd S( s* Give the appropriate Subject: header for mail-outs from this page. - adds a prefix if configured in mail_subject_prefix; - includes page name in brackets unless disabled with mail_page_name - abbreviates issue tracker page names to just the number, except when creating the page or when overridden with mail_issue_name. Temp kludge: we assume the page is being created if it's less than 30s old. (XXX tracker plugin dependency) - appends subjectSuffix if provided smail_page_nameif30.0ii<smail_issue_nameis[#%s] s[%s] ssmail_subject_prefixN( sgetattrsselfsfolders issueNumbersgetPhysicalRootsZopeTimes creationTimespagenamespageNamesstripssubjects subjectSuffix(sselfssubjects subjectSuffixspagename((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pys subjectHeader#s VcCs/|ip|ip|ipdSdS(s Give the appropriate To: header for mail-outs from this page. When sending a mail-out, we put the subscribers in Bcc for privacy. Something is needed in To, what should we use ? 1. if there is a mail_to property, use that 2. if there is a mail_replyto or mail_from property, use that. NB if you use a real address and also subscribe with it you may get duplicates; also when using the wiki mailin address a copy is sent quickly back to the wiki, possible cause of conflicts leading to slow comments ? Not recently. 3. or use ";" which is a legal "nowhere" address but causes messy cc header in replies s;N(sselfs toPropertysreplyToPropertys fromProperty(sself((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pystoHeaderBscCsR|i}|o!|dtidd|7}nt|idd|SdS(s Give the appropriate signature to add to mail-outs from this page. That is: - the contents of the mail_signature property - or a semi-permalink to a comment if its message id is provided - or a link to this page s#msg%ss^<(.*)>$s\1smail_signatures-- forwarded from %sN(sselfspageUrlsurls message_idsressubsgetattrsfolder(sselfs message_idsurl((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pys signatureVs  !cCst}|i}xf| o|o t|doF|iddddg}|o|d}nt|dt}qW|SdS( s Give the MailHost that should be used for sending mail, or None. This needs to just work, as follows: we want to find a real mailhost in a robust way, ie not relying only on a MailHost id, and acquiring it from a parent folder if necessary. NB there are at least two kinds, a MaildropHost can be transaction-safe and prevents duplicates, a MailHost sends immediately and almost never sends duplicates in practice; we won't favour one or the other. So: look for the first object with Maildrop Host or Mail Host meta_type in this folder, then in the parent folder, and so on. s objectValuessspecs Mail HostsSecure Mail Hosts Maildrop Hostis aq_parentN(sNonesmhostsselfsfoldershasattrs objectValuessmhostssgetattr(sselfsmhostsmhostssfolder((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pysmailhostfs  cCse|oZ|i|i|i|id|i||d|d|d|d|d|ndS(s Send mail to this page's and the wiki's subscribers, if any. If a mailhost and mail_from property have been configured and there are subscribers to this page, email text to them. So as not to prevent page edits, catch any mail-sending errors (and log them and try to mail them to an admin). This is used for sending things of interest to all subscribers, like comments and page creations. To reduce noise we apply a few special cases: - if text is empty, don't send - if this is a boring page, don't send to wiki subscribers unless they've requested all edits seditss subjectSuffixssubjects message_ids in_reply_tosexclude_addressN( stextsselfs sendMailTosemailAddressesFromssubscriberListswikiSubscriberListsisBoringsREQUESTs subjectSuffixssubjects message_ids in_reply_tosexclude_address(sselfstextsREQUESTs subjectSuffixssubjects message_ids in_reply_tosexclude_address((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pyssendMailToSubscribers}s.c Cs| odSn|idjo|i|i}n#|idd|idd}|i|i|||d|d|d|d|d|dS( sd Send mail to this page's and the wiki's all edits subscribers, if any. Like sendMailToSubscribers, but sends only to the subscribers who have requested notification of all edits. If text is empty, send nothing. For backwards compatibility, a mailout_policy property with value edits on the wiki folder will override this and send to all subscribers. I think that needs to go away as it makes the user's choice on subscribeform useless. During upgrade we could remove it and convert all subscribers to edits subscribers. Nseditsis subjectSuffixssubjects message_ids in_reply_tosexclude_address(stextsselfs mailoutPolicyssubscriberListswikiSubscriberLists recipientss sendMailTosemailAddressesFromsREQUESTs subjectSuffixssubjects message_ids in_reply_tosexclude_address( sselfstextsREQUESTs subjectSuffixssubjects message_ids in_reply_tosexclude_addresss recipients((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pyssendMailToEditSubscriberss"c Cs|i odSn|p|i|i} |p |i} y|i | Wnt j onX| odSnd|i ||i| |i||i||| |od|pd|i|i|i|i|i|i|i|i||i| f} y4|ii| t d| |i|fWnt d|t!ft"|i#dt$} | oBy#|i&g||dd d | Wqt d t!qXqnXdS( sc Send a mail-out containing text to a list of email addresses. If mail-out is not configured in this wiki or there are no valid recipients, do nothing. Catch and log any errors when sending mail. XXX templatize ? XXX ezmlm won't deliver with precedence: bulk, which these are, what to do NsFrom: %s Reply-To: %s To: %s Bcc: %s Subject: %s Message-ID: %s%s X-Zwiki-Version: %s X-BeenThere: %s List-Id: %s List-Post: %s List-Subscribe: <%s/subscribeform> List-Unsubscribe: <%s/subscribeform> List-Archive: <%s> List-Help: <%s> Content-Type: text/plain; charset="utf-8" %s %s s In-reply-to: %sss(sent mail to subscribers: To: %s Bcc: %ssfailed to send mail to %s: %ss mail_admins subjectSuffixs ERROR, subscriber mailout failedstos(failed to send error report to admin: %s('sselfsisMailoutEnableds message_idsmessageIdFromTimesZopeTimesmsgidstostoHeaderstohdrs recipientssremovesexclude_addresss ValueErrors fromHeadersREQUESTs replyToHeaders bccHeaders subjectHeaderssubjects subjectSuffixs in_reply_tos zwiki_versionsxBeenThereHeaders listIdHeaderslistPostHeaderspageUrlswikiUrlstexts signaturesmsgsmailhostssendsBLATHERsformattedTracebacksgetattrsfoldersNonesadmins sendMailTo(sselfs recipientsstextsREQUESTs subjectSuffixssubjects message_ids in_reply_tostosexclude_addresssadminstohdrsmsgidsmsg((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pys sendMailTos2 '!(s__name__s __module__s__doc__sisMailoutEnableds mailoutPolicys fromPropertysreplyToPropertys toPropertysNones fromHeaders replyToHeaderslistIdslistPostHeaders listIdHeadersxBeenThereHeaders bccHeaders subjectHeaderstoHeaders signaturesmailhostssendMailToSubscribersssendMailToEditSubscriberss sendMailTo(((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pysPageMailSupports(               "(sstringsressysssplitsjoinsfindslowersrfindsatoisstripslstripstypessI18ns_s TextFormattersUtilss html_unquotesBLATHERsformattedTracebacks stripLists isIpAddresssisEmailAddresss isUsernamesDefaultss AUTO_UPGRADEs PAGE_METATYPEsPageSubscriptionSupportsPageMailSupport(s PAGE_METATYPEslstripsformattedTracebacks stripListsstripsPageSubscriptionSupportsfindsisEmailAddresss AUTO_UPGRADEsressplits isIpAddresss TextFormattersstrings html_unquotessyssatois isUsernames_sBLATHERslowersjoinsPageMailSupportsrfind((s4/mnt/gmirror/ports/www/zope-zwiki/work/ZWiki/Mail.pys?s7  1