##############################################################################     
#      
# Zope Public License (ZPL) Version 0.9.7     
# ---------------------------------------     
#      
# Copyright (c) Digital Creations.  All rights reserved.     
#      
# This license has been certified as Open Source(tm).     
#      
# Redistribution and use in source and binary forms, with or without     
# modification, are permitted provided that the following conditions are     
# met:     
#      
# 1. Redistributions in source code must retain the above copyright     
#    notice, this list of conditions, and the following disclaimer.     
#      
# 2. Redistributions in binary form must reproduce the above copyright     
#    notice, this list of conditions, and the following disclaimer in     
#    the documentation and/or other materials provided with the     
#    distribution.     
#      
# 3. Digital Creations requests that attribution be given to Zope     
#    in any manner possible. Zope includes a "Powered by Zope"     
#    button that is installed by default. While it is not a license     
#    violation to remove this button, it is requested that the     
#    attribution remain. A significant investment has been put     
#    into Zope, and this effort will continue if the Zope community     
#    continues to grow. This is one way to assure that growth.     
#      
# 4. All advertising materials and documentation mentioning     
#    features derived from or use of this software must display     
#    the following acknowledgement:     
#      
#      "This product includes software developed by Digital Creations     
#      for use in the Z Object Publishing Environment     
#      (http://www.zope.org/)."     
#      
#    In the event that the product being advertised includes an     
#    intact Zope distribution (with copyright and license included)     
#    then this clause is waived.     
#      
# 5. Names associated with Zope or Digital Creations must not be used to     
#    endorse or promote products derived from this software without     
#    prior written permission from Digital Creations.     
#      
# 6. Modified redistributions of any form whatsoever must retain     
#    the following acknowledgment:     
#      
#      "This product includes software developed by Digital Creations     
#      for use in the Z Object Publishing Environment     
#      (http://www.zope.org/)."     
#      
#    Intact (re-)distributions of any official Zope release do not     
#    require an external acknowledgement.     
#      
# 7. Modifications are encouraged but must be packaged separately as     
#    patches to official Zope releases.  Distributions that do not     
#    clearly separate the patches from the original work must be clearly     
#    labeled as unofficial distributions.  Modifications which do not     
#    carry the name Zope may be packaged in any form, as long as they     
#    conform to all of the clauses above.     
#      
#      
# Disclaimer     
#      
#   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY     
#   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE     
#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR     
#   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS     
#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,     
#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT     
#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF     
#   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND     
#   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,     
#   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT     
#   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF     
#   SUCH DAMAGE.     
#      
#      
# This software consists of contributions made by Digital Creations and     
# many individuals on behalf of Digital Creations.  Specific     
# attributions are listed in the accompanying credits file.     
#      
##############################################################################     
#      
# Portions Copyright (c) 1999 by Butch Landingin.     
#      
# Redistribution and use in source and binary forms, with or without     
# modification, are permitted provided that the following conditions     
# are met:     
# 1. Redistributions of source code must retain the above copyright     
#    including the original copyright, this copyright notice, the list of      
#    conditions and the following disclaimer.     
# 2. Redistributions in binary form must reproduce the above copyright     
#    including the original copyright, this copyright notice, the list of      
#    conditions and the following disclaimer in the     
#    documentation and/or other materials provided with the distribution.     
# 3. The name of the author may not be used to endorse or promote products     
#    derived from this software without specific prior written permission     
#     
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR     
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES     
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.     
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,     
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT     
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY     
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT     
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF     
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
#       
#  In accordance with the license provided for by the software upon     
#  which some of the source code has been derived or used, the following      
#  acknowledgement is hereby provided :     
#     
#      "This product includes software developed by Digital Creations     
#      for use in the Z Object Publishing Environment     
#      (http://www.zope.org/)."     
#      
##############################################################################     
"""Squishdot - a web-based news publishing and discussion system"""
     
__version__='$Revision: 1.17 $'[11:-2]     
     
import sys, re    
from Globals import Persistent     
from Globals import PersistentMapping     
from Globals import HTMLFile ,MessageDialog     
from OFS.ObjectManager import ObjectManager     
from AccessControl.Role import RoleManager     
from SearchIndex.TextIndex import TextIndex     
from SearchIndex.Index import Index     
from IOBTree import BTree     
from intSet import intSet     
from Squishfile import Squishfile     
from OFS.Folder import Folder    
from Acquisition import Implicit     
from time import time, localtime, strftime, gmtime     
from string import strip,split,join     
from string import lower,rfind,atoi, replace    
from urllib import quote, unquote     
from DocumentTemplate.DT_Util import html_quote    
from OFS.Document import Document     
     
CRLF=re.compile('\r\n\|\n\r')    
tagRegex = re.compile("<.*?>")     
    
class Stack:     
    def __init__(self):     
        self.mlist = []     
    def pop(self):     
        data = self.mlist[-1]     
        del self.mlist[-1]     
        return data     
    def push(self,data):     
        self.mlist.append(data)     
    def isEmpty(self):     
        return (len(self.mlist) == 0)     
     
def sameday(n, m):     
    n = localtime(n)     
    m = localtime(m)     
    if m[0] == n[0] and m[1] == n[1] and m[2] == n[2]:     
        return 1     
    else:     
        return 0     
     
def addDTML(obj,id,title,file):     
    f=open('%s/Products/%s.dtml' % (SOFTWARE_HOME,file))     
    file=f.read()     
    f.close()     
    obj.manage_addDTMLMethod(id,title,file)     
    return getattr(obj,id)     
     
def addImage(obj,id,file):     
    f=open('%s/Products/%s' % (SOFTWARE_HOME,file),'rb')     
       
    contents=f.read()     
    f.close()     
    title=''     
    tlen = len(contents)     
    new_id = obj.manage_addImage(id,contents,title=title)   
    img_obj = obj.__getitem__(new_id)  
    img_obj.content_type = 'image/gif'  
    
     
def addTable(obj,id,fname):     
    file=open('%s/Products/%s.tbl' % (SOFTWARE_HOME,fname))     
    cols=file.readline()     
    cols=cols[:-1] # takeout newline     
    delim=file.readline()     
    delim=delim[:-1]     
    fcontent=file.read()     
    file.close()     
    title=''     
    obj.manage_addTinyTable(id,title,delim,cols)     
    tbl=getattr(obj,id)     
    tbl.manage_editData(fcontent)     
     
def addNewTable(obj,id,fname):     
    file=open('%s/Products/%s.tbl' % (SOFTWARE_HOME,fname))     
    cols=file.readline()     
    cols=cols[:-1] # takeout newline     
    fcontent=file.read()     
    file.close()     
    title=''     
    obj.manage_addTinyTable(id,title,cols)     
    tbl=getattr(obj,id)     
    tbl.manage_editData(fcontent)     
     
def addArt(obj,file):     
    f=open('%s/Products/%s' % (SOFTWARE_HOME,file))     
    file=''     
    title = f.readline()[:-1] # removes newline char     
    subject = f.readline()[:-1]     
    author = f.readline()[:-1]     
    email = f.readline()[:-1]     
    notify= f.readline()[:-1]     
    dept=f.readline()[:-1]     
    summary=''     
    currline=f.readline()     
    while strip(currline) <> '%%' and currline <> '':     
        summary = summary + currline     
        currline=f.readline()     
    body=''     
    currline=f.readline()     
    while strip(currline) <> '%%' and currline <> '':     
        body = body + currline     
        currline=f.readline()     
    f.close()     
    
    id =  obj.addPosting(title,author,body,email,notify,file,summary,subject,dept,None,None,1)     
    msg = obj.data[id]     
    msg.reviewed = 1     
    return id     
     
PATH_SEP=re.compile('[\\/]')      
    
def addFile(file, ctype):     
    try:     
        f = open('%s/Products/%s' % (SOFTWARE_HOME,file),'rb')     
    except:     
        return ''     
    sf = Squishfile()     
    sf._file = f.read()     
    f.close()     
    name=strip(PATH_SEP.split(file)[-1])     
    sf._name = name     
    sf._ctype = ctype           
    sf._created = time()     
    sf._modified = sf._created     
    return sf     
    
htmlhead =  '''<html><head><title>%s</title>  
<body><pre>    
'''    
    
htmlend = '''   
</pre></body></html>    
'''    
    
def addText(file,title):    
    global htmlhead, htmlend     
    try:     
        f = open('%s/Products/%s' % (SOFTWARE_HOME,file),'rb')     
    except:     
        return htmlhead + htmlend         
    s = f.read()     
    f.close()     
    return (htmlhead % title) + html_quote(s) + htmlend    
    
readme = addText('Squishdot/README.txt','Readme')    
credits = addText('Squishdot/Credits.txt','Credits')    
license = addText('Squishdot/License.txt','License')    
changes = addText('Squishdot/Changes.txt','Changes')    
version = addText('Squishdot/version.txt','Version')    
    
about = '''<html><head><title>About Squishdot</title></head>     
<body>    
<h3>About Squishdot</h3>    
<p>    
copyright (c) 1999 by Butch Landingin    
<p>    
<ul>    
<li><a href="Readme">Readme.txt</a>     
<li><a href="Credits">Credits.txt</a>     
<li><a href="License">License.txt</a>     
<li><a href="Changes">Changes.txt</a>     
<li><a href="Version">version.txt</a>     
</ul>    
</body></html>    
'''    
    
class SquishSite(Folder, RoleManager):     
    """ """     
    meta_type  ='Squishdot Site'     
    description='Squishdot Site'     
     
    icon       ='misc_/Squishdot/squishdot_img'     
    root       =1     
    squishlogo ='misc_/Squishdot/squishlogo'    
    
    _properties=({'id':'title', 'type':'string','mode':'w'},)     
     
    manage_postings=HTMLFile('Squishdot_manage_postings', globals())     
    manage_editForm=HTMLFile('Squishdot_editForm', globals())     
    manage_subjects=HTMLFile('Squishdot_manage_subjects', globals())    
       
    About = Document(about, __name__='About')    
    Readme = Document(readme, __name__='Readme')    
    Credits = Document(credits, __name__='Credits')    
    License = Document(license, __name__='License')    
    Changes = Document(changes, __name__='Changes')    
    Version = Document(version, __name__='Version')    
    About.__roles__=None    
    Readme.__roles__=None    
    Credits.__roles__=None    
    License.__roles__=None    
    Changes.__roles__=None    
    Version.__roles__=None    
    
    manage_options=({'label':'Contents', 'icon':icon,     
                     'action':'manage_main', 'target':'manage_main'},     
                    {'label':'Postings', 'icon':'',     
                     'action':'manage_postings', 'target':'manage_main'},     
                    {'label':'Subjects', 'icon':'',     
                     'action':'manage_subjects', 'target':'manage_main'},     
                     {'label':'Options', 'icon':'',     
                     'action':'manage_editForm', 'target':'manage_main'},     
                    {'label':'Properties', 'icon':'',     
                     'action':'manage_propertiesForm', 'target':'manage_main'},     
                    {'label':'Security', 'icon':'',     
                     'action':'manage_access', 'target':'manage_main'},     
                    {'label':'Undo', 'icon':'',     
                     'action':'manage_UndoForm','target':'manage_main'},     
                    )     
     
    __ac_permissions__=Folder.__ac_permissions__+(     
        ('Manage postings', ['manage_main','manage_edit', 'manage_delete', 'delete_subjects','add_subject',    
                             'manage_postings','manage_editForm','manage_subjects']),     
        ('Add postings', ['addPosting'], ('Anonymous', 'Manager')),     
        )     
        
        
    def __init__(self, id, title, mhost, exp, moderated, max_itemlist, default_doc):     
        t=time()     
        self.id       = id     
        self.title    = title     
        self.created  = t     
        self.modified = t     
        self.mail_host= mhost     
        self.expire   = exp     
     
        self.moderated= 0     
        self.mod_comment = 0     
        if moderated == 'both':     
            self.moderated = 1     
            self.mod_comment= 1     
        else:     
            if moderated == 'articles':     
                self.moderated = 1     
                self.mod_comment=0     
     
        if max_itemlist:     
            self.max_itemlist=max_itemlist     
        else:     
            self.max_itemlist=30     
     
        self.data     =BTree()  # id -> Message     
        self.ids      =intSet() # ids of children     
        self.subjects = PersistentMapping()     
     
        self.indices=PersistentMapping({'author': Index(),     
                                        'body'  : TextIndex(),     
                                        'title' : TextIndex(),     
                                        'subject': Index(),     
                                       })     
        self.subjindexes = PersistentMapping({'summary': TextIndex(),})     
                                                 
        for k in self.indices.keys():     
            self.indices[k]._init(self.data,None,k)     
        for k in self.subjindexes.keys():     
            self.subjindexes[k]._init(self.data,None,k)     
     
     
        self.defaultDocFile('validateArticle','Validate Article',     
                            'Squishdot/validArticle')     
        self.defaultDocFile('validateComment','Validate Comment',     
                            'Squishdot/validComment')     
        self.defaultDocFile('showMessage','Show Message',     
                            'Squishdot/showMessage')     
        self.defaultDocFile('showError','Show Error',     
                            'Squishdot/showError')     
        self.defaultDocFile('rdf','Netscape RDF/RSS channel page',     
                            'Squishdot/Squishdot_rdf_rss')     
    
        newprop = list(self._properties)     
        newprop.append({'id':'rss_description', 'type': 'string', 'mode': 'w'})     
        newprop.append({'id':'rss_title', 'type': 'string', 'mode': 'w'})     
        newprop.append({'id':'rss_image_url', 'type': 'string', 'mode': 'w'})     
    
        if default_doc == 'plain':     
            self.defaultDocFile('mail_html','Notification Email',     
                                'Squishdot/Squishdot_mail_html')     
            self.defaultDocFile('index_html','Squishdot Homepage',     
                                'Squishdot/Squishdot_index_html')     
            self.defaultDocFile('posting_html','Posting',     
                                'Squishdot/Squishdot_posting_html')     
            self.defaultDocFile('searchForm','Search Form',     
                                'Squishdot/Squishdot_searchForm')     
            self.defaultDocFile('searchResults','Search Results',     
                                'Squishdot/Squishdot_searchResults')     
            self.defaultDocFile('addPostingForm','Add Posting Form',     
                                'Squishdot/addPostingForm')     
            self.defaultDocFile('previewPosting','Preview Posting',     
                                'Squishdot/Squishdot_previewForm')     
            self._properties = tuple(newprop)     
            self._updateProperty('rss_image_url','')      
     
        if default_doc == 'demo1' or default_doc == 'demo2':     
            load_tbls = 1     
            tblver=''     
            try:     
                # check if TinyTable product exists     
                file = 'TinyTable/About'     
                f=open('%s/Products/%s.dtml' % (SOFTWARE_HOME,file))     
                f.close()      
                #     
                file = 'TinyTable/version.txt'     
                f=open('%s/Products/%s' % (SOFTWARE_HOME,file))     
                tblver=f.readline()     
                f.close()     
                tblver=tblver[:-1] #takeout newline     
            except:     
                load_tbls = 0     
     
            #spew('load tbl : ' + str(load_tbls))         
            self.defaultDocFile('mail_html','Notification Email',     
                                'Squishdot/demo/Squishdot_mail_html')     
            self.defaultDocFile('index_html','Squishdot Homepage',     
                                'Squishdot/demo/Squishdot_index_html')     
            self.defaultDocFile('posting_html','Posting',     
                                'Squishdot/demo/Squishdot_posting_html')     
            self.defaultDocFile('searchForm','Search Form',     
                                'Squishdot/demo/Squishdot_searchForm')     
            self.defaultDocFile('searchResults','Search Results',     
                                'Squishdot/demo/Squishdot_searchResults')     
            self.defaultDocFile('addPostingForm','Add Posting Form',     
                                'Squishdot/demo/addPostingForm')     
      
            self.defaultDocFile('site_footer','Site Footer',     
                                'Squishdot/demo/site_footer')     
            self.defaultDocFile('site_header','Site Header',     
                                'Squishdot/demo/site_header')     
            self.defaultDocFile('previewPosting','Preview Posting',     
                                'Squishdot/demo/Squishdot_previewForm')     
     
            self.manage_addFolder('Images','Images')     
            self.manage_addFolder('TopicImages','Topic Images')     
            self.manage_addFolder('misc_methods','Misc. methods')     
            self.manage_addFolder('rightbox_methods','Right box methods')     
     
            curr_folder =  getattr(self,'misc_methods')     
            addDTML(curr_folder,'advertising','advertising','Squishdot/demo/misc_methods/advertising')     
            addDTML(curr_folder,'copyright_notice','copyright','Squishdot/demo/misc_methods/copyright')     
            addDTML(curr_folder,'quotation','quotation','Squishdot/demo/misc_methods/quotation')     
     
            curr_folder =  getattr(self,'rightbox_methods')     
            feat_method = addDTML(curr_folder,'features','Features','Squishdot/demo/rightbox_methods/features')     
            prev_method = addDTML(curr_folder,'prev_articles','Previous Articles','Squishdot/demo/rightbox_methods/prevarticles')     
            quik_method = addDTML(curr_folder,'quick_links','Quick Links','Squishdot/demo/rightbox_methods/quicklinks')     
            rfc_method = addDTML(curr_folder,'request_comments','Requests for Comments','Squishdot/demo/rightbox_methods/reqcomments')     
            rev_method = addDTML(curr_folder,'reviews','Reviews','Squishdot/demo/rightbox_methods/reviews')     
     
            curr_folder =  getattr(self,'Images')     
            addImage(curr_folder,'botshadow_img','Squishdot/demo/Images/botshadow.gif')     
            addImage(curr_folder,'roundedge_img','Squishdot/demo/Images/roundedge.gif')     
            addImage(curr_folder,'rtbotshadow_img','Squishdot/demo/Images/rtbotshadow.gif')     
            addImage(curr_folder,'rtshadow_img','Squishdot/demo/Images/rtshadow.gif')     
            addImage(curr_folder,'sitetitle_img','Squishdot/demo/Images/sitetitle.gif')     
            addImage(curr_folder,'bluepix_img','Squishdot/demo/Images/bluepix.gif')     
            addImage(curr_folder,'greenpix_img','Squishdot/demo/Images/greenpix.gif')     
            addImage(curr_folder,'advert_img','Squishdot/demo/Images/advert.gif')     
     
            curr_folder =  getattr(self,'TopicImages')     
            # note: build images      
            addImage(curr_folder,'dc_img',  'Squishdot/demo/TopicImages/dc.gif')     
            addImage(curr_folder,'zope_img','Squishdot/demo/TopicImages/zope.gif')     
            addImage(curr_folder,'dtml_img','Squishdot/demo/TopicImages/dtml.gif')     
            addImage(curr_folder,'help_img','Squishdot/demo/TopicImages/help.gif')     
            addImage(curr_folder,'squishdot_img','Squishdot/demo/TopicImages/squish.gif')     
            addImage(curr_folder,'zopedev_img','Squishdot/demo/TopicImages/zopedev.gif')     
            addImage(curr_folder,'zdp_img','Squishdot/demo/TopicImages/zdp.gif')     
            addImage(curr_folder,'zserver_img','Squishdot/demo/TopicImages/zserver.gif')     
            addImage(curr_folder,'dope_img','Squishdot/demo/TopicImages/dope.gif')     
     
            if load_tbls and tblver:                     
                if tblver[10:] > '0-8-0':     
                    addNewTable(self,'bottom_items','Squishdot/demo/newtables/bottom_items')     
                    addNewTable(self,'leftbox_items','Squishdot/demo/newtables/leftbox_items')     
                    addNewTable(self,'rightbox_items','Squishdot/demo/newtables/rightbox_items')     
                else:     
                    addTable(self,'bottom_items','Squishdot/demo/bottom_items')     
                    addTable(self,'leftbox_items','Squishdot/demo/leftbox_items')     
                    addTable(self,'rightbox_items','Squishdot/demo/rightbox_items')     
     
            newprop.append({'id':'color1', 'type': 'string', 'mode': 'w'})     
            newprop.append({'id':'color2', 'type': 'string', 'mode': 'w'})     
            newprop.append({'id':'color3', 'type': 'string', 'mode': 'w'})     
            newprop.append({'id':'linedot_image', 'type': 'string', 'mode': 'w'})     
            newprop.append({'id':'color4', 'type': 'string', 'mode': 'w'})     
            newprop.append({'id':'color5', 'type': 'string', 'mode': 'w'})     
            newprop.append({'id':'drop_shadow', 'type': 'int', 'mode': 'w'})     
            newprop.append({'id':'round_edge', 'type': 'int', 'mode': 'w'})     
            newprop.append({'id':'title_image', 'type': 'string', 'mode': 'w'})     
            newprop.append({'id':'site_name', 'type': 'string', 'mode': 'w'})     
            newprop.append({'id':'comment_spillover', 'type': 'int', 'mode': 'w'})     
            newprop.append({'id':'prevday_cnt', 'type': 'int', 'mode': 'w'})     
            newprop.append({'id':'admin_address', 'type': 'string', 'mode': 'w'})     
            newprop.append({'id':'admin_name', 'type': 'string', 'mode': 'w'})     
            self._properties = tuple(newprop)     
            self._updateProperty('color1','#000000')      
            self._updateProperty('color2','#ffffff')      
            if default_doc == 'demo1':     
                self._updateProperty('color3','#006666')      
                self._updateProperty('linedot_image','Images/greenpix_img')      
            else:     
                self._updateProperty('color3','#0066cc')      
                self._updateProperty('linedot_image','Images/bluepix_img')      
            self._updateProperty('color4','#cccccc')      
            self._updateProperty('color5','#333333')      
            self._updateProperty('drop_shadow',1)      
            self._updateProperty('round_edge',1)      
            self._updateProperty('title_image','Images/sitetitle_img')      
            self._updateProperty('site_name','Squishdot')      
            self._updateProperty('comment_spillover',10)      
            self._updateProperty('prevday_cnt',7)      
            self._updateProperty('admin_address','squishdot@yahoo.com')     
            self._updateProperty('admin_name','the ZopeMeister')     
            self._updateProperty('rss_image_url','Images/sitetitle_img')      
     
            self.add_subject('Zope','TopicImages/zope_img')     
            self.add_subject('Zope DTML','TopicImages/dtml_img')     
            self.add_subject('Help','TopicImages/help_img')     
            self.add_subject('Digital Creations','TopicImages/dc_img')     
            self.add_subject('Squishdot','TopicImages/squishdot_img')     
            self.add_subject('Zope Development','TopicImages/zopedev_img')     
            self.add_subject('Zope Doc Project','TopicImages/zdp_img')     
            self.add_subject('ZServer','TopicImages/zserver_img')     
            self.add_subject('Zope Dopes','TopicImages/dope_img')     
     
     
            id10 = addArt(self,'Squishdot/demo/messages/message10.txt')     
            id9 = addArt(self,'Squishdot/demo/messages/message9.txt')     
            id8 = addArt(self,'Squishdot/demo/messages/message8.txt')     
            id7 = addArt(self,'Squishdot/demo/messages/message7.txt')     
            id6 = addArt(self,'Squishdot/demo/messages/message6.txt')     
            id5 = addArt(self,'Squishdot/demo/messages/message5.txt')     
            id4 = addArt(self,'Squishdot/demo/messages/message4.txt')     
            id3 = addArt(self,'Squishdot/demo/messages/message3.txt')     
            id2 = addArt(self,'Squishdot/demo/messages/message2.txt')     
            id1 = addArt(self,'Squishdot/demo/messages/message1.txt')     
            raw = feat_method.raw % (str(id1),str(id2),str(id5))     
            feat_method.raw = raw     
            raw = rfc_method.raw % str(id3)     
            rfc_method.raw = raw     
            art8 = self.data[id8]     
            file8 = addFile('Squishdot/demo/messages/images.zip','application/x-zip-compressed')     
            if file8:     
                setattr(art8,file8._name,file8)     
                art8.file=file8     
            else:     
                art8.file=''     
    
        #set rss related properties          
        self._updateProperty('rss_description','Squishdot: Cool Dope on Zope')      
        self._updateProperty('rss_title',title)      
    
    def __len__(self): return 1     
     
    def __getitem__(self,n):     
        try:    id=atoi(n)     
        except: raise AttributeError, n     
        if self.ids.has_key(id):     
            return self.data[id].__of__(self)     
        raise AttributeError, n     
     
    def dupString(self, dstr, count):     
        ''' returns a duplicate of dstr by count times (should really be a util function)'''     
        return dstr * count     
    
    def striptags(self,s):    
        ''' removes char sequences that invalidate RSS syntax (should really be a util function)'''     
        return tagRegex.sub("",s)    
    
     
    def has_subjects(self):     
        ''' returns true if site has subject topics defined'''     
        return len(self.subjects)     
     
    def subject_count(self):     
        ''' gives count of subject topics defined'''     
        return self.has_subjects()     
     
    def add_subject(self,subject='', imgurl='', REQUEST=None,RESPONSE=None):     
        """ add a subject topic """     
        if subject is None:     
            return MessageDialog(title='Data Missing',     
                                 message='You must enter a subject!',     
                                 action=REQUEST['URL1']+'/manage_subjects',     
                                 target='manage_main'     
                                )     
        self.subjects[subject]= imgurl     
        self._p_changed = 1    
     
        if REQUEST:     
            return self.manage_subjects(self, REQUEST)     
     
    def delete_subjects(self,subjs=[],REQUEST=None):     
        """ delete a subject topic"""     
        for subj in subjs:     
            del self.subjects[subj]     
        self._p_changed = 1    
        if REQUEST:     
            return self.manage_subjects(self, REQUEST)     
     
    def subjects_list(self):     
        ''' lists all subjects '''    
        subjects = self.subjects.keys()    
        subjects.sort()    
        return subjects    
     
    def subject_image(self,subj):     
        ''' returns an image url associated with the subject (can be an empty string)'''     
        if self.subjects.has_key(subj):     
            return self.subjects[subj]     
        else:     
            return ''     
     
    def setItem(self,id,obj):     
        # Make sure the object we store is not wrapped with     
        # an acquisition wrapper, since we will be wrapping     
        # it again manually in __getitem__ when it is needed.     
        if hasattr(obj, 'aq_base'):     
            obj=obj.aq_base     
        self.ids.insert(id)     
        self.data[id]=obj     
        for k in self.indices.keys():     
            self.indices[k].index_item(id)     
        for k in self.subjindexes.keys():     
            self.subjindexes[k].index_item(id)     
     
    def delItem(self,id):     
        data=self.data     
        item=data[id]     
        if self.ids.has_key(id): self.ids.remove(id)     
        else: data[item.thread[-1]].ids.remove(id)     
        if self.moderated:     
            if item.meta_type == 'Article':     
                if not item.reviewed:     
                    for t in item.thread:     
                        obj=self.data[t]     
                        if obj.revsub > 0: obj.revsub=obj.revsub-1     
                else:     
                    for t in item.thread:     
                        obj=self.data[t]     
                        if obj.reply_cnt > 0: obj.reply_cnt = obj.reply_cnt-1     
            else:     
                if self.mod_comment:     
                    if not item.reviewed:     
                        for t in item.thread:     
                            obj=self.data[t]     
                            if obj.revsub > 0: obj.revsub=obj.revsub-1     
                    else:     
                        for t in item.thread:     
                            obj=self.data[t]     
                            if obj.reply_cnt > 0: obj.reply_cnt = obj.reply_cnt-1     
                else:     
                    for t in item.thread:     
                        obj=self.data[t]     
                        if obj.reply_cnt > 0: obj.reply_cnt = obj.reply_cnt-1     
     
        else:     
            for t in item.thread:     
                obj=self.data[t]     
                if obj.reply_cnt > 0: obj.reply_cnt = obj.reply_cnt-1     
        ids=intSet()     
        ids.insert(id)     
        ids=item.sub_ids(ids,data)     
        item=None     
        for index in self.indices.values():     
            for id in ids:     
                try:    index.unindex_item(id)     
                except: pass     
                     
        for index in self.subjindexes.values():     
            for id in ids:     
                try:    index.unindex_item(id)     
                except: pass     
        for id in ids:     
            del data[id]     
     
    def createId(self):     
        id=int(time())     
        while 1:     
            try:    o=self.data[id]     
            except: break     
            id=id+1     
        return id     
     
    def defaultDocFile(self,id,title,file):     
        f=open('%s/Products/%s.dtml' % (SOFTWARE_HOME,file))     
        file=f.read()     
        f.close()     
        self.manage_addDTMLMethod(id,title,file)     
     
    def postingValues(self):     
        """ return list of articles """     
        return map(lambda x, p=self: x.__of__(p), self.data.map(self.ids))     
     
    def rev_id_list(self):     
        """ returns reversed id list of reviewed articles  """     
        rlist = map(None,self.ids)     
        rlist = filter(lambda x,p=self : p.data[x].reviewed, rlist)     
        rlist.reverse()     
        return rlist     
     
    def item_list(self):     
        """ returns latest articles  """                          
        currtime =   int(time())     
        return map(lambda x, p=self: x.__of__(p), self.data.map(self.id_list(currtime)))     
     
    def id_list(self, currtime):     
        ''' returns id list of latest articles at currtime '''     
        rlist = self.rev_id_list()     
        max = self.max_itemlist     
        min = max / 3     
        rlen = len(rlist)     
        if rlen <= min:     
            pass # take all elements     
        else:     
            today_list = self.date_id_list(currtime)  # take only items from today     
            tlen = len(today_list)     
            if tlen <= min:     
                rlist = rlist[:min] # take minimum elements even though some items came from yesterday     
            else:     
                if tlen >= max:     
                    rlist = today_list[:max]  # take maximum elements from today                        
                else:     
                    rlist = today_list # take entire list of items from today     
        return rlist     
             
    def other_id_list(self, currtime):     
        '''returns id list of articles exceeding max but still within current day'''      
        today_list = self.date_id_list(currtime) # take only items from today     
        tlen = len(today_list)     
        curr_list = self.id_list(currtime)  # take items displayed on main page     
        clen = len(curr_list)     
        if tlen > clen:     
            return today_list[clen:]  # return items from today not displayed on main page     
        else:     
            return []     
     
    def other_list(self):     
        """returns articles exceeding max but still within current day"""     
        currtime =   int(time())     
        return map(lambda x,  p=self: x.__of__(p), self.data.map(self.other_id_list(currtime)))     
     
    def date_id_list(self, currtime):     
        """returns list from sameday """     
        rlist = self.rev_id_list()     
        return filter(lambda x,p=currtime: sameday(x,p), rlist)     
             
    def date_list(self, day=0):     
        """return list from day """     
        currtime = int(time())  - (86400 * day)     
        return map(lambda x,  p=self: x.__of__(p), self.data.map(self.date_id_list(currtime)))     
     
    def site_id_list(self, currtime):     
        """ returns latest id list from currtime  """     
        ilist = self.id_list(currtime)     
        tdict = {}     
        tlist = []     
        ilen = len(ilist)     
        cnt = 0      
        while (cnt < ilen) and (len(tdict) < 5):     
            id = ilist[cnt]     
            item = self.data[id]     
            if tdict.has_key(item.subject):     
                pass     
            else:     
                tdict[item.subject] = id     
                tlist.append(id)     
            cnt = cnt + 1     
     
        return tlist     
     
    def site_item_list(self):     
        """ returns latest articles from today """     
        currtime =   int(time())     
        return map(lambda x, p=self: x.__of__(p), self.data.map(self.site_id_list(currtime)))     
            
     
    def tpId(self):     
        return self.id     
     
    def tpURL(self):     
        return self.id     
     
    def this(self):     
        return self     
     
    def site(self):     
        return (self,)     
     
    def site_url(self):    
        """ url of the Squishdot main page """ 
        req=self.REQUEST     
        par=req['PARENTS']     
        url=req['URL1']    
        mylist = par[:-1]     
        mystr = ''     
        for p in mylist:     
            if p.meta_type == 'Squishdot Site':    
                p = rfind(url,mystr)    
                if p >= 0:    
                    urlstr = url[:p]    
                else:    
                    raise "Squishdot site_url could not compute site_url"    
                return urlstr    
            else:    
                mystr = '/' +  str(p.id) +  mystr     
    
        raise " Squishdot site_url:could not find site"    
        return ""
        #url = self.REQUEST['URL1']    
        #return url     
     
    def has_items(self):     
        return len(self.ids)     
     
    def item_count(self):     
        return len(self.data)     
     
    def mailhost_list(self):     
        try:    return self.superValues(('Mail Host',))     
        except: return []     
     
    def desc_items(self):     
        """ articles in descending order """     
        mlist = []     
        mstack = Stack()     
        if self.has_items():     
            plist = []     
            for id in self.ids:     
                plist.append(id)     
            plist.reverse()     
            for id in plist:     
                mstack.push(id)     
            while not mstack.isEmpty():     
                item_id = mstack.pop()     
                item = self.data[item_id]     
                mlist.append(item)     
                if item.has_items():     
                    plist = []     
                    for id in item.ids:     
                        plist.append(id)     
                    plist.reverse()     
                    for id in plist:     
                        mstack.push(id)     
                        
        return map((lambda x, p=self: x.__of__(p)), mlist)     
           
    def expire_items(self):     
        """ run to delete articles which are past their expiration (assuming that it has been set)"""     
        if self.expire:     
            d=self.data     
            t=int(time()-(self.expire * 86400.0))     
            ids=[]     
            for id in d.keys():     
                if d[id].modified < t:     
                    ids.append(id)     
            for id in ids:     
                try:    self.delItem(id)     
                except: pass     
        return ''     
     
    def addPosting(self,title,author,body,email='',notify='',file='',     
                   summary='',subject='',dept='',REQUEST=None,RESPONSE=None,internal=0):     
        """ add an article """     
        title =strip(title)     
        author=strip(author)     
        email =strip(email)     
        summary = strip(summary)     
        if summary:     
            summary  =split(CRLF.sub('\n',summary),'\n')     
        else:     
            summary = None     
        subject =strip(subject)     
        dept =strip(dept)     
        body = strip(body)     
        if body:     
            body  =split(CRLF.sub('\n',body),'\n')     
        else:     
            body = None     
        notify=notify             
        reviewed=(not self.moderated) and 1 or 0     
    
        if not internal:     
            message=self.validateArticle(REQUEST=REQUEST,title=title,author=author,    
                                        email=email,summary=summary,dept=dept,body=body,notify=notify)     
            if message:     
                return self.showError(REQUEST=REQUEST,title='Data Missing',     
                                      message=message,     
                                      action=REQUEST['URL1']+'/previewPosting'     
                                     )     
     
        try:    file=Squishfile(file)     
        except: file=''     
     
        id=self.createId()     
        msg=Article(id,intSet(),title,author,body,email,notify,reviewed,file,subject,dept,summary)     
        msg=msg.__of__(self)      
        self.setItem(id,msg)     
        self.expire_items()     
     
        if REQUEST:     
            p='%s%s' % (REQUEST['SCRIPT_NAME'],REQUEST['PATH_INFO'])     
            sn = REQUEST['SCRIPT_NAME']     
            pi = REQUEST['PATH_INFO']     
            t=self.id     
            p=p[:(rfind(p,t)+len(t))]  + '/'     
            gtime = gmtime(id)     
            glist = list(gtime)     
            glist[0] = glist[0] + 1 # add 1 year to expiry date     
            glist[1] = 12     
            glist[2] = 31     
            glist[3] = 23     
            glist[4] = 59     
            glist[5] = 59     
            glist[6] = 0     
            glist[7] = 365     
            glist[8] = 0     
            gtime = tuple(glist)     
            e = strftime('%A, %d-%b-%y %H:%M:%S GMT',gtime)     
            resp=REQUEST['RESPONSE']     
            author = quote(author)    
            resp.setCookie('_suggest_author',author,path=p,expires=e)     
            email = quote(email)    
            resp.setCookie('_suggest_email',email,path=p,expires=e)     
            resp.setCookie('suggest_notify',notify,path=p,expires=e)     
            if self.moderated:     
                p2 = "%s/index_html" % self.site_url()     
            else:     
                p2 = "%s/%s/index_html" % (self.site_url(),id)     
            return self.showMessage(title='Article Posted',     
                                 message='Your article has been posted',     
                                 action=p2     
                                )     
        if internal:     
            return id     
     
    def search(self,REQUEST):     
        """ fulfill a search request """     
        sr=self.__call__(REQUEST,1)     
        rc=len(sr)     
        return self.searchResults(self,REQUEST,search_results=sr,     
                                  result_count=rc)     
     
     
    def manage_edit(self,mailhost='',exp=0,expire='0',moderated='none', max_itemlist=30,     
                    REQUEST=None):     
        """ edit SquishDot options  """     
        if exp: expire=atoi(expire)     
        else:   expire=0     
        if mailhost:     
            try:    v=getattr(self, mailhost)     
            except:      
                return MessageDialog(title='Invalid Mail Host',     
                                     message='Cannot find the named mail host!',     
                                     action=REQUEST['URL']+'/manage_main'     
                                    )     
        self.mail_host=mailhost     
        self.expire   =expire     
     
        if moderated == 'both':     
            self.moderated = 1     
            self.mod_comment= 1     
        else:     
            if moderated == 'articles':     
                self.moderated = 1     
                self.mod_comment=0     
            else:     
                if moderated == 'none':     
                    self.moderated = 0     
                    self.mod_comment = 0     
     
        if max_itemlist:     
            self.max_itemlist=max_itemlist     
        else:     
            self.max_itemlist=30     
        return self.manage_main(self, REQUEST)     
     
    def manage_delete(self,ids=[],REQUEST=None):     
        """ delete Squishdot site """     
        ids=map(atoi, ids)     
        while ids:     
            self.delItem(ids[-1])     
            del ids[-1]     
        return self.manage_postings(self, REQUEST)     
     
        
    # Searchable interface     
     
    def __call__(self, REQUEST=None, internal=0):     
        if REQUEST is None: REQUEST=self.REQUEST     
        myid=self.id     
        rset=None     
        sset=None     
        used={}     
        body = ''     
        try:     
            body = REQUEST['body']     
        except:     
            pass     
        if body is not None:     
            REQUEST.set('summary',body)     
            i = self.subjindexes['summary']     
            try:     
                r=i._apply_index(REQUEST,myid)     
                if r is not None:     
                    sset,u = r     
            except: pass     
                 
        for k in self.indices.keys():     
            i = self.indices[k]     
            try:     
                r=i._apply_index(REQUEST,myid)     
                if r is not None:     
                    r,u=r     
                    if k == 'body' and sset is not None:     
                        r = r.union(sset)                         
                    if rset is None: rset=r     
                    else: rset=rset.intersection(r)     
            except: pass     
     
                         
        if rset is None:     
            r=[]     
        else:     
            r=self.data.map(rset)     
            if self.moderated:     
                r=filter(lambda x: x.reviewed, r)     
            op = ''     
            try:     
                op = REQUEST['op']     
            except:     
                pass     
            if op == 'articles':     
                r = filter(lambda x: x.meta_type == 'Article', r)     
            r=map(lambda x, p=self: x.__of__(p), r)     
     
        if internal: return r     
        return SquishSet(r)     
     
    def _searchable_result_columns(self):     
        return ({'name':'title', 'type':'s'},     
                {'name':'author','type':'s'},     
                {'name':'body',  'type':'s'},     
                {'name':'email', 'type':'s'},     
               )     
     
    def _searchable_arguments(self):     
        return {'author': {'type':'string', 'optional':1, 'indexed':1},     
                'body':   {'type':'string', 'optional':0, 'indexed':1},     
                'title':   {'type':'string', 'optional':0, 'indexed':1},     
                'subject':   {'type':'string', 'optional':0, 'indexed':1},     
               }     
     
    def suggest_author(self):    
        author = ''    
        try: author = self.REQUEST.cookies['_suggest_author']    
        except: pass    
        if author : author = unquote(author)    
        return author or None    
    
    def suggest_email (self):    
        email  = ''    
        try: email  = self.REQUEST.cookies['_suggest_email']    
        except: pass    
        if email  : email  = unquote(email)    
        return email  or None    
     
class SquishItem:     
    def __init__(self,data):     
        self._data=data     
     
    _schema=['title','author','body','email','subject']     
     
    def __getattr__(self,key):     
        if key=='body':     
            return join(self._data.body,'<BR>')     
        return getattr(self._data, key)     
     
    def __getitem__(self,key,inttype=type(0)):     
        try:     
            if type(key) is inttype:     
                return getattr(self._data,self._schema[key])     
            return getattr(self._data, key)     
        except (IndexError, KeyError):     
            raise AttributeError, key     
     
    def __len__(self):     
        return len(self._schema)     
     
     
     
class SquishSet:     
    def __init__(self,data):     
        self._data=map(SquishItem, data)     
     
    def __getitem__(self,index):     
        return self._data[index]     
         
    def __len__(self):     
        return len(self._data)     
     
    def __getslice__(self,i1,i2):     
        return self._data[i1:i2]     
     
    slice=__getslice__     
    _searchable_result_columns=SquishSite._searchable_result_columns     
     
     
     
class Posting(Persistent, Implicit):     
    """ """     
    manage_editForm=HTMLFile('editPostingForm', globals())      
    manage         =manage_editForm     
    manage_main    =manage_editForm     
    meta_type='Posting'     
    icon   ='misc_/Squishdot/posting_img'     
    root=0     
    
    def __init__(self, id, thread, title, author, body,     
                 email, notify, reviewed, file, subject,level):     
        self.id      =str(id)     
        self.ids     =intSet()     
        self.thread  =thread     
        self.title   =title     
        self.author  =author     
        self.body    =body     
        self.email   =email     
        self.notify  =notify     
        self.created =id     
        self.modified=id     
        self.reviewed=reviewed     
        self.subject =subject     
        self.level =level     
        if file:     
            setattr(self,file._name,file)     
            self.file=file     
        else:     
            self.file=''     
        self.revsub  =0     
        self.reply_cnt =0     
     
    def __len__(self): return 1     
     
    def __getitem__(self,n):     
        try:    id=atoi(n)     
        except: raise AttributeError, n     
        if self.ids.has_key(id):     
            return self.data[id].__of__(self)     
        raise AttributeError, n     
     
    def setItem(self,id,obj):     
        # Make sure the object we store is not wrapped with     
        # an acquisition wrapper, since we will be wrapping     
        # it again manually in __getitem__ when it is needed.     
        if hasattr(obj, 'aq_base'):     
            obj=obj.aq_base     
     
        self.ids.insert(id)     
        self.data[id]=obj     
        for k in self.indices.keys():     
            self.indices[k].index_item(id)     
     
    def dupString(self, dstr, count):     
        return dstr * count     
    
    def striptags(self,s):    
        ''' removes char sequences that invalidate RSS syntax (should really be a util function)'''     
        return tagRegex.sub("",s)    
    
     
    def date_posted(self,fmstr='%A %B %d, @%I:%M%p'):     
        """ date when article was posted """     
        ltime = localtime(self.created)         
        return strftime(fmstr,ltime)     
             
    def body_len(self,divisor=None):     
        """ total body length of text """    
        tlen = 0     
        if not self.body:     
            tlen = 0    
        else:    
            for line in self.body:     
                tlen = tlen + len(line)    
    
        if divisor is None:    
            if tlen == 0:    
                return ''    
            if tlen > 51200:     
                tlen = tlen / 1024     
                return str(tlen) + ' Kb'     
            else:     
                return str(tlen) + ' bytes'     
    
        if divisor < 1:    
            return tlen    
        else:    
            return tlen/divisor    
                    
    def postingValues(self):     
        """ return all replies """     
        return map(lambda x, p=self: x.__of__(p), self.data.map(self.ids))     
     
    def tpId(self):     
        return self.id     
     
    def tpURL(self):     
        return self.id     
     
    def this(self): return self     
         
    def has_items(self):     
        return len(self.ids)     
     
    def sub_ids(self,ids,data):     
        map(ids.insert, self.ids)     
        for item in data.map(self.ids):     
            ids=item.sub_ids(ids,data)     
        return ids     
     
    def desc_items(self):     
        """ return latest list of replies """     
        mlist = []     
        mstack = Stack()     
        if self.has_items():     
            plist = []     
            for id in self.ids:     
                plist.append(id)     
            plist.reverse()     
            for id in plist:     
                mstack.push(id)     
            while not mstack.isEmpty():     
                item_id = mstack.pop()     
                item = self.data[item_id]     
                mlist.append(item)     
                if item.has_items():     
                    plist = []     
                    for id in item.ids:     
                        plist.append(id)     
                    plist.reverse()     
                    for id in plist:     
                        mstack.push(id)     
        return map((lambda x, p=self: x.__of__(p)), mlist)     
     
    def date_created(self):     
        """ date article was created """     
        t=localtime(self.created)     
        return '%d/%d/%d' % (t[1],t[2],t[0])     
     
    def time_created(self):     
        """ time article was created """     
        t=localtime(self.created)     
        return '%02d:%02d' % (t[3],t[4])     
     
    def attachment(self):     
        """ file attachment """     
        file=self.file     
        return file and (file,) or None     
     
    def suggest_title(self):     
        """ suggested title of reply """     
        t=self.title     
        return (lower(t[:3])=='re:') and t or 'Re: %s' % t     
     
    def thread_path(self):     
        return join(map(lambda x: '/%s' % x, self.thread), '')     
     
    def index_html(self,REQUEST):     
        """ squishdot article main page (the read more page) """    
        return self.posting_html(self,REQUEST)     
     
    def doNotify(self, msg, REQUEST):     
        """ sends mail to notify person being replied to """     
        if self.notify and self.email and self.mail_host:     
            mail =self.mail_html(self, REQUEST, newItem=(msg,))     
            mhost=getattr(self,self.mail_host)     
            mhost.send(mail)     
     
    def cancelNotify(self, REQUEST):     
        """ cancels email notification of replies """     
        self.notify=''     
        return self.showMessage(title='Cancelled Notification',     
                             message='You will no longer be notified of replies to this message',     
                             action=self.site_url()     
                            )     
     
    def addPosting(self,title,author,body,email='',notify='',file='',     
                   REQUEST=None,RESPONSE=None):     
        """ add a reply """     
        title   =strip(title)     
        author  =strip(author)     
        email   =strip(email)     
        body    =strip(body)     
        notify  =notify     
        reviewed=(not self.mod_comment) and 1 or 0     
     
        message=self.validateComment(REQUEST=REQUEST,title=title,author=author,    
                                     email=email,body=body,notify=notify)    
     
        if message:    
            return self.showError(REQUEST=REQUEST,title='Data Missing',     
                                 message=message,     
                                 action=REQUEST['URL1'] + '/previewPosting'     
                                )     
        if body:     
            body = split(CRLF.sub('\n',body),'\n')     
        else:     
            body = None     
      
        try:    file=Squishfile(file)     
        except: file=''     
     
        id=self.createId()     
        thread=intSet()     
        map(thread.insert, self.thread)     
        thread.insert(atoi(self.id))     
        for t in thread:     
            obj=self.data[t]     
            obj.modified=id     
            if not reviewed:     
                obj.revsub=obj.revsub+1     
            else:     
                obj.reply_cnt = obj.reply_cnt+1     
     
        msg=Comment(id, thread, title, author, body, email, notify,     
                  reviewed, file, self.subject, self.level+1)     
        msg=msg.__of__(self)    
        self.setItem(id, msg)     
     
        if REQUEST:     
            try:    self.doNotify(msg,REQUEST)     
            except: pass     
     
            p='%s%s' % (REQUEST['SCRIPT_NAME'],REQUEST['PATH_INFO'])     
            t=self.site()[0].id     
            p=p[:(rfind(p,t)+len(t))]  + '/'      
            gtime = gmtime(id)     
            glist = list(gtime)     
            glist[0] = glist[0] + 1 # add 1 year to expiry date     
            glist[1] = 12     
            glist[2] = 31     
            glist[3] = 23     
            glist[4] = 59     
            glist[5] = 59     
            glist[6] = 0     
            glist[7] = 365     
            glist[8] = 0     
            gtime = tuple(glist)     
            e = 'Friday, 31-Dec-99 23:59:59 GMT'     
            e = strftime('%A, %d-%b-%y %H:%M:%S GMT',gtime)     
            resp=REQUEST['RESPONSE']     
            author = quote(author)    
            resp.setCookie('_suggest_author',author,path=p,expires=e)     
            email = quote(email)    
            resp.setCookie('_suggest_email',email,path=p,expires=e)     
            resp.setCookie('suggest_notify',notify,path=p,expires=e)     
            if self.mod_comment:     
                p2 = "%s%s/%s/posting_html" % (self.site_url(),self.thread_path(),self.id)     
            else:     
                p2 = "%s%s/%s/%s/posting_html" % (self.site_url(),self.thread_path(),self.id,id)     
            return self.showMessage(title='Comment Posted',     
                                 message='Your comment has been posted',     
                                 action=p2     
                                )     
     
    def manage_edit(self,title,author,body,email='',notify='',reviewed='',     
                    REQUEST=None,RESPONSE=None):     
        """ edit replies """     
    
        id = self.id     
        title = strip(title)     
        author = strip(author)     
        email = strip(email)     
    
        message=self.validateComment(REQUEST=REQUEST,title=title,author=author,    
                                     email=email,body=body,notify=notify)    
     
        if message:     
            return self.showError(REQUEST=REQUEST,title='Data Missing',     
                                 message=message,     
                                 action=REQUEST['URL1']+'/manage_editForm'     
                                )     
    
        body = split(CRLF.sub('\n',body),'\n')     
     
        for index in self.indices.values():               
            try:    index.unindex_item(id)     
            except: pass     
                     
        self.title =title     
        self.author=author     
        self.email =email     
        self.body  =body     
        self.notify=notify             
     
        for index in self.indices.values():               
            try:    index.index_item(id)     
            except: pass     
     
     
        if self.mod_comment and (not self.reviewed) and reviewed:     
            self.reviewed=1     
            for t in self.thread:     
                obj=self.data[t]     
                if obj.revsub > 0: obj.revsub=obj.revsub-1     
                obj.reply_cnt = obj.reply_cnt+1     
     
        if RESPONSE:     
            RESPONSE.redirect('%s/manage_postings' % self.site_url())     
     
     
class Article(Posting):     
    """ """     
    meta_type  ='Article'     
    icon   ='misc_/Squishdot/posting_img'     
    def __init__(self, id, thread, title, author, body,     
                 email, notify, reviewed, file, subject, dept, summary ):     
        Posting.__init__(self,id,thread,title,author,body,     
                 email, notify, reviewed, file, subject,0)     
        self.summary = summary     
        self.dept = dept     
             
    def manage_edit(self,title,author,body,email='',notify='',reviewed='', subject='', dept='', summary='',     
                    REQUEST=None,RESPONSE=None):     
        """ edit an article """     
        title =strip(title)     
        author=strip(author)     
        email =strip(email)     
        subject =strip(subject)     
        dept =strip(dept)    
    
        message=self.validateArticle(REQUEST=REQUEST,title=title,author=author,    
                                     email=email,summary=summary,dept=dept,body=body,notify=notify)    
    
        if message:     
            return self.showError(REQUEST=REQUEST,title='Data Missing',     
                                 message=message,     
                                 action=REQUEST['URL1']+'/manage_editForm'     
                                )     
        id = self.id     
        body  =split(CRLF.sub('\n',body),'\n')     
        summary  =split(CRLF.sub('\n',summary),'\n')     
     
        for index in self.indices.values():                 
            try:    index.unindex_item(id)     
            except: pass                     
        for index in self.subjindexes.values():                 
            try:    index.unindex_item(id)     
            except: pass     
     
        self.title =title     
        self.author=author     
        self.email =email     
        self.body  =body     
        self.summary  =summary     
        self.subject =subject     
        self.dept =dept     
        self.notify=notify     
     
        for index in self.indices.values():     
            try:    index.index_item(id)     
            except: pass     
        for index in self.subjindexes.values():     
            try:    index.index_item(id)     
            except: pass     
     
        if self.moderated and (not self.reviewed) and reviewed:     
            self.reviewed=1     
            for t in self.thread:     
                obj=self.data[t]     
                if obj.revsub > 0: obj.revsub=obj.revsub-1     
                obj.reply_cnt = obj.reply_cnt+1     
     
        if RESPONSE:     
            RESPONSE.redirect('%s/manage_postings' % self.site_url())     
     
     
    def prev_item(self):     
        """ return previous id in the item list"""     
        parent = self.site()[0]     
        currtime = int(time())     
        rlist = list(parent.id_list(currtime))     
        currpos = 0     
        try:     
            currpos = rlist.index(int(self.id))     
        except:     
            currpos = -1     
        if (currpos == 0) or (currpos < 0):     
            return None     
        else:     
            previd = rlist[currpos - 1]     
            obj = self.data[previd]     
            return (obj.__of__(self),)     
     
    def next_item(self):     
        """ return next id in the item list """     
        parent = self.site()[0]     
        currtime = int(time())     
        rlist = list(parent.id_list(currtime))     
        currpos = 0     
        try:     
            currpos = rlist.index(int(self.id))     
        except:     
            currpos = -1     
        lastpos = len(rlist) - 1     
        if (currpos == lastpos) or (currpos < 0):     
            return None     
        else:     
            nextid = rlist[currpos + 1]     
            obj = self.data[nextid]     
            return (obj.__of__(self),)     
     
     
class Comment(Posting):     
    """ """     
    meta_type  ='Comment'     
    icon       ='misc_/Squishdot/comment_img'     
     
     
     
     
def manage_addSquishdot(self,id,title='',mailhost='',exp=0,expire='0',     
                              moderated=0, max_itemlist=30, default_doc='', REQUEST=None):     
    """Create Squishdot Site"""     
    if exp:     
        try:    expire=atoi(expire)     
        except: expire=0     
    else:   expire=0     
    if mailhost:     
        try:    v=getattr(self, mailhost)     
        except: return MessageDialog(title='Invalid Mail Host',     
                                     message='Cannot find the named mail host!',     
                                     action=REQUEST['URL1']+'/manage_main'     
                                    )     
    ob=SquishSite(id, title, mailhost, expire, moderated, max_itemlist, default_doc)         
    self._setObject(id, ob)     
     
    if REQUEST: return self.manage_main(self,REQUEST,update_menu=1)  
