From steve@cat-box.net Mon Apr 1 09:53:10 2002 From: steve@cat-box.net (Steve Alexander) Date: Mon, 1 Apr 2002 04:53:10 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/Image/Views/Browser - edit.pt:1.1.2.2 Message-ID: <200204010953.g319rAP18663@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/Image/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv17619/lib/python/Zope/App/OFS/Content/Image/Views/Browser Modified Files: Tag: Zope-3x-branch edit.pt Log Message: Changed here -> context and container -> view as described in http://collector.zope.org/Zope3-dev/43 === Zope3/lib/python/Zope/App/OFS/Content/Image/Views/Browser/edit.pt 1.1.2.1 => 1.1.2.2 ===

-

+

Description of the Form.

@@ -41,11 +41,11 @@ Size + tal:content="context/getImageSize"> - + Title From steve@cat-box.net Mon Apr 1 09:53:10 2002 From: steve@cat-box.net (Steve Alexander) Date: Mon, 1 Apr 2002 04:53:10 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/File - edit.pt:1.1.2.2 Message-ID: <200204010953.g319rAd18651@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File In directory cvs.zope.org:/tmp/cvs-serv17619/lib/python/Zope/App/OFS/Content/File Modified Files: Tag: Zope-3x-branch edit.pt Log Message: Changed here -> context and container -> view as described in http://collector.zope.org/Zope3-dev/43 === Zope3/lib/python/Zope/App/OFS/Content/File/edit.pt 1.1.2.1 => 1.1.2.2 === -

+

Message will go here.

-

+

Description of the Form.

@@ -38,7 +38,7 @@ - + + === Zope3/lib/python/Zope/App/OFS/Container/Views/Browser/main.pt 1.1.2.2 => 1.1.2.3 === (may be None) --> - +
Title Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv17619/lib/python/Zope/App/OFS/Container/Views/Browser Modified Files: Tag: Zope-3x-branch add.pt main.pt Log Message: Changed here -> context and container -> view as described in http://collector.zope.org/Zope3-dev/43 === Zope3/lib/python/Zope/App/OFS/Container/Views/Browser/add.pt 1.1.2.1 => 1.1.2.2 === (may be None) --> -
Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv17619/lib/python/Zope/App/OFS/Content/File/Views/Browser Modified Files: Tag: Zope-3x-branch edit.pt Log Message: Changed here -> context and container -> view as described in http://collector.zope.org/Zope3-dev/43 === Zope3/lib/python/Zope/App/OFS/Content/File/Views/Browser/edit.pt 1.1.2.1 => 1.1.2.2 === -

+

Message will go here.

-

+

Description of the Form.

@@ -38,7 +38,7 @@ - + \n%s \n' TABLE='\n
Title Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv17619/lib/python/Zope/App/OFS/Content/ZPTPage/Views/Browser Modified Files: Tag: Zope-3x-branch ZPTPageEval.py edit.pt Log Message: Changed here -> context and container -> view as described in http://collector.zope.org/Zope3-dev/43 === Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views/Browser/ZPTPageEval.py 1.1.2.1 => 1.1.2.2 === } if inst is not None: - c['here'] = inst.getContext() - c['container'] = inst + c['context'] = inst.getContext() + c['view'] = inst c['views'] = ViewMapper(inst.getContext(), REQUEST) return c === Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views/Browser/edit.pt 1.1.2.1 => 1.1.2.2 === -

+

Message will go here.

-

+

Description of the Form.

@@ -39,7 +39,7 @@ - + From casey@zope.com Fri Apr 12 20:25:48 2002 From: casey@zope.com (Casey Duncan) Date: Fri, 12 Apr 2002 15:25:48 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.467 Message-ID: <200204121925.g3CJPmQ12370@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv12251/doc Modified Files: CHANGES.txt Log Message: Fix for Bug#96: Narrower/Wider buttons now work in CSS browsers. This is only in affect for DTML thus far. === Zope/doc/CHANGES.txt 1.466 => 1.467 === Bugs: + + - Fixed bug #96: Narrower/Wider buttons now work on both CSS and non-CSS + compliant browsers. This allows better control for browsers that have a + hard time knowing what 100% means. - Fix for Collector #319: filtered_manage_options didn't correctly filter tabs based on permission. From casey@zope.com Fri Apr 12 20:25:48 2002 From: casey@zope.com (Casey Duncan) Date: Fri, 12 Apr 2002 15:25:48 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - DTMLMethod.py:1.76 Message-ID: <200204121925.g3CJPmq12371@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv12251/lib/python/OFS Modified Files: DTMLMethod.py Log Message: Fix for Bug#96: Narrower/Wider buttons now work in CSS browsers. This is only in affect for DTML thus far. === Zope/lib/python/OFS/DTMLMethod.py 1.75 => 1.76 === rows=max(1,int(dtpref_rows)+dr) - cols=max(40,int(dtpref_cols)+dc) + cols=max(35,int(dtpref_cols)+dc) e=(DateTime('GMT') + 365).rfc822() resp=REQUEST['RESPONSE'] resp.setCookie('dtpref_rows',str(rows),path='/',expires=e) @@ -231,7 +231,7 @@ self,REQUEST,title=title,__str__=self.quotedHTML(data), dtpref_cols=cols,dtpref_rows=rows) - def manage_edit(self,data,title,SUBMIT='Change',dtpref_cols='50', + def manage_edit(self,data,title,SUBMIT='Change',dtpref_cols='70', dtpref_rows='20',REQUEST=None): """ Replaces a Documents contents with Data, Title with Title. From chrism@zope.com Fri Apr 12 20:26:50 2002 From: chrism@zope.com (Chris McDonough) Date: Fri, 12 Apr 2002 15:26:50 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/ZCatalog - CatalogPathAwareness.py:1.8 __init__.py:1.19 Message-ID: <200204121926.g3CJQo313284@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/ZCatalog In directory cvs.zope.org:/tmp/cvs-serv13270 Modified Files: CatalogPathAwareness.py __init__.py Log Message: Register CatalogPathAware (a bare subclass of CatalogPathAwareness .CatalogAware) as a ZClass base class. Its reason for existence is to make the name that shows up in the ZClass Product list different than 'ZCatalog: CatalogAware', which is the name registered by CatalogAwareness.CatalogAware. The fix should *really* be to change the product registry to keep the whole module/class path and to make the ZClass add UI show the whole path, but this is nontrivial, we don't want to spend a lot of time on ZClasses, and this works. Now when we tell people to use CatalogPathAware instead of CatalogAware, they will actually be able to do it without a lot of effort. The reason we can't replace CatalogAware with CatalogPathAware is backwards-compatibility and the desire to not force people to do data conversion on their existing instances. === Zope/lib/python/Products/ZCatalog/CatalogPathAwareness.py 1.7 => 1.8 === return 'done!' +class CatalogPathAware(CatalogAware): + """ + This is a stub class that gets registered in __init__.py as a + ZClass base class. Its reason for existance is to make the name + that shows up in the ZClass Product list different than 'ZCatalog: + CatalogAware', which is the name registered by + CatalogAwareness.CatalogAware. The fix should *really* be to + change the product registry to keep the whole module/class path + and to make the ZClass add UI show the whole path, but this is + nontrivial, we don't want to spend a lot of time on ZClasses, and + this works. + """ === Zope/lib/python/Products/ZCatalog/__init__.py 1.18 => 1.19 === """ZCatalog product""" -import ZCatalog, Catalog, CatalogPathAwareness, ZClasses +import ZCatalog, Catalog, CatalogAwareness, CatalogPathAwareness, ZClasses from Products.PluginIndexes.TextIndex import Vocabulary from ZClasses import createZClassForBase createZClassForBase( ZCatalog.ZCatalog , globals() , 'ZCatalogBase', 'ZCatalog' ) -createZClassForBase( CatalogPathAwareness.CatalogAware, globals() +createZClassForBase( CatalogAwareness.CatalogAware, globals() , 'CatalogAwareBase', 'CatalogAware' ) +createZClassForBase( CatalogPathAwareness.CatalogPathAware, globals() + , 'CatalogPathAwareBase', 'CatalogPathAware' ) def initialize(context): context.registerClass( From shane@cvs.zope.org Fri Apr 12 20:34:11 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 15:34:11 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - ObjectManager.py:1.145.16.2 Message-ID: <200204121934.g3CJYB114796@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv14684 Modified Files: Tag: Zope-2_5-branch ObjectManager.py Log Message: Collector #167: made superValues() include items with duplicated IDs. === Zope/lib/python/OFS/ObjectManager.py 1.145.16.1 => 1.145.16.2 === seen={} vals=[] + relativePhysicalPath = () have=seen.has_key x=0 while x < 100: @@ -399,13 +400,17 @@ for i in obj._objects: try: id=i['id'] - if (not have(id)) and (i['meta_type'] in t): + physicalPath = relativePhysicalPath + (id,) + if (not have(physicalPath)) and (i['meta_type'] in t): vals.append(get(id)) - seen[id]=1 + seen[physicalPath]=1 except: pass - if hasattr(obj,'aq_parent'): obj=obj.aq_parent - else: return vals + if hasattr(obj,'aq_parent'): + obj=obj.aq_parent + relativePhysicalPath = ('..',) + relativePhysicalPath + else: + return vals x=x+1 return vals From shane@cvs.zope.org Fri Apr 12 20:35:30 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 15:35:30 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - ObjectManager.py:1.149 Message-ID: <200204121935.g3CJZUg14903@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv14891 Modified Files: ObjectManager.py Log Message: Collector #167 === Zope/lib/python/OFS/ObjectManager.py 1.148 => 1.149 === seen={} vals=[] + relativePhysicalPath = () have=seen.has_key x=0 while x < 100: @@ -422,13 +423,17 @@ for i in obj._objects: try: id=i['id'] - if (not have(id)) and (i['meta_type'] in t): + physicalPath = relativePhysicalPath + (id,) + if (not have(physicalPath)) and (i['meta_type'] in t): vals.append(get(id)) - seen[id]=1 + seen[physicalPath]=1 except: pass - if hasattr(obj,'aq_parent'): obj=obj.aq_parent - else: return vals + if hasattr(obj,'aq_parent'): + obj=obj.aq_parent + relativePhysicalPath = ('..',) + relativePhysicalPath + else: + return vals x=x+1 return vals From casey@zope.com Fri Apr 12 20:37:02 2002 From: casey@zope.com (Casey Duncan) Date: Fri, 12 Apr 2002 15:37:02 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS/dtml - documentEdit.dtml:1.7 Message-ID: <200204121937.g3CJb2u15891@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS/dtml In directory cvs.zope.org:/tmp/cvs-serv15810 Modified Files: documentEdit.dtml Log Message: Fixed bug in dtml manage_edit. === Zope/lib/python/OFS/dtml/documentEdit.dtml 1.6 => 1.7 === From casey@zope.com Fri Apr 12 21:19:33 2002 From: casey@zope.com (Casey Duncan) Date: Fri, 12 Apr 2002 16:19:33 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App/dtml - manage_zmi_prefs.dtml:1.4 Message-ID: <200204122019.g3CKJX332731@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App/dtml In directory cvs.zope.org:/tmp/cvs-serv32529/App/dtml Modified Files: manage_zmi_prefs.dtml Log Message: New wider/narrower implementation. Allows you to alternately use percentages or absolute column widths. You can set this in the standard prefs. Still only works for editing DTML right now. === Zope/lib/python/App/dtml/manage_zmi_prefs.dtml 1.3 => 1.4 === + @@ -90,8 +91,7 @@
Title Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/File In directory cvs.zope.org:/tmp/cvs-serv17619/lib/python/Zope/App/OFS/File Modified Files: Tag: Zope-3x-branch edit.pt Log Message: Changed here -> context and container -> view as described in http://collector.zope.org/Zope3-dev/43 === Zope3/lib/python/Zope/App/OFS/File/edit.pt 1.1.2.2 => 1.1.2.3 === -

+

Message will go here.

-

+

Description of the Form.

@@ -38,7 +38,7 @@ - + + === Zope3/lib/python/Zope/App/OFS/Folder/Views/Browser/contents.pt 1.1.4.1 => 1.1.4.2 === (may be None) --> - +
Title Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Folder/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv17619/lib/python/Zope/App/OFS/Folder/Views/Browser Modified Files: Tag: Zope-3x-branch add.pt contents.pt limit.pt loaded_folder_contents.pt Log Message: Changed here -> context and container -> view as described in http://collector.zope.org/Zope3-dev/43 === Zope3/lib/python/Zope/App/OFS/Folder/Views/Browser/add.pt 1.1.4.1 => 1.1.4.2 === (may be None) --> -
-

Services -Allow Services +

Services +Allow Services

=== Zope3/lib/python/Zope/App/OFS/Folder/Views/Browser/limit.pt 1.1.4.1 => 1.1.4.2 === -

+

Message will go here.

-

+

Description of the Form.

@@ -38,7 +38,7 @@ - + + From steve@cat-box.net Mon Apr 1 09:53:20 2002 From: steve@cat-box.net (Steve Alexander) Date: Mon, 1 Apr 2002 04:53:20 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Folder/Views/XUL - limit.pt:1.1.4.2 tree.pt:1.1.4.2 Message-ID: <200204010953.g319rKR18710@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Folder/Views/XUL In directory cvs.zope.org:/tmp/cvs-serv17619/lib/python/Zope/App/OFS/Folder/Views/XUL Modified Files: Tag: Zope-3x-branch limit.pt tree.pt Log Message: Changed here -> context and container -> view as described in http://collector.zope.org/Zope3-dev/43 === Zope3/lib/python/Zope/App/OFS/Folder/Views/XUL/limit.pt 1.1.4.1 => 1.1.4.2 === xmlns:html="http://www.w3.org/1999/xhtml" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - tal:attributes="id string:${container/name}-window; - title container/title"> + tal:attributes="id string:${view/name}-window; + title view/title"> + + @@ -39,10 +64,18 @@
+
Title 1.1.4.2 === (may be None) --> -
Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Image In directory cvs.zope.org:/tmp/cvs-serv17619/lib/python/Zope/App/OFS/Image Modified Files: Tag: Zope-3x-branch edit.pt Log Message: Changed here -> context and container -> view as described in http://collector.zope.org/Zope3-dev/43 === Zope3/lib/python/Zope/App/OFS/Image/edit.pt 1.1.2.2 => 1.1.2.3 === + tal:attributes="value context/getContentType" />
Size + tal:content="context/getImageSize">
+

@@ -52,6 +85,7 @@


+
From tdickenson@geminidataloggers.com Wed Apr 3 17:20:36 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Wed, 3 Apr 2002 12:20:36 -0500 Subject: [Zope-Checkins] CVS: Zope/lib/python/ZODB - cPickleCache.c:1.52 Message-ID: <200204031720.g33HKai31002@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/ZODB In directory cvs.zope.org:/tmp/cvs-serv30979 Modified Files: cPickleCache.c Log Message: replaced placeholder; its needed to avoid dangling pointers === Zope/lib/python/ZODB/cPickleCache.c 1.51 => 1.52 === cPersistentObject *object; int error; + CPersistentRing placeholder; CPersistentRing *here = self->ring_home.next; #ifdef MUCH_RING_CHECKING @@ -278,13 +279,17 @@ else if (object->state == cPersistent_UPTODATE_STATE) { /* deactivate it. This is the main memory saver. */ - /* Save the next pointer of the object we're about to ghostify, - * so that we can follow the link after the ghosted object is - * removed from the ring (via ghostify()). - */ - - /* FIXME: This needs to be changed back to a placeholder */ - CPersistentRing *next = here->next; + /* Add a placeholder; a dummy node in the ring. We need to + do this to mark our position in the ring. All the other nodes + come from persistent objects, and they are all liable + to be deallocated before "obj._p_changed = None" returns + to this function. This operation is only safe when the + ring lock is held (and it is) */ + + placeholder.next = here->next; + placeholder.prev = here; + here->next->prev = &placeholder; + here->next = &placeholder; ENGINE_NOISE("G"); @@ -292,7 +297,12 @@ error = PyObject_SetAttr((PyObject *)object, py__p_changed, Py_None); - here = next; + + /* unlink the placeholder */ + placeholder.next->prev = placeholder.prev; + placeholder.prev->next = placeholder.next; + + here = placeholder.next; if (error) return -1; /* problem */ From jens@zope.com Wed Apr 3 17:41:05 2002 From: jens@zope.com (Jens Vagelpohl) Date: Wed, 3 Apr 2002 12:41:05 -0500 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS/dtml - cmassoc.dtml:1.4 Message-ID: <200204031741.g33Hf5705130@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS/dtml In directory cvs.zope.org:/tmp/cvs-serv5049 Modified Files: cmassoc.dtml Log Message: added "select all" and "deselect all" capability to cache manager "Associate" tab like in the standard ZMI folder contents view === Zope/lib/python/OFS/dtml/cmassoc.dtml 1.3 => 1.4 === - + + + @@ -39,10 +64,18 @@
+
+

@@ -52,6 +85,7 @@


+
From jeremy@zope.com Wed Apr 3 17:53:27 2002 From: jeremy@zope.com (Jeremy Hylton) Date: Wed, 3 Apr 2002 12:53:27 -0500 Subject: [Zope-Checkins] CVS: StandaloneZODB/ZODB - cPickleCache.c:1.53 Message-ID: <200204031753.g33HrRs08590@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZODB In directory cvs.zope.org:/tmp/cvs-serv8583 Modified Files: cPickleCache.c Log Message: Let emacs reformat the long comment lbock. (Thanks for the comments, Toby!) === StandaloneZODB/ZODB/cPickleCache.c 1.52 => 1.53 === self->data dictionary, and are never garbage collected. -The klass_items() method returns a sequence of (oid,object) tuples -for every Persistent Class, which should make it possible to -implement garbage collection in Python if necessary. +The klass_items() method returns a sequence of (oid,object) tuples for +every Persistent Class, which should make it possible to implement +garbage collection in Python if necessary. Regime 2: Ghost Objects -There is no benefit to keeping a ghost object which has no -external references, therefore a weak reference scheme is -used to ensure that ghost objects are removed from memory -as soon as possible, when the last external reference is lost. - -Ghost objects are stored in the self->data dictionary. Normally -a dictionary keeps a strong reference on its values, however -this reference count is 'stolen'. +There is no benefit to keeping a ghost object which has no external +references, therefore a weak reference scheme is used to ensure that +ghost objects are removed from memory as soon as possible, when the +last external reference is lost. + +Ghost objects are stored in the self->data dictionary. Normally a +dictionary keeps a strong reference on its values, however this +reference count is 'stolen'. This weak reference scheme leaves a dangling reference, in the -dictionary, when the last external reference is lost. To clean up -this dangling reference the persistent object dealloc function -calls self->cache->_oid_unreferenced(self->oid). The cache looks -up the oid in the dictionary, ensures it points to an object whose -reference count is zero, then removes it from the dictionary. Before -removing the object from the dictionary it must temporarily resurrect -the object in much the same way that class instances are resurrected +dictionary, when the last external reference is lost. To clean up this +dangling reference the persistent object dealloc function calls +self->cache->_oid_unreferenced(self->oid). The cache looks up the oid +in the dictionary, ensures it points to an object whose reference +count is zero, then removes it from the dictionary. Before removing +the object from the dictionary it must temporarily resurrect the +object in much the same way that class instances are resurrected before their __del__ is called. -Since ghost objects are stored under a different regime to -non-ghost objects, an extra ghostify function in cPersistenceAPI -replaces self->state=GHOST_STATE assignments that were common in -other persistent classes (such as BTrees). +Since ghost objects are stored under a different regime to non-ghost +objects, an extra ghostify function in cPersistenceAPI replaces +self->state=GHOST_STATE assignments that were common in other +persistent classes (such as BTrees). Regime 3: Non-Ghost Objects -Non-ghost objects are stored in two data structures. Firstly, in -the dictionary along with everything else, with a *strong* reference. -Secondly, they are stored in a doubly-linked-list which encodes -the order in which these objects have been most recently used. +Non-ghost objects are stored in two data structures. Firstly, in the +dictionary along with everything else, with a *strong* reference. +Secondly, they are stored in a doubly-linked-list which encodes the +order in which these objects have been most recently used. -The doubly-link-list nodes contain next and previous pointers -linking together the cache and all non-ghost persistent objects. +The doubly-link-list nodes contain next and previous pointers linking +together the cache and all non-ghost persistent objects. The node embedded in the cache is the home position. On every -attribute access a non-ghost object will relink itself just -behind the home position in the ring. Objects accessed least -recently will eventually find themselves positioned after -the home position. - -Occasionally other nodes are temporarily inserted in the ring -as position markers. The cache contains a ring_lock flag which -must be set and unset before and after doing so. Only if the flag -is unset can the cache assume that all nodes are either his own -home node, or nodes from persistent objects. This assumption is -useful during the garbage collection process. +attribute access a non-ghost object will relink itself just behind the +home position in the ring. Objects accessed least recently will +eventually find themselves positioned after the home position. + +Occasionally other nodes are temporarily inserted in the ring as +position markers. The cache contains a ring_lock flag which must be +set and unset before and after doing so. Only if the flag is unset can +the cache assume that all nodes are either his own home node, or nodes +from persistent objects. This assumption is useful during the garbage +collection process. The number of non-ghost objects is counted in self->non_ghost_count. The garbage collection process consists of traversing the ring, and @@ -80,10 +79,9 @@ self->non_ghost_count is down to the target size, or until it reaches the home position again. -Note that objects in the sticky or changed states are still kept -in the ring, however they can not be deactivated. The garbage -collection process must skip such objects, rather than deactivating -them. +Note that objects in the sticky or changed states are still kept in +the ring, however they can not be deactivated. The garbage collection +process must skip such objects, rather than deactivating them. */ From shane@cvs.zope.org Wed Apr 3 19:43:31 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Wed, 3 Apr 2002 14:43:31 -0500 Subject: [Zope-Checkins] CVS: Zope/lib/python/zExceptions - ExceptionFormatter.py:1.1.4.2 Message-ID: <200204031943.g33JhVI06918@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/zExceptions In directory cvs.zope.org:/tmp/cvs-serv6909 Modified Files: Tag: shane-better-tracebacks-branch ExceptionFormatter.py Log Message: Fixed URL printing and the default arguments to format_exception(). === Zope/lib/python/zExceptions/ExceptionFormatter.py 1.1.4.1 => 1.1.4.2 === def formatSourceURL(self, url): - return ['URL: %s' % self.formatSupplementLine(url)] + return [self.formatSupplementLine('URL: %s' % url)] def formatSupplement(self, supplement, tb): result = [] @@ -244,7 +244,7 @@ html_formatter = HTMLExceptionFormatter(limit) -def format_exception(t, v, tb, as_html=0, limit=None): +def format_exception(t, v, tb, limit=None, as_html=0): if as_html: fmt = html_formatter else: From shane@cvs.zope.org Wed Apr 3 19:45:04 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Wed, 3 Apr 2002 14:45:04 -0500 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/SiteErrorLog/www - showEntry.pt:1.1.2.1 main.pt:1.1.2.2 Message-ID: <200204031945.g33Jj4e07341@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/SiteErrorLog/www In directory cvs.zope.org:/tmp/cvs-serv7194/www Modified Files: Tag: shane-better-tracebacks-branch main.pt Added Files: Tag: shane-better-tracebacks-branch showEntry.pt Log Message: The site error log product now shows the log and the tracebacks through the web. === Added File Zope/lib/python/Products/SiteErrorLog/www/showEntry.pt ===

Header

Tabs

Exception traceback

The specified log entry was not found. It may have expired.
Time
User joe
Request URL http://example.com
Exception Type AttributeError
Exception Value zzope

REQUEST

Footer

=== Zope/lib/python/Products/SiteErrorLog/www/main.pt 1.1.2.1 => 1.1.2.2 ===
+ +

Exception Log

+ +
+ + +No exceptions logged. + + + + + + + + + + + + + +
TimeUserException
+ 13:04:41 + + joe + + + AttributeError: + + Application object has no attribute "zzope" + +
+ +
+ + +

+

+ +
+

Footer

From shane@cvs.zope.org Wed Apr 3 19:45:04 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Wed, 3 Apr 2002 14:45:04 -0500 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/SiteErrorLog - SiteErrorLog.py:1.1.2.2 Message-ID: <200204031945.g33Jj4u07338@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/SiteErrorLog In directory cvs.zope.org:/tmp/cvs-serv7194 Modified Files: Tag: shane-better-tracebacks-branch SiteErrorLog.py Log Message: The site error log product now shows the log and the tracebacks through the web. === Zope/lib/python/Products/SiteErrorLog/SiteErrorLog.py 1.1.2.1 => 1.1.2.2 === import os import sys +import time +from random import random from thread import allocate_lock from types import StringType, UnicodeType @@ -48,7 +50,7 @@ meta_type = 'Site Error Log' id = 'error_log' - keep_entries = 10 + keep_entries = 20 copy_to_zlog = 0 security = ClassSecurityInfo() @@ -60,6 +62,9 @@ security.declareProtected(use_error_logging, 'getProperties') manage_main = PageTemplateFile('main.pt', _www) + security.declareProtected(use_error_logging, 'showEntry') + showEntry = PageTemplateFile('showEntry.pt', _www) + security.declarePrivate('manage_beforeDelete') def manage_beforeDelete(self, item, container): if item is self: @@ -98,33 +103,49 @@ Called by SimpleItem's exception handler. """ try: + now = time.time() try: tb_text = None tb_html = None if not isinstance(info[2], StringType) and not isinstance( info[2], UnicodeType): - tb_text = format_exception(*info, **{'as_html': 0}) - tb_html = format_exception(*info, **{'as_html': 1}) + tb_text = ''.join( + format_exception(*info, **{'as_html': 0})) + tb_html = ''.join( + format_exception(*info, **{'as_html': 1})) else: tb_text = info[2] request = getattr(self, 'REQUEST', None) url = None + username = None + req_html = None if request: url = request['URL'] + username = getSecurityManager().getUser().getUserName() + try: + req_html = str(request) + except: + pass log = self._getLog() log.append({ + 'type': str(getattr(info[0], '__name__', info[0])), + 'value': str(info[1]), + 'time': now, + 'id': str(now) + str(random()), # Low chance of collision 'tb_text': tb_text, 'tb_html': tb_html, + 'username': username, 'url': url, + 'req_html': req_html, }) cleanup_lock.acquire() try: if len(log) >= self.keep_entries: - del log[:-keep_entries] + del log[:-self.keep_entries] finally: cleanup_lock.release() except: @@ -141,7 +162,7 @@ return {'keep_entries': self.keep_entries, 'copy_to_zlog': self.copy_to_zlog} - security.declarePublic('checkEventLogPermission') + security.declareProtected(log_to_event_log, 'checkEventLogPermission') def checkEventLogPermission(self): if not getSecurityManager().checkPermission(log_to_event_log, self): raise Unauthorized, ('You do not have the "%s" permission.' % @@ -152,18 +173,38 @@ def setProperties(self, keep_entries, copy_to_zlog=0, RESPONSE=None): """Sets the properties of this site error log. """ - self.keep_entries = int(keep_entries) copy_to_zlog = not not copy_to_zlog if copy_to_zlog and not self.copy_to_zlog: # Before turning on event logging, check the permission. self.checkEventLogPermission() + self.keep_entries = int(keep_entries) self.copy_to_zlog = copy_to_zlog if RESPONSE is not None: RESPONSE.redirect( '%s/manage_main?manage_tabs_message=Changed+properties.' % self.absolute_url()) - + security.declareProtected(use_error_logging, 'getLogEntries') + def getLogEntries(self): + """Returns the entries in the log. + + Makes a copy to prevent changes. + """ + # List incomprehension ;-) + return [entry.copy() for entry in self._getLog()] + + security.declareProtected(use_error_logging, 'getLogEntryById') + def getLogEntryById(self, id): + """Returns the specified log entry. + + Makes a copy to prevent changes. Returns None if not found. + """ + for entry in self._getLog(): + if entry['id'] == id: + return entry.copy() + return None + + Globals.InitializeClass(SiteErrorLog) From casey@zope.com Wed Apr 3 20:43:43 2002 From: casey@zope.com (Casey Duncan) Date: Wed, 3 Apr 2002 15:43:43 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/HTTP - HTTPResponse.py:1.1.2.17 Message-ID: <200204032043.g33Khhh03404@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/HTTP In directory cvs.zope.org:/tmp/cvs-serv365/lib/python/Zope/Publisher/HTTP Modified Files: Tag: Zope-3x-branch HTTPResponse.py Log Message: Zope configuration now uses Shane's nifty traceback supplements to sprinkle helpful debug info into exceptions that occur during configuration processing, rather than masking them with a single generic configuration exception. Exception formatting is now turned on during testing, and when config is run at startup. === Zope3/lib/python/Zope/Publisher/HTTP/HTTPResponse.py 1.1.2.16 => 1.1.2.17 === self.setStatus(tname) - tb = ''.join(format_exception(t, v, exc_info[2], 1)) + tb = ''.join(format_exception(t, v, exc_info[2], as_html=1)) body = self._html(title, "%s" % tb) self.setBody(body) From casey@zope.com Wed Apr 3 20:43:43 2002 From: casey@zope.com (Casey Duncan) Date: Wed, 3 Apr 2002 15:43:43 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Testing - __init__.py:1.3.38.6 Message-ID: <200204032043.g33Khhj03405@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Testing In directory cvs.zope.org:/tmp/cvs-serv365/lib/python/Zope/Testing Modified Files: Tag: Zope-3x-branch __init__.py Log Message: Zope configuration now uses Shane's nifty traceback supplements to sprinkle helpful debug info into exceptions that occur during configuration processing, rather than masking them with a single generic configuration exception. Exception formatting is now turned on during testing, and when config is run at startup. === Zope3/lib/python/Zope/Testing/__init__.py 1.3.38.5 => 1.3.38.6 === traceback.format_exception = format_exception -if os.environ.get('NEW_EXCEPTION_FORMATTER', 0): +# Use the new exception formatter by default, its useful! +if os.environ.get('NEW_EXCEPTION_FORMATTER', 1): patchTracebackModule() From shane@cvs.zope.org Wed Apr 3 20:44:25 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Wed, 3 Apr 2002 15:44:25 -0500 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/PageTemplates - Expressions.py:1.34 PageTemplate.py:1.23 PageTemplateFile.py:1.13 TALES.py:1.29 ZopePageTemplate.py:1.32 Message-ID: <200204032044.g33KiPe03630@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/PageTemplates In directory cvs.zope.org:/tmp/cvs-serv3170/lib/python/Products/PageTemplates Modified Files: Expressions.py PageTemplate.py PageTemplateFile.py TALES.py ZopePageTemplate.py Log Message: Merged shane-better-tracebacks-branch. The changes are explained in http://dev.zope.org/Wikis/DevSite/Proposals/BetterTracebacks === Zope/lib/python/Products/PageTemplates/Expressions.py 1.33 => 1.34 === import re, sys from TALES import Engine, CompilerError, _valid_name, NAME_RE, \ - TALESError, Undefined, Default, _parse_expr + Undefined, Default, _parse_expr from string import strip, split, join, replace, lstrip from Acquisition import aq_base, aq_inner, aq_parent @@ -33,7 +33,6 @@ from PathIterator import Iterator _engine = Engine(Iterator) installHandlers(_engine) - _engine._nocatch = (TALESError, 'Redirect') return _engine def installHandlers(engine): @@ -171,7 +170,7 @@ def _eval(self, econtext, isinstance=isinstance, StringType=type(''), render=render): for expr in self._subexprs[:-1]: - # Try all but the last subexpression, skipping undefined ones + # Try all but the last subexpression, skipping undefined ones. try: ob = expr(econtext) except Undefs: @@ -179,12 +178,8 @@ else: break else: - # On the last subexpression allow exceptions through, but - # wrap ones that indicate that the subexpression was undefined - try: - ob = self._subexprs[-1](econtext) - except Undefs[1:]: - raise Undefined(self._s, sys.exc_info()) + # On the last subexpression allow exceptions through. + ob = self._subexprs[-1](econtext) if self._name == 'nocall' or isinstance(ob, StringType): return ob @@ -234,8 +229,9 @@ vvals = [] for var in self._vars: v = var(econtext) - if isinstance(v, Exception): - raise v + # I hope this isn't in use anymore. + ## if isinstance(v, Exception): + ## raise v vvals.append(v) return self._expr % tuple(vvals) @@ -328,9 +324,10 @@ if not validate(object, container, name, o): raise Unauthorized, name else: - o=get(object, name, M) + # Try an attribute. + o = get(object, name, M) if o is not M: - # Check security. + # Check access to the attribute. if has(object, 'aq_acquire'): object.aq_acquire( name, validate2, validate) @@ -338,12 +335,31 @@ if not validate(object, object, name, o): raise Unauthorized, name else: + # Try an item. try: - o=object[name] - except (AttributeError, TypeError): - raise AttributeError, name - if not validate(object, object, name, o): - raise Unauthorized, name + # XXX maybe in Python 2.2 we can just check whether + # the object has the attribute "__getitem__" + # instead of blindly catching exceptions. + o = object[name] + except AttributeError, exc: + if str(exc).find('__getitem__') >= 0: + # The object does not support the item interface. + # Try to re-raise the original attribute error. + # XXX I think this only happens with + # ExtensionClass instances. + get(object, name) + raise + except TypeError, exc: + if str(exc).find('unsubscriptable') >= 0: + # The object does not support the item interface. + # Try to re-raise the original attribute error. + # XXX This is sooooo ugly. + get(object, name) + raise + else: + # Check access to the item. + if not validate(object, object, name, o): + raise Unauthorized, name object = o return object === Zope/lib/python/Products/PageTemplates/PageTemplate.py 1.22 => 1.23 === __version__='$Revision$'[11:-2] -import os, sys, traceback, pprint +import sys + from TAL.TALParser import TALParser from TAL.HTMLTALParser import HTMLTALParser from TAL.TALGenerator import TALGenerator @@ -26,12 +27,8 @@ from string import join, strip, rstrip, split, replace, lower, find from cStringIO import StringIO from ExtensionClass import Base +from ComputedAttribute import ComputedAttribute -Z_DEBUG_MODE = os.environ.get('Z_DEBUG_MODE') == '1' - -class MacroCollection(Base): - def __of__(self, parent): - return parent.pt_macros() class PageTemplate(Base): "Page Templates using TAL, TALES, and METAL" @@ -40,11 +37,16 @@ expand = 0 _v_errors = () _v_warnings = () + _v_program = None + _v_macros = None + _v_cooked = 0 id = '(unknown)' _text = '' _error_start = '') -elif tb_style == 'plain': - tb_delims = '
', '
' -else: - tb_delims = '' class HTTPResponse(BaseResponse): """\ @@ -384,8 +381,15 @@ else: h=value self.setHeader(name,h) - def isHTML(self,str): - return str.strip().lower()[:6] == '' or str.find(' 0 + def isHTML(self, s): + s = s.lstrip() + # Note that the string can be big, so s.lower().startswith() is more + # expensive than s[:n].lower(). + if (s[:6].lower() == '' or s[:14].lower() == ' 0: + return 1 + return 0 def quoteHTML(self,text, subs={'&':'&', "<":'<', ">":'>', '\"':'"'} @@ -397,42 +401,9 @@ return text - def format_exception(self, etype, value, tb, limit=None): - import traceback - result=['Traceback (innermost last):'] - if limit is None: - if hasattr(sys, 'tracebacklimit'): - limit = sys.tracebacklimit - n = 0 - while tb is not None and (limit is None or n < limit): - f = tb.tb_frame - lineno = tb.tb_lineno - co = f.f_code - filename = co.co_filename - name = co.co_name - locals=f.f_locals - result.append(' File %s, line %d, in %s' - % (filename,lineno,name)) - try: result.append(' (Object: %s)' % - locals[co.co_varnames[0]].__name__) - except: pass - try: result.append(' (Info: %s)' % - str(locals['__traceback_info__'])) - except: pass - tb = tb.tb_next - n = n + 1 - result.append(' '.join(traceback.format_exception_only(etype, value))) - return result - - def _traceback(self, t, v, tb): - tb = self.format_exception(t, v, tb, 200) - tb = '\n'.join(tb) - tb = self.quoteHTML(tb) - if self.debug_mode: _tbopen, _tbclose = '
', '
' - else: _tbopen, _tbclose = tb_delims - if _tbopen is None: - return '' - return "\n%s\n%s\n%s" % (_tbopen, tb, _tbclose) + def _traceback(self, t, v, tb, as_html=1): + tb = format_exception(t, v, tb, as_html=as_html) + return '\n'.join(tb) def redirect(self, location, status=302, lock=0): """Cause a redirection without raising an error""" @@ -621,20 +592,22 @@ if match is None: body = self.setBody( (str(t), - 'Sorry, a site error occurred.

' + 'Sorry, a site error occurred.

' + self._traceback(t, v, tb)), - is_error=1) - elif b.strip().lower()[:6]=='' or \ - b.strip().lower()[:14]==' Update of /cvs-repository/Zope/lib/python/zExceptions In directory cvs.zope.org:/tmp/cvs-serv3170/lib/python/zExceptions Added Files: ExceptionFormatter.py ITracebackSupplement.py Log Message: Merged shane-better-tracebacks-branch. The changes are explained in http://dev.zope.org/Wikis/DevSite/Proposals/BetterTracebacks === Zope/lib/python/zExceptions/ExceptionFormatter.py 1.1 => 1.2 === +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +"""An exception formatter that shows traceback supplements and traceback info, +optionally in HTML. + +$Id$ +""" + +import sys +import cgi + + +DEBUG_EXCEPTION_FORMATTER = 1 + + +class TextExceptionFormatter: + + line_sep = '\n' + show_revisions = 0 + + def __init__(self, limit=None): + self.limit = limit + + def escape(self, s): + return s + + def getPrefix(self): + return 'Traceback (innermost last):' + + def getLimit(self): + limit = self.limit + if limit is None: + limit = getattr(sys, 'tracebacklimit', None) + return limit + + def getRevision(self, globals): + if not self.show_revisions: + return None + revision = globals.get('__revision__', None) + if revision is None: + # Incorrect but commonly used spelling + revision = globals.get('__version__', None) + + if revision is not None: + try: + revision = str(revision).strip() + except: + revision = '???' + return revision + + def formatSupplementLine(self, line): + return ' - %s' % line + + def formatObject(self, object): + return [self.formatSupplementLine(repr(object))] + + def formatSourceURL(self, url): + return [self.formatSupplementLine('URL: %s' % url)] + + def formatSupplement(self, supplement, tb): + result = [] + fmtLine = self.formatSupplementLine + + object = getattr(supplement, 'object', None) + if object is not None: + result.extend(self.formatObject(object)) + + url = getattr(supplement, 'source_url', None) + if url is not None: + result.extend(self.formatSourceURL(url)) + + line = getattr(supplement, 'line', 0) + if line == -1: + line = tb.tb_lineno + col = getattr(supplement, 'column', -1) + if line: + if col is not None and col >= 0: + result.append(fmtLine('Line %s, Column %s' % ( + line, col))) + else: + result.append(fmtLine('Line %s' % line)) + elif col is not None and col >= 0: + result.append(fmtLine('Column %s' % col)) + + expr = getattr(supplement, 'expression', None) + if expr: + result.append(fmtLine('Expression: %s' % expr)) + + warnings = getattr(supplement, 'warnings', None) + if warnings: + for warning in warnings: + result.append(fmtLine('Warning: %s' % warning)) + + extra = self.formatExtraInfo(supplement) + if extra: + result.append(extra) + return result + + def formatExtraInfo(self, supplement): + getInfo = getattr(supplement, 'getInfo', None) + if getInfo is not None: + extra = getInfo() + if extra: + return extra + return None + + def formatTracebackInfo(self, tbi): + return self.formatSupplementLine('__traceback_info__: %s' % tbi) + + def formatLine(self, tb): + f = tb.tb_frame + lineno = tb.tb_lineno + co = f.f_code + filename = co.co_filename + name = co.co_name + locals = f.f_locals + globals = f.f_globals + modname = globals.get('__name__', filename) + + s = ' Module %s, line %d' % (modname, lineno) + + revision = self.getRevision(globals) + if revision: + s = s + ', rev. %s' % revision + + s = s + ', in %s' % name + + result = [] + result.append(self.escape(s)) + + # Output a traceback supplement, if any. + if locals.has_key('__traceback_supplement__'): + # Use the supplement defined in the function. + tbs = locals['__traceback_supplement__'] + elif globals.has_key('__traceback_supplement__'): + # Use the supplement defined in the module. + # This is used by Scripts (Python). + tbs = globals['__traceback_supplement__'] + else: + tbs = None + if tbs is not None: + factory = tbs[0] + args = tbs[1:] + try: + supp = factory(*args) + result.extend(self.formatSupplement(supp, tb)) + except: + if DEBUG_EXCEPTION_FORMATTER: + import traceback + traceback.print_exc() + # else just swallow the exception. + + try: + tbi = locals.get('__traceback_info__', None) + if tbi is not None: + result.append(self.formatTracebackInfo(tbi)) + except: + pass + + return self.line_sep.join(result) + + def formatExceptionOnly(self, etype, value): + import traceback + return self.line_sep.join( + traceback.format_exception_only(etype, value)) + + def formatLastLine(self, exc_line): + return self.escape(exc_line) + + def formatException(self, etype, value, tb, limit=None): + # The next line provides a way to detect recursion. + __exception_formatter__ = 1 + result = [self.getPrefix() + '\n'] + if limit is None: + limit = self.getLimit() + n = 0 + while tb is not None and (limit is None or n < limit): + if tb.tb_frame.f_locals.get('__exception_formatter__'): + # Stop recursion. + result.append('(Recursive formatException() stopped)\n') + break + line = self.formatLine(tb) + result.append(line + '\n') + tb = tb.tb_next + n = n + 1 + exc_line = self.formatExceptionOnly(etype, value) + result.append(self.formatLastLine(exc_line)) + return result + + + +class HTMLExceptionFormatter (TextExceptionFormatter): + + line_sep = '
\r\n' + + def escape(self, s): + return cgi.escape(s) + + def getPrefix(self): + return '

Traceback (innermost last):\r\n

    ' + + def formatSupplementLine(self, line): + return '%s' % self.escape(str(line)) + + def formatTracebackInfo(self, tbi): + s = self.escape(str(tbi)) + s = s.replace('\n', self.line_sep) + return '__traceback_info__: %s' % s + + def formatLine(self, tb): + line = TextExceptionFormatter.formatLine(self, tb) + return '
  • %s
  • ' % line + + def formatLastLine(self, exc_line): + return '
%s

' % self.escape(exc_line) + + def formatExtraInfo(self, supplement): + getInfo = getattr(supplement, 'getInfo', None) + if getInfo is not None: + extra = getInfo(1) + if extra: + return extra + return None + + + +limit = 200 + +if hasattr(sys, 'tracebacklimit'): + limit = min(limit, sys.tracebacklimit) + +text_formatter = TextExceptionFormatter(limit) +html_formatter = HTMLExceptionFormatter(limit) + + +def format_exception(t, v, tb, limit=None, as_html=0): + if as_html: + fmt = html_formatter + else: + fmt = text_formatter + return fmt.formatException(t, v, tb, limit=limit) + === Zope/lib/python/zExceptions/ITracebackSupplement.py 1.1 => 1.2 === +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +"""ITracebackSupplement interface definition. + +$Id$ +""" + + +from Interface import Interface +from Interface.Attribute import Attribute + +class ITracebackSupplement(Interface): + """Provides valuable information to supplement an exception traceback. + + The interface is geared toward providing meaningful feedback when + exceptions occur in user code written in mini-languages like + Zope page templates and restricted Python scripts. + """ + + source_url = Attribute( + 'source_url', + """Optional. Set to URL of the script where the exception occurred. + + Normally this generates a URL in the traceback that the user + can visit to manage the object. Set to None if unknown or + not available. + """ + ) + + object = Attribute( + 'object', + """Optional. Set to the script or template where the exception + occurred. + + Set to None if unknown or not available. + """ + ) + + line = Attribute( + 'line', + """Optional. Set to the line number (>=1) where the exception + occurred. + + Set to 0 or None if the line number is unknown. + """ + ) + + column = Attribute( + 'column', + """Optional. Set to the column offset (>=0) where the exception + occurred. + + Set to None if the column number is unknown. + """ + ) + + expression = Attribute( + 'expression', + """Optional. Set to the expression that was being evaluated. + + Set to None if not available or not applicable. + """ + ) + + warnings = Attribute( + 'warnings', + """Optional. Set to a sequence of warning messages. + + Set to None if not available, not applicable, or if the exception + itself provides enough information. + """ + ) + + + def getInfo(as_html=0): + """Optional. Returns a string containing any other useful info. + + If as_html is set, the implementation must HTML-quote the result + (normally using cgi.escape()). Returns None to provide no + extra info. + """ From shane@cvs.zope.org Wed Apr 3 20:44:32 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Wed, 3 Apr 2002 15:44:32 -0500 Subject: [Zope-Checkins] CVS: Zope/lib/python/TAL - DummyEngine.py:1.30 HTMLTALParser.py:1.32 TALDefs.py:1.27 TALGenerator.py:1.54 TALInterpreter.py:1.68 TALParser.py:1.18 XMLParser.py:1.8 __init__.py:1.2 driver.py:1.27 markbench.py:1.3 ndiff.py:1.3 runtest.py:1.21 setpath.py:1.4 timer.py:1.11 Message-ID: <200204032044.g33KiWb03705@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/TAL In directory cvs.zope.org:/tmp/cvs-serv3170/lib/python/TAL Modified Files: DummyEngine.py HTMLTALParser.py TALDefs.py TALGenerator.py TALInterpreter.py TALParser.py XMLParser.py __init__.py driver.py markbench.py ndiff.py runtest.py setpath.py timer.py Log Message: Merged shane-better-tracebacks-branch. The changes are explained in http://dev.zope.org/Wikis/DevSite/Proposals/BetterTracebacks === Zope/lib/python/TAL/DummyEngine.py 1.29 => 1.30 === # -# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. @@ -16,11 +17,10 @@ import re import sys -from string import rfind, strip import driver -from TALDefs import NAME_RE, TALError, TALESError +from TALDefs import NAME_RE, TALESError, ErrorInfo Default = [] @@ -32,6 +32,7 @@ class DummyEngine: position = None + source_file = None def __init__(self, macros=None): if macros is None: @@ -44,6 +45,9 @@ def getCompilerError(self): return CompilerError + def setSourceFile(self, source_file): + self.source_file = source_file + def setPosition(self, position): self.position = position @@ -51,7 +55,8 @@ return "$%s$" % expr def uncompile(self, expression): - assert expression[:1] == "$" == expression[-1:], expression + assert (expression.startswith("$") and expression.endswith("$"), + expression) return expression[1:-1] def beginScope(self): @@ -71,7 +76,8 @@ self.globals[name] = value def evaluate(self, expression): - assert expression[:1] == "$" == expression[-1:], expression + assert (expression.startswith("$") and expression.endswith("$"), + expression) expression = expression[1:-1] m = name_match(expression) if m: @@ -82,7 +88,7 @@ if type in ("string", "str"): return expr if type in ("path", "var", "global", "local"): - expr = strip(expr) + expr = expr.strip() if self.locals.has_key(expr): return self.locals[expr] elif self.globals.has_key(expr): @@ -97,8 +103,15 @@ try: return eval(expr, self.globals, self.locals) except: - raise TALESError("evaluation error in %s" % `expr`, - info=sys.exc_info()) + raise TALESError("evaluation error in %s" % `expr`) + if type == "position": + # Insert the current source file name, line number, + # and column offset. + if self.position: + lineno, offset = self.position + else: + lineno, offset = None, None + return '%s (%s,%s)' % (self.source_file, lineno, offset) raise TALESError("unrecognized expression: " + `expression`) def evaluateValue(self, expr): @@ -122,7 +135,8 @@ return self.evaluate(expr) def evaluateMacro(self, macroName): - assert macroName[:1] == "$" == macroName[-1:], macroName + assert (macroName.startswith("$") and macroName.endswith("$"), + macroName) macroName = macroName[1:-1] file, localName = self.findMacroFile(macroName) if not file: @@ -147,7 +161,7 @@ def findMacroFile(self, macroName): if not macroName: raise TALESError("empty macro name") - i = rfind(macroName, '/') + i = macroName.rfind('/') if i < 0: # No slash -- must be a locally defined macro return None, macroName @@ -161,8 +175,8 @@ seq = self.evaluateSequence(expr) return Iterator(name, seq, self) - def getTALESError(self): - return TALESError + def createErrorInfo(self, err, position): + return ErrorInfo(err, position) def getDefault(self): return Default === Zope/lib/python/TAL/HTMLTALParser.py 1.31 => 1.32 === # -# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. @@ -15,7 +16,6 @@ """ import sys -import string from TALGenerator import TALGenerator from TALDefs import ZOPE_METAL_NS, ZOPE_TAL_NS, METALError, TALError @@ -74,7 +74,7 @@ % (tagstack[0], endtag)) else: msg = ('Open tags <%s> do not match close tag ' - % (string.join(tagstack, '>, <'), endtag)) + % ('>, <'.join(tagstack), endtag)) else: msg = 'No tags are open to match ' % endtag HTMLParseError.__init__(self, msg, position) @@ -235,7 +235,7 @@ def scan_xmlns(self, attrs): nsnew = {} for key, value in attrs: - if key[:6] == "xmlns:": + if key.startswith("xmlns:"): nsnew[key[6:]] = value if nsnew: self.nsstack.append(self.nsdict) @@ -249,7 +249,7 @@ def fixname(self, name): if ':' in name: - prefix, suffix = string.split(name, ':', 1) + prefix, suffix = name.split(':', 1) if prefix == 'xmlns': nsuri = self.nsdict.get(suffix) if nsuri in (ZOPE_TAL_NS, ZOPE_METAL_NS): === Zope/lib/python/TAL/TALDefs.py 1.26 => 1.27 === # -# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. @@ -66,27 +67,22 @@ pass class TALESError(TALError): + pass + + +class ErrorInfo: + + def __init__(self, err, position=(None, None)): + if isinstance(err, Exception): + self.type = err.__class__ + self.value = err + else: + self.type = err + self.value = None + self.lineno = position[0] + self.offset = position[1] - # This exception can carry around another exception + traceback - def takeTraceback(self): - t = self.info[2] - self.info = self.info[:2] + (None,) - return t - - def __init__(self, msg, position=(None, None), info=(None, None, None)): - t, v, tb = info - if t: - if issubclass(t, Exception) and t.__module__ == "exceptions": - err = t.__name__ - else: - err = str(t) - v = v is not None and str(v) - if v: - err = "%s: %s" % (err, v) - msg = "%s: %s" % (msg, err) - TALError.__init__(self, msg, position) - self.info = info import re _attr_re = re.compile(r"\s*([^\s]+)\s+([^\s].*)\Z", re.S) @@ -117,11 +113,10 @@ def splitParts(arg): # Break in pieces at undoubled semicolons and # change double semicolons to singles: - import string - arg = string.replace(arg, ";;", "\0") - parts = string.split(arg, ';') - parts = map(lambda s, repl=string.replace: repl(s, "\0", ";"), parts) - if len(parts) > 1 and not string.strip(parts[-1]): + arg = arg.replace(";;", "\0") + parts = arg.split(';') + parts = [p.replace("\0", ";") for p in parts] + if len(parts) > 1 and not parts[-1].strip(): del parts[-1] # It ended in a semicolon return parts @@ -139,7 +134,7 @@ return None def getProgramVersion(program): - if (isinstance(program, ListType) and len(program) >= 2 and + if (len(program) >= 2 and isinstance(program[0], TupleType) and len(program[0]) == 2): opcode, version = program[0] if opcode == "version": === Zope/lib/python/TAL/TALGenerator.py 1.53 => 1.54 === # -# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. @@ -14,7 +15,6 @@ Code generator for TALInterpreter intermediate code. """ -import string import re import cgi @@ -24,8 +24,9 @@ inMacroUse = 0 inMacroDef = 0 + source_file = None - def __init__(self, expressionCompiler=None, xml=1): + def __init__(self, expressionCompiler=None, xml=1, source_file=None): if not expressionCompiler: from DummyEngine import DummyEngine expressionCompiler = DummyEngine() @@ -40,6 +41,9 @@ self.xml = xml self.emit("version", TAL_VERSION) self.emit("mode", xml and "xml" or "html") + if source_file is not None: + self.source_file = source_file + self.emit("setSourceFile", source_file) def getCode(self): assert not self.stack @@ -78,9 +82,9 @@ # instructions to be joined together. output.append(self.optimizeArgsList(item)) continue - text = string.join(collect, "") + text = "".join(collect) if text: - i = string.rfind(text, "\n") + i = text.rfind("\n") if i >= 0: i = len(text) - (i + 1) output.append(("rawtextColumn", (text, i))) @@ -272,7 +276,7 @@ def emitDefineMacro(self, macroName): program = self.popProgram() - macroName = string.strip(macroName) + macroName = macroName.strip() if self.macros.has_key(macroName): raise METALError("duplicate macro definition: %s" % `macroName`, self.position) @@ -291,7 +295,7 @@ def emitDefineSlot(self, slotName): program = self.popProgram() - slotName = string.strip(slotName) + slotName = slotName.strip() if not re.match('%s$' % NAME_RE, slotName): raise METALError("invalid slot name: %s" % `slotName`, self.position) @@ -299,7 +303,7 @@ def emitFillSlot(self, slotName): program = self.popProgram() - slotName = string.strip(slotName) + slotName = slotName.strip() if self.slots.has_key(slotName): raise METALError("duplicate fill-slot name: %s" % `slotName`, self.position) @@ -330,7 +334,7 @@ self.program[i] = ("rawtext", text[:m.start()]) collect.append(m.group()) collect.reverse() - return string.join(collect, "") + return "".join(collect) def unEmitNewlineWhitespace(self): collect = [] @@ -349,7 +353,7 @@ break text, rest = m.group(1, 2) collect.reverse() - rest = rest + string.join(collect, "") + rest = rest + "".join(collect) del self.program[i:] if text: self.emit("rawtext", text) @@ -427,6 +431,8 @@ if self.inMacroUse: if fillSlot: self.pushProgram() + if self.source_file is not None: + self.emit("setSourceFile", self.source_file) todo["fillSlot"] = fillSlot self.inMacroUse = 0 else: @@ -438,6 +444,8 @@ self.pushProgram() self.emit("version", TAL_VERSION) self.emit("mode", self.xml and "xml" or "html") + if self.source_file is not None: + self.emit("setSourceFile", self.source_file) todo["defineMacro"] = defineMacro self.inMacroDef = self.inMacroDef + 1 if useMacro: === Zope/lib/python/TAL/TALInterpreter.py 1.67 => 1.68 === # -# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. @@ -85,7 +86,6 @@ self.program = program self.macros = macros self.engine = engine - self.TALESError = engine.getTALESError() self.Default = engine.getDefault() self.stream = stream or sys.stdout self._stream_write = self.stream.write @@ -112,6 +112,7 @@ self.col = 0 self.level = 0 self.scopeLevel = 0 + self.sourceFile = None def saveState(self): return (self.position, self.col, self.stream, @@ -201,6 +202,11 @@ self.endlen = len(self.endsep) bytecode_handlers["mode"] = do_mode + def do_setSourceFile(self, source_file): + self.sourceFile = source_file + self.engine.setSourceFile(source_file) + bytecode_handlers["setSourceFile"] = do_setSourceFile + def do_setPosition(self, position): self.position = position self.engine.setPosition(position) @@ -515,7 +521,12 @@ raise METALError("macro %s has incompatible mode %s" % (`macroName`, `mode`), self.position) self.pushMacro(macroName, compiledSlots) + saved_source = self.sourceFile + saved_position = self.position # Used by Boa Constructor self.interpret(macro) + if self.sourceFile != saved_source: + self.engine.setSourceFile(saved_source) + self.sourceFile = saved_source self.popMacro() bytecode_handlers["useMacro"] = do_useMacro @@ -531,10 +542,15 @@ return macs = self.macroStack if macs and macs[-1] is not None: + saved_source = self.sourceFile + saved_position = self.position # Used by Boa Constructor macroName, slots = self.popMacro()[:2] slot = slots.get(slotName) if slot is not None: self.interpret(slot) + if self.sourceFile != saved_source: + self.engine.setSourceFile(saved_source) + self.sourceFile = saved_source self.pushMacro(macroName, slots, entering=0) return self.pushMacro(macroName, slots) @@ -553,16 +569,16 @@ self._stream_write = stream.write try: self.interpret(block) - except self.TALESError, err: + except: + exc = sys.exc_info()[1] self.restoreState(state) engine = self.engine engine.beginScope() - err.lineno, err.offset = self.position - engine.setLocal('error', err) + error = engine.createErrorInfo(exc, self.position) + engine.setLocal('error', error) try: self.interpret(handler) finally: - err.takeTraceback() engine.endScope() else: self.restoreOutputState(state) === Zope/lib/python/TAL/TALParser.py 1.17 => 1.18 === # -# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. @@ -14,7 +15,6 @@ Parse XML and compile to TALInterpreter intermediate code. """ -import string from XMLParser import XMLParser from TALDefs import * from TALGenerator import TALGenerator @@ -99,7 +99,7 @@ def fixname(self, name): if ' ' in name: - uri, name = string.split(name, ' ') + uri, name = name.split(' ') prefix = self.nsDict[uri] prefixed = name if prefix: === Zope/lib/python/TAL/XMLParser.py 1.7 => 1.8 === # -# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. === Zope/lib/python/TAL/__init__.py 1.1 => 1.2 === +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE +# +############################################################################## +""" Template Attribute Language package """ === Zope/lib/python/TAL/driver.py 1.26 => 1.27 === +#!/usr/bin/env python ############################################################################## # -# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. @@ -17,7 +18,6 @@ import os import sys -import string import getopt @@ -93,7 +93,7 @@ assert mode in ("html", "xml", None) if mode is None: ext = os.path.splitext(file)[1] - if string.lower(ext) in (".html", ".htm"): + if ext.lower() in (".html", ".htm"): mode = "html" else: mode = "xml" === Zope/lib/python/TAL/markbench.py 1.2 => 1.3 === +#! /usr/bin/env python + +# This software is subject to the provisions of the Zope Public License, +# Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. + '''Run benchmarks of TAL vs. DTML''' === Zope/lib/python/TAL/ndiff.py 1.2 => 1.3 === # have been in sys.argv[1:] had the cmd-line form been used. -import string TRACE = 0 # define what "junk" means === Zope/lib/python/TAL/runtest.py 1.20 => 1.21 === +#! /usr/bin/env python ############################################################################## # -# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. @@ -17,7 +18,6 @@ import sys import os -import string from cStringIO import StringIO import glob import traceback @@ -57,7 +57,7 @@ if args and args[0] == "-Q": unittesting = 1 del args[0] - while args and args[0][:1] == '-': + while args and args[0].startswith('-'): opts.append(args[0]) del args[0] if not args: @@ -76,12 +76,12 @@ errors = 0 for arg in args: locopts = [] - if string.find(arg, "metal") >= 0 and "-m" not in opts: + if arg.find("metal") >= 0 and "-m" not in opts: locopts.append("-m") if not unittesting: print arg, sys.stdout.flush() - if tests.utils.skipxml and arg[-4:] == ".xml": + if tests.utils.skipxml and arg.endswith(".xml"): print "SKIPPED (XML parser not available)" continue save = sys.stdout, sys.argv @@ -109,7 +109,7 @@ continue head, tail = os.path.split(arg) outfile = os.path.join( - string.replace(head, "input", "output"), + head.replace("input", "output"), tail) try: f = open(outfile) === Zope/lib/python/TAL/setpath.py 1.3 => 1.4 === +# Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. + """ Read a module search path from .path. """ import os import sys -import string dir = os.path.dirname(__file__) path = os.path.join(dir, ".path") @@ -13,7 +19,7 @@ raise IOError, "Please edit .path to point to " else: for line in f.readlines(): - line = string.strip(line) + line = line.strip() if line and line[0] != '#': for dir in string.split(line, os.pathsep): dir = os.path.expanduser(os.path.expandvars(dir)) === Zope/lib/python/TAL/timer.py 1.10 => 1.11 === +#! /usr/bin/env python ############################################################################## # -# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. From casey@zope.com Wed Apr 3 20:59:30 2002 From: casey@zope.com (Casey Duncan) Date: Wed, 3 Apr 2002 15:59:30 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/Browser - BrowserResponse.py:1.1.4.5 Message-ID: <200204032059.g33KxUY12167@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/Browser In directory cvs.zope.org:/tmp/cvs-serv11830 Modified Files: Tag: Zope-3x-branch BrowserResponse.py Log Message: Cleanup some stray chars... === Zope3/lib/python/Zope/Publisher/Browser/BrowserResponse.py 1.1.4.4 => 1.1.4.5 === "%s\n" "

%s

\n" - "%s\nsdfgj lksdf" + "%s\n" "\n" % (t, t, content) ) From shane@cvs.zope.org Wed Apr 3 21:00:20 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Wed, 3 Apr 2002 16:00:20 -0500 Subject: [Zope-Checkins] CVS: Zope/lib/python/AccessControl/tests - testSecurity.py:1.9 Message-ID: <200204032100.g33L0KF12578@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/AccessControl/tests In directory cvs.zope.org:/tmp/cvs-serv12307/lib/python/AccessControl/tests Modified Files: testSecurity.py Log Message: Used failUnlessRaises() to clean up a little code. === Zope/lib/python/AccessControl/tests/testSecurity.py 1.8 => 1.9 === html = self.doc_class('') - try: - html(myinst=myclass()) - except Unauthorized: - # Passed the test. - pass - else: - assert 0, 'Did not deny attribute access' + self.failUnlessRaises(Unauthorized, html, myinst=myclass()) def testSecurityInSyntax(self): ''' From garyposter@earthlink.net Thu Apr 4 03:53:08 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:08 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Formulator/Widgets/Browser/tests - .testinfo:1.1.4.1 Message-ID: <200204040353.g343r8H09185@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Formulator/Widgets/Browser/tests In directory cvs.zope.org:/tmp/cvs-serv7752/Formulator/Widgets/Browser/tests Added Files: Tag: Zope-3x-branch .testinfo Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Added File Zope3/lib/python/Zope/App/Formulator/Widgets/Browser/tests/.testinfo === From garyposter@earthlink.net Thu Apr 4 03:53:23 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:23 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZMI/Views - __init__.py:1.1.4.1 views.zcml:1.1.4.1 Message-ID: <200204040353.g343rNI09428@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZMI/Views In directory cvs.zope.org:/tmp/cvs-serv7752/ZMI/Views Added Files: Tag: Zope-3x-branch __init__.py views.zcml Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Added File Zope3/lib/python/Zope/App/ZMI/Views/__init__.py === === Added File Zope3/lib/python/Zope/App/ZMI/Views/views.zcml === From garyposter@earthlink.net Thu Apr 4 03:53:24 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:24 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication/XMLRPC - Publication.py:1.1.2.3 Message-ID: <200204040353.g343rON09471@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/XMLRPC In directory cvs.zope.org:/tmp/cvs-serv7752/ZopePublication/XMLRPC Modified Files: Tag: Zope-3x-branch Publication.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/ZopePublication/XMLRPC/Publication.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ +$Id$ """ - + from Zope.App.ZopePublication.HTTP.Publication import ZopeHTTPPublication from Zope.ComponentArchitecture import getRequestView from Zope.ContextWrapper import Wrapper From garyposter@earthlink.net Thu Apr 4 03:53:23 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:23 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZMI/Views/Browser - GenericCreatorView.py:1.1.4.1 __init__.py:1.1.4.1 add.pt:1.1.4.1 add_confirmed.pt:1.1.4.1 browser.zcml:1.1.4.1 Message-ID: <200204040353.g343rNa09456@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZMI/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv7752/ZMI/Views/Browser Added Files: Tag: Zope-3x-branch GenericCreatorView.py __init__.py add.pt add_confirmed.pt browser.zcml Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Added File Zope3/lib/python/Zope/App/ZMI/Views/Browser/GenericCreatorView.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## from Zope.Publisher.Browser.AttributePublisher import AttributePublisher from Zope.PageTemplate import PageTemplateFile from Zope.App.ZMI.IGenericCreatorMarker import IGenericCreatorMarker from Zope.ContextWrapper import getcontext from Zope.App.OFS.Container.Exceptions import DuplicateIDError from Zope.ComponentArchitecture import createObject class GenericCreatorView(AttributePublisher): """Provide an interface for editing a contact """ # Boiler plate def __init__(self, context): self._context=context def getContext(self): return self._context # Assert that we can only be applied to IGenericCreatorMarker __used_for__=IGenericCreatorMarker # Input form index = PageTemplateFile('add.pt', globals()) # action method def action(self, name, REQUEST=None): "Create an item of the class identified by the Addable (held in _context) within the container that is the parent of the Addable" addable=self.getContext() container=getcontext(addable) if name in container.objectIds(): raise DuplicateIDError, "ID '%s' already in use." % name container.setObject(name, createObject(container, addable.id())) if REQUEST is not None: # for unit tests REQUEST.getResponse().redirect(REQUEST.URL[-3]) return self.confirmed( type_name=addable.id(), id=name ) confirmed = PageTemplateFile('add_confirmed.pt') === Added File Zope3/lib/python/Zope/App/ZMI/Views/Browser/__init__.py === === Added File Zope3/lib/python/Zope/App/ZMI/Views/Browser/add.pt === add

Add Item Title

The item's description goes here

Enter the id (or file name, as seen in the URL) for this item, and click "Add".

=== Added File Zope3/lib/python/Zope/App/ZMI/Views/Browser/add_confirmed.pt ===

Object added successfully.

=== Added File Zope3/lib/python/Zope/App/ZMI/Views/Browser/browser.zcml === From garyposter@earthlink.net Thu Apr 4 03:53:24 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:24 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication/tests - testDefaultTraverser.py:1.1.2.10 Message-ID: <200204040353.g343rOU09483@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/tests In directory cvs.zope.org:/tmp/cvs-serv7752/ZopePublication/tests Modified Files: Tag: Zope-3x-branch testDefaultTraverser.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/ZopePublication/tests/testDefaultTraverser.py 1.1.2.9 => 1.1.2.10 === # ############################################################################## -""" - -$Id$ -""" +""" + +$Id$ +""" import unittest, sys from Zope.ComponentArchitecture.tests.Request import Request From garyposter@earthlink.net Thu Apr 4 03:53:38 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:38 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/tests - testContainerTraversable.py:1.1.2.3 testContainerTraverser.py:1.1.2.4 Message-ID: <200204040353.g343rct09857@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/tests In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Container/tests Modified Files: Tag: Zope-3x-branch testContainerTraversable.py testContainerTraverser.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Container/tests/testContainerTraversable.py 1.1.2.2 => 1.1.2.3 === ############################################################################## """ - -$Id$ -""" + +$Id$ +""" import unittest, sys from Zope.App.OFS.Container.ContainerTraversable import ContainerTraversable === Zope3/lib/python/Zope/App/OFS/Container/tests/testContainerTraverser.py 1.1.2.3 => 1.1.2.4 === # ############################################################################## +""" + +$Id$ """ - -$Id$ -""" - + import unittest, sys from Zope.ComponentArchitecture.tests.Request import Request from Zope.ComponentArchitecture import provideView From garyposter@earthlink.net Thu Apr 4 03:53:38 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:38 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container - IContainerLimit.py:1.1.2.3 IOrderedContainer.py:1.1.2.3 Message-ID: <200204040353.g343rcR09858@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Container Modified Files: Tag: Zope-3x-branch IContainerLimit.py IOrderedContainer.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Container/IContainerLimit.py 1.1.2.2 => 1.1.2.3 === # ############################################################################## -""" - $Id$ +""" + $Id$ """ from Interface import Base === Zope3/lib/python/Zope/App/OFS/Container/IOrderedContainer.py 1.1.2.2 => 1.1.2.3 === ############################################################################## """ - $Id$ + $Id$ """ from Interface import Base From garyposter@earthlink.net Thu Apr 4 03:53:39 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:39 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/File - FileFields.py:1.1.2.3 __init__.py:1.1.2.3 Message-ID: <200204040353.g343rdw09878@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/File Modified Files: Tag: Zope-3x-branch FileFields.py __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/File/FileFields.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ +$Id$ """ from Zope.App.Formulator.FieldRegistry import getField === Zope3/lib/python/Zope/App/OFS/Content/File/__init__.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ -""" +$Id$ +""" From garyposter@earthlink.net Thu Apr 4 03:53:40 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:40 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/File/Views - __init__.py:1.1.2.3 Message-ID: <200204040353.g343reH09881@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File/Views In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/File/Views Modified Files: Tag: Zope-3x-branch __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/File/Views/__init__.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ -""" +$Id$ +""" From garyposter@earthlink.net Thu Apr 4 03:53:42 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:42 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/File/Views/XUL - __init__.py:1.1.2.3 Message-ID: <200204040353.g343rg809891@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File/Views/XUL In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/File/Views/XUL Modified Files: Tag: Zope-3x-branch __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/File/Views/XUL/__init__.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ +$Id$ """ From garyposter@earthlink.net Thu Apr 4 03:53:42 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:42 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/File/Views/Browser/tests - __init__.py:1.1.2.3 Message-ID: <200204040353.g343rgh09890@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File/Views/Browser/tests In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/File/Views/Browser/tests Modified Files: Tag: Zope-3x-branch __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/File/Views/Browser/tests/__init__.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ +$Id$ """ From garyposter@earthlink.net Thu Apr 4 03:53:42 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:42 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/File/Views/XUL/tests - __init__.py:1.1.2.3 Message-ID: <200204040353.g343rgp09900@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File/Views/XUL/tests In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/File/Views/XUL/tests Modified Files: Tag: Zope-3x-branch __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/File/Views/XUL/tests/__init__.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ +$Id$ """ From garyposter@earthlink.net Thu Apr 4 03:53:43 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:43 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/File/tests - __init__.py:1.1.2.3 Message-ID: <200204040353.g343rhR09903@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File/tests In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/File/tests Modified Files: Tag: Zope-3x-branch __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/File/tests/__init__.py 1.1.2.2 => 1.1.2.3 === # ############################################################################## -""" - -$Id$ +""" + +$Id$ """ From garyposter@earthlink.net Thu Apr 4 03:53:43 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:43 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/Image/Views - __init__.py:1.1.2.3 Message-ID: <200204040353.g343rhh09912@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/Image/Views In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/Image/Views Modified Files: Tag: Zope-3x-branch __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/Image/Views/__init__.py 1.1.2.2 => 1.1.2.3 === ############################################################################## """ - -$Id$ -""" + +$Id$ +""" From garyposter@earthlink.net Thu Apr 4 03:53:41 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:41 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/File/Views/Browser - FileView.py:1.1.2.3 __init__.py:1.1.2.3 Message-ID: <200204040353.g343rfD09885@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/File/Views/Browser Modified Files: Tag: Zope-3x-branch FileView.py __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/File/Views/Browser/FileView.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ -""" +$Id$ +""" from Zope.Publisher.Browser.AttributePublisher import AttributePublisher === Zope3/lib/python/Zope/App/OFS/Content/File/Views/Browser/__init__.py 1.1.2.2 => 1.1.2.3 === ############################################################################## """ - -$Id$ + +$Id$ """ From garyposter@earthlink.net Thu Apr 4 03:53:44 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:44 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/Image/Views/Browser - __init__.py:1.1.2.3 Message-ID: <200204040353.g343riC09922@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/Image/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/Image/Views/Browser Modified Files: Tag: Zope-3x-branch __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/Image/Views/Browser/__init__.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ -""" +$Id$ +""" From garyposter@earthlink.net Thu Apr 4 03:53:46 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:46 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/Image/Views/Browser/tests - __init__.py:1.1.2.3 testImageEdit.py:1.1.2.4 Message-ID: <200204040353.g343rkZ09927@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/Image/Views/Browser/tests In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/Image/Views/Browser/tests Modified Files: Tag: Zope-3x-branch __init__.py testImageEdit.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/Image/Views/Browser/tests/__init__.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ +$Id$ """ === Zope3/lib/python/Zope/App/OFS/Content/Image/Views/Browser/tests/testImageEdit.py 1.1.2.3 => 1.1.2.4 === """ -$Id$ -""" +$Id$ +""" import unittest, cStringIO From garyposter@earthlink.net Thu Apr 4 03:53:43 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:43 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/Image - ImageFields.py:1.1.2.3 Message-ID: <200204040353.g343rhE09911@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/Image In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/Image Modified Files: Tag: Zope-3x-branch ImageFields.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/Image/ImageFields.py 1.1.2.2 => 1.1.2.3 === """ Revision information: -$Id$ +$Id$ """ - + from Zope.App.Formulator.FieldRegistry import getField from Zope.App.Formulator.ValidatorRegistry import getValidator From garyposter@earthlink.net Thu Apr 4 03:53:47 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:47 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/Image/tests - __init__.py:1.1.2.3 Message-ID: <200204040353.g343rlg09940@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/Image/tests In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/Image/tests Modified Files: Tag: Zope-3x-branch __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/Image/tests/__init__.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ +$Id$ """ From garyposter@earthlink.net Thu Apr 4 03:53:47 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:47 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/ZPTPage - ZPTPageFields.py:1.1.2.3 __init__.py:1.1.2.3 Message-ID: <200204040353.g343rle09945@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/ZPTPage In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/ZPTPage Modified Files: Tag: Zope-3x-branch ZPTPageFields.py __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/ZPTPageFields.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ -""" +$Id$ +""" from Zope.App.Formulator.FieldRegistry import getField from Zope.App.Formulator.ValidatorRegistry import getValidator === Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/__init__.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ +$Id$ """ From garyposter@earthlink.net Thu Apr 4 03:53:49 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:49 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views/XUL - __init__.py:1.1.2.3 Message-ID: <200204040353.g343rnS09962@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views/XUL In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/ZPTPage/Views/XUL Modified Files: Tag: Zope-3x-branch __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views/XUL/__init__.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ -""" +$Id$ +""" From garyposter@earthlink.net Thu Apr 4 03:53:50 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:50 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views/XUL/tests - __init__.py:1.1.2.3 Message-ID: <200204040353.g343roU09968@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views/XUL/tests In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/ZPTPage/Views/XUL/tests Modified Files: Tag: Zope-3x-branch __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views/XUL/tests/__init__.py 1.1.2.2 => 1.1.2.3 === # ############################################################################## -""" - -$Id$ +""" + +$Id$ """ From garyposter@earthlink.net Thu Apr 4 03:53:51 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:51 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Folder/Views/XMLRPC - Methods.py:1.1.4.3 __init__.py:1.1.4.3 Message-ID: <200204040353.g343rpU09984@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Folder/Views/XMLRPC In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Folder/Views/XMLRPC Modified Files: Tag: Zope-3x-branch Methods.py __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Folder/Views/XMLRPC/Methods.py 1.1.4.2 => 1.1.4.3 === """ -$Id$ -""" +$Id$ +""" from Zope.Publisher.XMLRPC.MethodPublisher import MethodPublisher from Zope.Publisher.XMLRPC.IXMLRPCPublisher import IXMLRPCPublisher === Zope3/lib/python/Zope/App/OFS/Folder/Views/XMLRPC/__init__.py 1.1.4.2 => 1.1.4.3 === """ -$Id$ -""" +$Id$ +""" From garyposter@earthlink.net Thu Apr 4 03:53:52 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:52 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZMI - IGenericCreatorMarker.py:1.1.4.1 Addable.py:1.1.2.6 metaConfigure.py:1.1.2.10 zmi-meta.zcml:1.1.2.5 zmi.zcml:1.1.2.6 Message-ID: <200204040353.g343rq109999@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZMI In directory cvs.zope.org:/tmp/cvs-serv7752/ZMI Modified Files: Tag: Zope-3x-branch Addable.py metaConfigure.py zmi-meta.zcml zmi.zcml Added Files: Tag: Zope-3x-branch IGenericCreatorMarker.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Added File Zope3/lib/python/Zope/App/ZMI/IGenericCreatorMarker.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ ZMI Generic Creator Marker Interface $Id: IGenericCreatorMarker.py,v 1.1.4.1 2002/04/04 03:53:21 poster Exp $ """ from Interface import Interface class IGenericCreatorMarker(Interface): "This is the marker interface for the default create view" === Zope3/lib/python/Zope/App/ZMI/Addable.py 1.1.2.5 => 1.1.2.6 === class Addables: - def provideAddable(self, id, title, description): - self.__reg.append(Addable(id, title, description)) + def provideAddable(self, id, title, description, marker_interface=None): + self.__reg.append(Addable(id, title, description, marker_interface=marker_interface)) def getAddables(self, ob): return self.__reg[:] @@ -47,11 +47,16 @@ class Addable: - def __init__(self, id, title, description, icon=None): + def __init__(self, id, title, description, icon=None, marker_interface=None): self.__id = id self.__title = title self.__description = description self.__icon = icon + if marker_interface: + if hasattr(self, "__implements__"): + # not checking to see if already there... + self.__implements__ = marker_interface, self.__implements__ + else: self.__implements__=marker_interface def id(self): return self.__id def title(self): return self.__title === Zope3/lib/python/Zope/App/ZMI/metaConfigure.py 1.1.2.9 => 1.1.2.10 === from Zope.ComponentArchitecture import provideFactory import Addable +from IGenericCreatorMarker import IGenericCreatorMarker class ClassFactory: __implements__ = IFactory @@ -29,12 +30,12 @@ self.__permission__ = permission self._class = _class - def __call__(self): - return self._class() + def __call__(self, *args, **kwargs): + return self._class(*args, **kwargs) def provideClass(registry, qualified_name, _class, permission, - title, description=''): + title, description='', marker_interface=None): """Provide simple class setup - create a component @@ -47,7 +48,7 @@ """ factory = ClassFactory(_class, permission) provideFactory(qualified_name, factory) - registry.provideAddable(qualified_name, title, description) + registry.provideAddable(qualified_name, title, description, marker_interface) def ServiceClassDir(_context, name, class_, permission_id, title, @@ -61,14 +62,16 @@ ) ] - def ContentClassDir(_context, name, class_, permission_id, title, - description=''): + description='', + marker_interface=IGenericCreatorMarker): + if marker_interface is not IGenericCreatorMarker: + marker_interface=_context.resolve(marker_interface) return [ Action( discriminator = name, callable = provideClass, args = (Addable.ContentAddables, name, _context.resolve(class_), - permission_id, title, description) + permission_id, title, description, marker_interface) ) ] === Zope3/lib/python/Zope/App/ZMI/zmi-meta.zcml 1.1.2.4 => 1.1.2.5 === 1.1.2.6 === methods="getZMIViews"/> + + + From garyposter@earthlink.net Thu Apr 4 03:53:50 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:50 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Folder - FolderLimit.py:1.1.4.3 LoadedFolderFields.py:1.1.4.3 OrderedFolder.py:1.1.4.3 Message-ID: <200204040353.g343roL09973@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Folder In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Folder Modified Files: Tag: Zope-3x-branch FolderLimit.py LoadedFolderFields.py OrderedFolder.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Folder/FolderLimit.py 1.1.4.2 => 1.1.4.3 === Revision information: -$Id$ +$Id$ """ from Zope.App.OFS.Container.IContainerLimit import IContainerLimit === Zope3/lib/python/Zope/App/OFS/Folder/LoadedFolderFields.py 1.1.4.2 => 1.1.4.3 === """ -$Id$ +$Id$ """ - + from Zope.App.Formulator import getField === Zope3/lib/python/Zope/App/OFS/Folder/OrderedFolder.py 1.1.4.2 => 1.1.4.3 === """ Revision information: -$Id$ +$Id$ """ From garyposter@earthlink.net Thu Apr 4 03:53:51 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:51 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Folder/Views/XUL - Main.py:1.1.4.3 Message-ID: <200204040353.g343rp609985@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Folder/Views/XUL In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Folder/Views/XUL Modified Files: Tag: Zope-3x-branch Main.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Folder/Views/XUL/Main.py 1.1.4.2 => 1.1.4.3 === """ -$Id$ +$Id$ """ - + from Zope.PageTemplate.PageTemplateFile import PageTemplateFile from Zope.Publisher.Browser.AttributePublisher import AttributePublisher From garyposter@earthlink.net Thu Apr 4 03:53:47 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:47 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/Image/Views/XUL - __init__.py:1.1.2.3 Message-ID: <200204040353.g343rld09934@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/Image/Views/XUL In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/Image/Views/XUL Modified Files: Tag: Zope-3x-branch __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/Image/Views/XUL/__init__.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ +$Id$ """ From garyposter@earthlink.net Thu Apr 4 03:53:53 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:53 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication - PublicationTraverse.py:1.1.2.12 Message-ID: <200204040353.g343rrb10012@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication In directory cvs.zope.org:/tmp/cvs-serv7752/ZopePublication Modified Files: Tag: Zope-3x-branch PublicationTraverse.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/ZopePublication/PublicationTraverse.py 1.1.2.11 => 1.1.2.12 === from Zope.ContextWrapper import Wrapper +from Zope.App.ZMI.Addable import ContentAddables +from Zope.App.OFS.Container.IContainer import IWriteContainer + class DuplicateNamespaces(Exception): """More than one namespave was specified in a request""" @@ -149,6 +152,13 @@ if r is None: raise NotFound(ob, name, request) raise ExcessiveWrapping(ob, name, request) + + def _traversecreate(self, request, ob, name): + for addable in ContentAddables.getAddables(ob): + if addable.id() == name: + return addable + raise NotFound(ob, name, request) + class PublicationTraverser(PublicationTraverse): From garyposter@earthlink.net Thu Apr 4 03:53:48 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:48 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views/Browser - __init__.py:1.1.2.3 Message-ID: <200204040353.g343rmR09953@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/ZPTPage/Views/Browser Modified Files: Tag: Zope-3x-branch __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views/Browser/__init__.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ +$Id$ """ From garyposter@earthlink.net Thu Apr 4 03:53:49 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:49 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views/Browser/tests - __init__.py:1.1.2.3 Message-ID: <200204040353.g343rnq09958@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views/Browser/tests In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/ZPTPage/Views/Browser/tests Modified Files: Tag: Zope-3x-branch __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views/Browser/tests/__init__.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ -""" +$Id$ +""" From garyposter@earthlink.net Thu Apr 4 03:56:25 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:56:25 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/ComponentArchitecture - hooks.py:1.1.2.21 Message-ID: <200204040356.g343uPc10590@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/ComponentArchitecture In directory cvs.zope.org:/tmp/cvs-serv10125 Modified Files: Tag: Zope-3x-branch hooks.py Log Message: Component Architecture changes to allow factories to pass arguments; multiple touched files because of previous backwards merge and license script. I will check out after this to see if enough of my changes have gone through and I don't have to do a further mass check in. === Zope3/lib/python/Zope/ComponentArchitecture/hooks.py 1.1.2.20 => 1.1.2.21 === return provideFactory_hook(qname, factory) -def createObject(place, name): - return createObject_hook(place, name) +def createObject(place, name, *args, **kwargs): + return createObject_hook(place, name, args, kwargs) # default hooks @@ -86,15 +86,13 @@ _verify(_IFactory, factory) _factories[qname] = factory -def createObject_hook(place, name): +def createObject_hook(place, name, args=[], kwargs={}): # XXX: place is ignored at present, as we don't yet # have placeful factories - - try: factory = _factories[name] + try: return _factories[name](*args, **kwargs) except KeyError: raise ComponentLookupError(name) - return factory() def _clear(): global _adapters, _utilities, _factories From garyposter@earthlink.net Thu Apr 4 03:53:50 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:50 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Folder/Views - __init__.py:1.1.4.3 Message-ID: <200204040353.g343roO09977@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Folder/Views In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Folder/Views Modified Files: Tag: Zope-3x-branch __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Folder/Views/__init__.py 1.1.4.2 => 1.1.4.3 === """ -$Id$ +$Id$ """ From garyposter@earthlink.net Thu Apr 4 03:53:51 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:51 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Folder/Views/Browser - __init__.py:1.1.4.3 Message-ID: <200204040353.g343rp309980@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Folder/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Folder/Views/Browser Modified Files: Tag: Zope-3x-branch __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Folder/Views/Browser/__init__.py 1.1.4.2 => 1.1.4.3 === """ -$Id$ +$Id$ """ From garyposter@earthlink.net Thu Apr 4 03:53:52 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:52 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Introspector/tests - testIntrospector.py:1.1.2.3 Message-ID: <200204040353.g343rqN09992@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Introspector/tests In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Introspector/tests Modified Files: Tag: Zope-3x-branch testIntrospector.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Introspector/tests/testIntrospector.py 1.1.2.2 => 1.1.2.3 === from Zope.App.OFS.Introspector.Introspector import Introspector -# This software is subject to the provisions of the Zope Public License, -# Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. from Interface import Interface from Interface.Implements import implements From garyposter@earthlink.net Thu Apr 4 03:53:47 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:47 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/Image/Views/XUL/tests - __init__.py:1.1.2.3 Message-ID: <200204040353.g343rlU09937@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/Image/Views/XUL/tests In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/Image/Views/XUL/tests Modified Files: Tag: Zope-3x-branch __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/Image/Views/XUL/tests/__init__.py 1.1.2.2 => 1.1.2.3 === # ############################################################################## -""" - -$Id$ +""" + +$Id$ """ From garyposter@earthlink.net Thu Apr 4 03:53:47 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 22:53:47 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views - __init__.py:1.1.2.3 Message-ID: <200204040353.g343rlt09947@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views In directory cvs.zope.org:/tmp/cvs-serv7752/OFS/Content/ZPTPage/Views Modified Files: Tag: Zope-3x-branch __init__.py Log Message: checking in gary-pre_create_view-branch, with support for create namespace. Because I merged in the Zope-3x-branch earlier and then had to run the license script again, many (most?) of the files were touched. I am checking these in incrementally, since I ran into trouble overloading the cvs server when I had to do this for my own branch. I will notate the last checkin, and then immediately check it out again to check my work. === Zope3/lib/python/Zope/App/OFS/Content/ZPTPage/Views/__init__.py 1.1.2.2 => 1.1.2.3 === """ -$Id$ +$Id$ """ From garyposter@earthlink.net Thu Apr 4 04:29:46 2002 From: garyposter@earthlink.net (Gary Poster) Date: Wed, 3 Apr 2002 23:29:46 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Formulator/Widgets/Browser/tests - .testinfo:NONE Message-ID: <200204040429.g344TkT24079@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Formulator/Widgets/Browser/tests In directory cvs.zope.org:/tmp/cvs-serv24046 Removed Files: Tag: Zope-3x-branch .testinfo Log Message: removing erroneously readded file === Removed File Zope3/lib/python/Zope/App/Formulator/Widgets/Browser/tests/.testinfo === From srichter@cbu.edu Thu Apr 4 11:35:55 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:35:55 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/VFS/tests Zope3/lib/python/Zope/Publisher/VFS/tests - New directory Message-ID: <200204041135.g34BZt019023@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/VFS/tests In directory cvs.zope.org:/tmp/cvs-serv19015/tests Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/Publisher/VFS/tests added to the repository --> Using per-directory sticky tag `Zope3-Server-Branch' === Added directory Zope3/lib/python/Zope/Publisher/VFS/tests === From srichter@cbu.edu Thu Apr 4 11:38:45 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:38:45 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/Views/VFS Zope3/lib/python/Zope/App/OFS/Container/Views/VFS - New directory Message-ID: <200204041138.g34BcjB21324@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Views/VFS In directory cvs.zope.org:/tmp/cvs-serv21318/VFS Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Views/VFS added to the repository --> Using per-directory sticky tag `Zope3-Server-Branch' === Added directory Zope3/lib/python/Zope/App/OFS/Container/Views/VFS === From srichter@cbu.edu Thu Apr 4 11:44:50 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:44:50 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/Views/VFS - __init__.py:1.1.2.1 Message-ID: <200204041144.g34Biov25157@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Views/VFS In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/App/OFS/Container/Views/VFS Added Files: Tag: Zope3-Server-Branch __init__.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Added File Zope3/lib/python/Zope/App/OFS/Container/Views/VFS/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## From srichter@cbu.edu Thu Apr 4 11:44:51 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:44:51 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication/VFS - Publication.py:1.1.2.1 __init__.py:1.1.4.1 Message-ID: <200204041144.g34Bipi25169@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/VFS In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/App/ZopePublication/VFS Added Files: Tag: Zope3-Server-Branch Publication.py __init__.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Added File Zope3/lib/python/Zope/App/ZopePublication/VFS/Publication.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ $Id: Publication.py,v 1.1.2.1 2002/04/04 11:44:50 srichter Exp $ """ from Zope.App.ZopePublication.ZopePublication import ZopePublication class VFSPublication(ZopePublication): """The Publication will do all the work for the VFS""" === Added File Zope3/lib/python/Zope/App/ZopePublication/VFS/__init__.py === From srichter@cbu.edu Thu Apr 4 11:44:52 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:44:52 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/VFS/tests - __init__.py:1.1.2.1 Message-ID: <200204041144.g34BiqO25200@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/VFS/tests In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Publisher/VFS/tests Added Files: Tag: Zope3-Server-Branch __init__.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Added File Zope3/lib/python/Zope/Publisher/VFS/tests/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.2.1 2002/04/04 11:44:51 srichter Exp $ """ From srichter@cbu.edu Thu Apr 4 11:44:53 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:44:53 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/VFS - IVFSDirectoryPublisher.py:1.1.2.1 IVFSFilePublisher.py:1.1.2.1 IVFSObjectPublisher.py:1.1.2.1 IVFSPublisher.py:1.1.2.1 InfoPublisher.py:1.1.2.1 VFSRequest.py:1.1.2.1 VFSResponse.py:1.1.2.1 __init__.py:1.1.2.1 metaConfigure.py:1.1.2.1 vfs-meta.py:1.1.2.1 vfs-meta.zcml:1.1.2.1 Message-ID: <200204041144.g34Bir625219@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/VFS In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Publisher/VFS Added Files: Tag: Zope3-Server-Branch IVFSDirectoryPublisher.py IVFSFilePublisher.py IVFSObjectPublisher.py IVFSPublisher.py InfoPublisher.py VFSRequest.py VFSResponse.py __init__.py metaConfigure.py vfs-meta.py vfs-meta.zcml Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Added File Zope3/lib/python/Zope/Publisher/VFS/IVFSDirectoryPublisher.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IVFSDirectoryPublisher.py,v 1.1.2.1 2002/04/04 11:44:51 srichter Exp $ """ from IVFSObjectPublisher import IVFSObjectPublisher class IVFSDirectoryPublisher(IVFSObjectPublisher): """ """ def listdir(): """Returns a sequence of names""" def remove(name): """Removes a file""" def rename(oldname, newname): """Renames a file""" def getfile(name): """Returns an existing IVFSObject""" === Added File Zope3/lib/python/Zope/Publisher/VFS/IVFSFilePublisher.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IVFSFilePublisher.py,v 1.1.2.1 2002/04/04 11:44:51 srichter Exp $ """ from IVFSObjectPublisher import IVFSObjectPublisher class IVFSFilePublisher(IVFSObjectPublisher): """ """ def read(): """Returns a string or a stream""" def write(stream): """Writes the stream to this object""" === Added File Zope3/lib/python/Zope/Publisher/VFS/IVFSObjectPublisher.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IVFSObjectPublisher.py,v 1.1.2.1 2002/04/04 11:44:51 srichter Exp $ """ from IVFSPublisher import IVFSPublisher class IVFSObjectPublisher(IVFSPublisher): """ """ def stat(): """Similar to os.stat()""" === Added File Zope3/lib/python/Zope/Publisher/VFS/IVFSPublisher.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IVFSPublisher.py,v 1.1.2.1 2002/04/04 11:44:51 srichter Exp $ """ from Interface import Interface class IVFSPublisher(Interface): def publishTraverse(request, name): """Lookup a name The request argument is the publisher request object. """ === Added File Zope3/lib/python/Zope/Publisher/VFS/InfoPublisher.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: InfoPublisher.py,v 1.1.2.1 2002/04/04 11:44:51 srichter Exp $ """ from IVFSPublisher import IVFSPublisher class InfoPublisher(object): """ """ __implements__ = IVFSPublisher ############################################################ # Implementation methods for interface # Zope.Publisher.VFS.IVFSPublisher. def publishTraverse(self, request, name): 'See Zope.Publisher.VFS.IVFSPublisher.IVFSPublisher' return getattr(self, name) # ############################################################ === Added File Zope3/lib/python/Zope/Publisher/VFS/VFSRequest.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ $Id: VFSRequest.py,v 1.1.2.1 2002/04/04 11:44:51 srichter Exp $ """ from Zope.Publisher.BaseRequest import BaseRequest from IVFSPublisher import IVFSPublisher from VFSResponse import VFSResponse class VFSRequest(BaseRequest): __implements__ = BaseRequest.__implements__ # _viewtype is overridden from the BaseRequest # to implement IVFSPublisher _viewtype = IVFSPublisher def __init__(self, body_instream, outstream, environ): """ """ super(VFSRequest, self).__init__(body_instream, outstream, environ) self._environ = environ self.__setupPath() def _createResponse(self, outstream): """Create a specific XML-RPC response object.""" return VFSResponse(outstream) ###################################### # from: Zope.Publisher.IPublisherRequest.IPublisherRequest def processInputs(self): 'See Zope.Publisher.IPublisherRequest.IPublisherRequest' if self._environ.has_key('command'): self.setPathSuffix((self._environ['command'],)) # ############################################################ def __setupPath(self): path = self.get('PATH_INFO', '/').strip() if path.endswith('/'): path = path[:-1] # XXX Why? Not sure self._endswithslash = 1 else: self._endswithslash = 0 if path.startswith('/'): path = path[1:] # XXX Why? Not sure clean = [] for item in path.split('/'): if item == '.': continue elif item == '..': try: del clean[-1] except IndexError: raise NotFound('..') else: clean.append(item) clean.reverse() self.setTraversalStack(clean) self._path_suffix = None === Added File Zope3/lib/python/Zope/Publisher/VFS/VFSResponse.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ $Id: VFSResponse.py,v 1.1.2.1 2002/04/04 11:44:51 srichter Exp $ """ from Zope.Publisher.BaseResponse import BaseResponse class VFSResponse(BaseResponse): """VFS response """ def setBody(self, body): """Sets the body of the response It is very important to note that in this case the body may not be just a astring, but any Python object. """ # XXX: Handle exceptions self._body = body def getResult(self): """ """ return self._getBody() def handleException(self, exc_info): """ """ t, value = exc_info[:2] import traceback traceback.print_tb(exc_info[2]) print t print value self.setBody(value) === Added File Zope3/lib/python/Zope/Publisher/VFS/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.2.1 2002/04/04 11:44:51 srichter Exp $ """ === Added File Zope3/lib/python/Zope/Publisher/VFS/metaConfigure.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: metaConfigure.py,v 1.1.2.1 2002/04/04 11:44:51 srichter Exp $ """ from Zope.ComponentArchitecture import setDefaultViewName from Zope.Configuration.Action import Action from IVFSPublisher import IVFSPublisher def view(_context, name, factory, for_=None, layer=''): if for_ is not None: for_ = _context.resolve(for_) factory = map(_context.resolve, factory.split(' ')) return [ Action( discriminator = ('defaultViewName', for_, name, IVFSPublisher), callable = setDefaultViewName, args = (for_, IVFSPublisher, name), ) ] === Added File Zope3/lib/python/Zope/Publisher/VFS/vfs-meta.py === === Added File Zope3/lib/python/Zope/Publisher/VFS/vfs-meta.zcml === From srichter@cbu.edu Thu Apr 4 11:44:54 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:44:54 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa - .testinfo:NONE ANNOUNCE.txt:NONE ANNOUNCE_970922.txt:NONE INSTALL.txt:NONE Makefile:NONE __init__.py:NONE asynchat.py:NONE auth_handler.py:NONE chat_server.py:NONE continuation.py:NONE counter.py:NONE default_handler.py:NONE event_loop.py:NONE fifo.py:NONE filesys.py:NONE ftp_server.py:NONE http_bobo.py:NONE http_date.py:NONE http_server.py:NONE logger.py:NONE m_syslog.py:NONE medusa.html:NONE medusa_gif.py:NONE mime_type_table.py:NONE monitor.py:NONE monitor_client.py:NONE monitor_client_win32.py:NONE out:NONE producers.py:NONE put_handler.py:NONE redirecting_handler.py:NONE resolver.py:NONE rpc_client.py:NONE rpc_server.py:NONE script_handler.py:NONE start_medusa.py:NONE status_handler.py:NONE unix_user_handler.py:NONE virtual_handler.py:NONE xmlrpc_handler.py:NONE Message-ID: <200204041144.g34Bise25251@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Server/medusa Removed Files: Tag: Zope3-Server-Branch .testinfo ANNOUNCE.txt ANNOUNCE_970922.txt INSTALL.txt Makefile __init__.py asynchat.py auth_handler.py chat_server.py continuation.py counter.py default_handler.py event_loop.py fifo.py filesys.py ftp_server.py http_bobo.py http_date.py http_server.py logger.py m_syslog.py medusa.html medusa_gif.py mime_type_table.py monitor.py monitor_client.py monitor_client_win32.py out producers.py put_handler.py redirecting_handler.py resolver.py rpc_client.py rpc_server.py script_handler.py start_medusa.py status_handler.py unix_user_handler.py virtual_handler.py xmlrpc_handler.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Removed File Zope3/lib/python/Zope/Server/medusa/.testinfo === === Removed File Zope3/lib/python/Zope/Server/medusa/ANNOUNCE.txt === === Removed File Zope3/lib/python/Zope/Server/medusa/ANNOUNCE_970922.txt === === Removed File Zope3/lib/python/Zope/Server/medusa/INSTALL.txt === === Removed File Zope3/lib/python/Zope/Server/medusa/Makefile === === Removed File Zope3/lib/python/Zope/Server/medusa/__init__.py === === Removed File Zope3/lib/python/Zope/Server/medusa/asynchat.py === === Removed File Zope3/lib/python/Zope/Server/medusa/auth_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/chat_server.py === === Removed File Zope3/lib/python/Zope/Server/medusa/continuation.py === === Removed File Zope3/lib/python/Zope/Server/medusa/counter.py === === Removed File Zope3/lib/python/Zope/Server/medusa/default_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/event_loop.py === === Removed File Zope3/lib/python/Zope/Server/medusa/fifo.py === === Removed File Zope3/lib/python/Zope/Server/medusa/filesys.py === === Removed File Zope3/lib/python/Zope/Server/medusa/ftp_server.py === === Removed File Zope3/lib/python/Zope/Server/medusa/http_bobo.py === === Removed File Zope3/lib/python/Zope/Server/medusa/http_date.py === === Removed File Zope3/lib/python/Zope/Server/medusa/http_server.py === === Removed File Zope3/lib/python/Zope/Server/medusa/logger.py === === Removed File Zope3/lib/python/Zope/Server/medusa/m_syslog.py === === Removed File Zope3/lib/python/Zope/Server/medusa/medusa.html === === Removed File Zope3/lib/python/Zope/Server/medusa/medusa_gif.py === === Removed File Zope3/lib/python/Zope/Server/medusa/mime_type_table.py === === Removed File Zope3/lib/python/Zope/Server/medusa/monitor.py === === Removed File Zope3/lib/python/Zope/Server/medusa/monitor_client.py === === Removed File Zope3/lib/python/Zope/Server/medusa/monitor_client_win32.py === === Removed File Zope3/lib/python/Zope/Server/medusa/out === === Removed File Zope3/lib/python/Zope/Server/medusa/producers.py === === Removed File Zope3/lib/python/Zope/Server/medusa/put_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/redirecting_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/resolver.py === === Removed File Zope3/lib/python/Zope/Server/medusa/rpc_client.py === === Removed File Zope3/lib/python/Zope/Server/medusa/rpc_server.py === === Removed File Zope3/lib/python/Zope/Server/medusa/script_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/start_medusa.py === === Removed File Zope3/lib/python/Zope/Server/medusa/status_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/unix_user_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/virtual_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/xmlrpc_handler.py === From srichter@cbu.edu Thu Apr 4 11:44:54 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:44:54 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - PublisherFileSystem.py:1.1.2.1 PublisherVFSTask.py:1.1.2.1 ZODBFileSystem.py:NONE Message-ID: <200204041144.g34Bisv25245@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Server/VFS Added Files: Tag: Zope3-Server-Branch PublisherFileSystem.py PublisherVFSTask.py Removed Files: Tag: Zope3-Server-Branch ZODBFileSystem.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Added File Zope3/lib/python/Zope/Server/VFS/PublisherFileSystem.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: PublisherFileSystem.py,v 1.1.2.1 2002/04/04 11:44:53 srichter Exp $ """ import os, re import stat import time from IReadFileSystem import IReadFileSystem from IWriteFileSystem import IWriteFileSystem from Zope.Publisher.Publish import publish from ListProducer import ListProducer class PublisherFileSystem: """Generic Publisher FileSystem implementation. """ __implements__ = IReadFileSystem, IWriteFileSystem request_factory = None def __init__ (self, root): self.root = root def _execute(self, path, command, env=None): if env is None: env = {} env['command'] = command env['path'] = path request = self.request_factory(StringIO(''), StringIO(''), env) publish(request) return request.getResponse().getResult() ############################################################ # Implementation methods for interface # Zope.Server.VFS.IReadFileSystem.IReadFileSystem def exists(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) return self._execute(path, 'exists') def isdir(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) return self._execute(path, 'isdir') def isfile(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) return self._execute(path, 'isfile') def listdir(self, path, long=0): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) # Returns a list of Wrapper objects representing the objects # Also, the Wrapper object should contain *all* stat information ld = self._execute(path, 'listdir') ld.sort() if not long: return ListProducer(ld, 0, None) else: return ListProducer(result, 1, self.longify) def longify(self, (path, stat_info)): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' return unix_longify (path, stat_info) def open(self, path, mode): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) return self._execute(path, 'open', {'mode': mode}) def stat(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) return self._execute(path, 'stat') # ############################################################ ############################################################ # Implementation methods for interface # Zope.Server.VFS.IWriteFileSystem. def chmod(self, path, mode): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' p = self.translate (path) return os.chmod(p, mode) def chown(self, path, uid, gid): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' p = self.translate (path) raise NotImplementedError('This function is not implemented.') def link(self, src, dst): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' src = self.translate(src) dst = self.translate(dst) raise NotImplementedError('This function is not implemented.') def mkdir(self, path, mode=6*2**6): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' p = self.translate(path) def mkfifo(self, path, mode=6*2**6): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' raise NotImplementedError('This function is not implemented.') def remove(self, path): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' p = self.translate (path) def rmdir(self, path): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' p = self.translate (path) def rename(self, old, new): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' old = self.translate(old) new = self.translate(new) def symlink(self, src, dst): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' src = self.translate(src) dst = self.translate(dst) raise NotImplementedError('This function is not implemented.') def unlink(self, path): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' pass def write(self, fd, data): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' pass # ############################################################ # utility methods def normalize (self, path): # watch for the ever-sneaky '/+' path element path = re.sub('/+', '/', path) # Someone is trying to get lower than the permitted root. # We just ignore it. path = os.path.normpath(path) if path.startswith('..'): path = '/' return path def translate (self, path): """We need to join together three separate path components, and do it safely. / use the operating system's path separator. We need to be extremly careful to include the cases where a hacker could attempt to a directory below root! """ # Normalize the directory path = os.sep.join(path.split('/')) path = self.normalize(self.path_module.join(path)) # Prepare for joining with root if path[0] == '/': path = path[1:] # Join path with root path = self.path_module.join(self.root, path) return path def __repr__ (self): return '' % self.root months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] mode_table = { '0':'---', '1':'--x', '2':'-w-', '3':'-wx', '4':'r--', '5':'r-x', '6':'rw-', '7':'rwx' } def unix_longify (file, stat_info): # for now, only pay attention to the lower bits import pwd, grp try: username = pwd.getpwuid(int(stat_info[stat.ST_UID]))[0] except: username = stat_info[stat.ST_UID] try: grpname = grp.getgrgid(int(stat_info[stat.ST_GID]))[0] except: grpname = stat_info[stat.ST_GID] mode = ('%o' % stat_info[stat.ST_MODE])[-3:] mode = ''.join(map (lambda x: mode_table[x], mode)) if stat.S_ISDIR (stat_info[stat.ST_MODE]): dirchar = 'd' else: dirchar = '-' date = ls_date (long(time.time()), stat_info[stat.ST_MTIME]) return '%s%s %3d %-8s %-8s %8d %s %s' % ( dirchar, mode, stat_info[stat.ST_NLINK], username, grpname, stat_info[stat.ST_SIZE], date, file ) def ls_date (now, t): """Emulate the unix 'ls' command's date field. it has two formats - if the date is more than 180 days in the past, then it's like this: Oct 19 1995 otherwise, it looks like this: Oct 19 17:33 """ try: info = time.gmtime(t) except: info = time.gmtime(0) # 15,600,000 == 86,400 * 180 if (now - t) > 15600000: return '%s %2d %d' % ( months[info[1]-1], info[2], info[0] ) else: return '%s %2d %02d:%02d' % ( months[info[1]-1], info[2], info[3], info[4] ) def safe_stat (path): try: return os.stat(path) except: return None === Added File Zope3/lib/python/Zope/Server/VFS/PublisherVFSTask.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: PublisherVFSTask.py,v 1.1.2.1 2002/04/04 11:44:53 srichter Exp $ """ import socket from Zope.Server.ITask import ITask class FTPTask: """ """ __implements__ = ITask def __init__(self, channel, command, m_name): self.channel = channel self.m_name = m_name self.args = command.args ############################################################ # Implementation methods for interface # Zope.Server.ITask def service(self): """Called to execute the task. """ try: try: self.start() getattr(self, self.m_name)(self.args) self.finish() except socket.error: self.close_on_finish = 1 if self.channel.adj.log_socket_errors: raise finally: self.channel.end_task(self.close_on_finish) def cancel(self): 'See Zope.Server.ITask.ITask' self.channel.close_when_done() def defer(self): 'See Zope.Server.ITask.ITask' pass # ############################################################ def start(self): now = time.time() self.start_time = now def finish(self): hit_log = self.channel.server.hit_log if hit_log is not None: hit_log.log(self) === Removed File Zope3/lib/python/Zope/Server/VFS/ZODBFileSystem.py === From srichter@cbu.edu Thu Apr 4 11:44:54 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:44:54 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/contrib - bobo_handler.py:NONE sample_cgi.py:NONE Message-ID: <200204041144.g34Bisb25255@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/contrib In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Server/medusa/contrib Removed Files: Tag: Zope3-Server-Branch bobo_handler.py sample_cgi.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Removed File Zope3/lib/python/Zope/Server/medusa/contrib/bobo_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/contrib/sample_cgi.py === From srichter@cbu.edu Thu Apr 4 11:44:55 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:44:55 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/demo - publish.py:NONE Message-ID: <200204041144.g34Bitk25264@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/demo In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Server/medusa/demo Removed Files: Tag: Zope3-Server-Branch publish.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Removed File Zope3/lib/python/Zope/Server/medusa/demo/publish.py === From srichter@cbu.edu Thu Apr 4 11:44:56 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:44:56 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/dist - license.html:NONE Message-ID: <200204041144.g34Bit125274@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/dist In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Server/medusa/dist Removed Files: Tag: Zope3-Server-Branch license.html Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Removed File Zope3/lib/python/Zope/Server/medusa/dist/license.html === From srichter@cbu.edu Thu Apr 4 11:44:56 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:44:56 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/docs - README.html:NONE composing_producers.gif:NONE data_flow.gif:NONE data_flow.html:NONE producers.gif:NONE proxy_notes.txt:NONE Message-ID: <200204041144.g34BitU25275@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/docs In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Server/medusa/docs Removed Files: Tag: Zope3-Server-Branch README.html composing_producers.gif data_flow.gif data_flow.html producers.gif proxy_notes.txt Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Removed File Zope3/lib/python/Zope/Server/medusa/docs/README.html === === Removed File Zope3/lib/python/Zope/Server/medusa/docs/composing_producers.gif === === Removed File Zope3/lib/python/Zope/Server/medusa/docs/data_flow.gif === === Removed File Zope3/lib/python/Zope/Server/medusa/docs/data_flow.html === === Removed File Zope3/lib/python/Zope/Server/medusa/docs/producers.gif === === Removed File Zope3/lib/python/Zope/Server/medusa/docs/proxy_notes.txt === From srichter@cbu.edu Thu Apr 4 11:44:56 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:44:56 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/misc - async_mysql.py:NONE recorder.py:NONE syncsock.py:NONE Message-ID: <200204041144.g34Biuv25276@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/misc In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Server/medusa/misc Removed Files: Tag: Zope3-Server-Branch async_mysql.py recorder.py syncsock.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Removed File Zope3/lib/python/Zope/Server/medusa/misc/async_mysql.py === === Removed File Zope3/lib/python/Zope/Server/medusa/misc/recorder.py === === Removed File Zope3/lib/python/Zope/Server/medusa/misc/syncsock.py === From srichter@cbu.edu Thu Apr 4 11:44:56 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:44:56 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/script_handler_demo - form.mpy:NONE persistent.py:NONE start_demo.py:NONE today.mpy:NONE Message-ID: <200204041144.g34BiuE25290@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/script_handler_demo In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Server/medusa/script_handler_demo Removed Files: Tag: Zope3-Server-Branch form.mpy persistent.py start_demo.py today.mpy Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Removed File Zope3/lib/python/Zope/Server/medusa/script_handler_demo/form.mpy === === Removed File Zope3/lib/python/Zope/Server/medusa/script_handler_demo/persistent.py === === Removed File Zope3/lib/python/Zope/Server/medusa/script_handler_demo/start_demo.py === === Removed File Zope3/lib/python/Zope/Server/medusa/script_handler_demo/today.mpy === From srichter@cbu.edu Thu Apr 4 11:44:57 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:44:57 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/thread - __init__.py:NONE pi_module.py:NONE select_trigger.py:NONE test_module.py:NONE thread_channel.py:NONE thread_handler.py:NONE Message-ID: <200204041144.g34BivC25318@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/thread In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Server/medusa/thread Removed Files: Tag: Zope3-Server-Branch __init__.py pi_module.py select_trigger.py test_module.py thread_channel.py thread_handler.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Removed File Zope3/lib/python/Zope/Server/medusa/thread/__init__.py === === Removed File Zope3/lib/python/Zope/Server/medusa/thread/pi_module.py === === Removed File Zope3/lib/python/Zope/Server/medusa/thread/select_trigger.py === === Removed File Zope3/lib/python/Zope/Server/medusa/thread/test_module.py === === Removed File Zope3/lib/python/Zope/Server/medusa/thread/thread_channel.py === === Removed File Zope3/lib/python/Zope/Server/medusa/thread/thread_handler.py === From srichter@cbu.edu Thu Apr 4 11:44:57 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:44:57 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/sendfile - README:NONE asynchat_sendfile.py:NONE sendfilemodule.c:NONE test_sendfile.py:NONE Message-ID: <200204041144.g34BivO25305@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/sendfile In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Server/medusa/sendfile Removed Files: Tag: Zope3-Server-Branch README asynchat_sendfile.py sendfilemodule.c test_sendfile.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Removed File Zope3/lib/python/Zope/Server/medusa/sendfile/README === === Removed File Zope3/lib/python/Zope/Server/medusa/sendfile/asynchat_sendfile.py === === Removed File Zope3/lib/python/Zope/Server/medusa/sendfile/sendfilemodule.c === === Removed File Zope3/lib/python/Zope/Server/medusa/sendfile/test_sendfile.py === From srichter@cbu.edu Thu Apr 4 11:44:56 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:44:56 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/notes - async_blurbs.txt:NONE debugging.txt:NONE threads.txt:NONE tkinter.txt:NONE Message-ID: <200204041144.g34BiuW25284@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/notes In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Server/medusa/notes Removed Files: Tag: Zope3-Server-Branch async_blurbs.txt debugging.txt threads.txt tkinter.txt Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Removed File Zope3/lib/python/Zope/Server/medusa/notes/async_blurbs.txt === === Removed File Zope3/lib/python/Zope/Server/medusa/notes/debugging.txt === === Removed File Zope3/lib/python/Zope/Server/medusa/notes/threads.txt === === Removed File Zope3/lib/python/Zope/Server/medusa/notes/tkinter.txt === From srichter@cbu.edu Thu Apr 4 11:44:58 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:44:58 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/StartUp - ServerType.py:1.1.2.2.2.1 SiteDefinition.py:1.1.2.1.4.1 startup-registry.zcml:1.1.2.1.4.2 Message-ID: <200204041144.g34Biw025324@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/StartUp In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/StartUp Modified Files: Tag: Zope3-Server-Branch ServerType.py SiteDefinition.py startup-registry.zcml Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Zope3/lib/python/Zope/StartUp/ServerType.py 1.1.2.2 => 1.1.2.2.2.1 === # ############################################################################## -""" - -$Id$ -""" - -from Interface import Interface -from RequestFactoryRegistry import getRequestFactory - - -class IServerType(Interface): - """This is a pure read-only interface, since the values are set through - a ZCML directive and we shouldn't be able to change them. - """ - - def create(task_dispatcher, db, port=None, verbose=None): - """Create the server knowing the port, task dispatcher and the ZODB. - """ - - -class ServerType: - - __implements__ = IServerType - - - def __init__(self, name, factory, requestFactory, logFactory, - defaultPort, defaultVerbose): - """ """ - self._name = name - self._factory = factory - self._requestFactory = requestFactory - self._logFactory = logFactory - self._defaultPort = defaultPort - self._defaultVerbose = defaultVerbose - - - ############################################################ - # Implementation methods for interface - # Zope.StartUp.ServerType.IServerType - - def create(self, task_dispatcher, db, port=None, verbose=None): - 'See Zope.StartUp.ServerType.IServerType' - - - request_factory = getRequestFactory(self._requestFactory) - request_factory = request_factory.realize(db) - - if port is None: - port = self._defaultPort - - if verbose is None: - verbose = self._defaultVerbose - - apply(self._factory, - (request_factory, self._name, '', port), - {'task_dispatcher': task_dispatcher, - 'verbose': verbose, - 'hit_log': self._logFactory()}) - - # - ############################################################ - - +"""e.py,v 1.1.2.2 2002/04/02 02:20:40 srichter Exp $ +""" + +from Interface import Interface +from RequestFactoryRegistry import getRequestFactory + + +class IServerType(Interface): + """This is a pure read-only interface, since the values are set through + a ZCML directive and we shouldn't be able to change them. + """ + + def create(task_dispatcher, db, port=None, verbose=None): + """Create the server knowing the port, task dispatcher and the ZODB. + """ + + +class ServerType: + + __implements__ = IServerType + + + def __init__(self, name, factory, requestFactory, logFactory, + defaultPort, defaultVerbose): + """ """ + self._name = name + self._factory = factory + self._requestFactory = requestFactory + self._logFactory = logFactory + self._defaultPort = defaultPort + self._defaultVerbose = defaultVerbose + + + ############################################################ + # Implementation methods for interface + # Zope.StartUp.ServerType.IServerType + + def create(self, task_dispatcher, db, port=None, verbose=None): + 'See Zope.StartUp.ServerType.IServerType' + + request_factory = getRequestFactory(self._requestFactory) + request_factory = request_factory.realize(db) + + if port is None: + port = self._defaultPort + + if verbose is None: + verbose = self._defaultVerbose + + apply(self._factory, + (request_factory, self._name, '', port), + {'task_dispatcher': task_dispatcher, + 'verbose': verbose, + 'hit_log': self._logFactory()}) + + # + ############################################################ + + === Zope3/lib/python/Zope/StartUp/SiteDefinition.py 1.1.2.1 => 1.1.2.1.4.1 === # not create one. self._initDB() - + # Start the servers for type, server_info in self._servers.items(): server = getServerType(type) - server.create(td, self._zodb, server_info['port'], server_info['verbose']) - def _initDB(self): """Initialize the ZODB""" === Zope3/lib/python/Zope/StartUp/startup-registry.zcml 1.1.2.1.4.1 => 1.1.2.1.4.2 === + + + + + From srichter@cbu.edu Thu Apr 4 11:45:20 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:45:20 -0500 Subject: [Zope-Checkins] CVS: Zope3 - startup.zcml:1.1.2.3.4.1 Message-ID: <200204041145.g34BjKL25458@cvs.baymountain.com> Update of /cvs-repository/Zope3 In directory cvs.zope.org:/tmp/cvs-serv21650 Modified Files: Tag: Zope3-Server-Branch startup.zcml Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Zope3/startup.zcml 1.1.2.3 => 1.1.2.3.4.1 === Browser - A standard HTML/XUL server XML-RPC - An XML-RPC server, for calling objects remotely + FTP - A server to access the ZODB via the FTP protocol Soon: SOAP - An SOAP server for Zope based on ZSI - FTP - A server to access the ZODB via the FTP protocol The 'port' option specifies the port the server should run on of course. @@ -46,6 +46,7 @@ + From srichter@cbu.edu Thu Apr 4 11:44:57 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:44:57 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/test - __init__.py:NONE asyn_http_bench.py:NONE max_sockets.py:NONE test_11.py:NONE test_lb.py:NONE test_medusa.py:NONE test_single_11.py:NONE tests.txt:NONE Message-ID: <200204041144.g34Bivs25315@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/test In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Server/medusa/test Removed Files: Tag: Zope3-Server-Branch __init__.py asyn_http_bench.py max_sockets.py test_11.py test_lb.py test_medusa.py test_single_11.py tests.txt Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Removed File Zope3/lib/python/Zope/Server/medusa/test/__init__.py === === Removed File Zope3/lib/python/Zope/Server/medusa/test/asyn_http_bench.py === === Removed File Zope3/lib/python/Zope/Server/medusa/test/max_sockets.py === === Removed File Zope3/lib/python/Zope/Server/medusa/test/test_11.py === === Removed File Zope3/lib/python/Zope/Server/medusa/test/test_lb.py === === Removed File Zope3/lib/python/Zope/Server/medusa/test/test_medusa.py === === Removed File Zope3/lib/python/Zope/Server/medusa/test/test_single_11.py === === Removed File Zope3/lib/python/Zope/Server/medusa/test/tests.txt === From srichter@cbu.edu Thu Apr 4 11:45:21 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:45:21 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/Browser - AttributePublisher.py:1.1.2.14.2.1 Message-ID: <200204041145.g34BjLM25471@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/Browser In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Publisher/Browser Modified Files: Tag: Zope3-Server-Branch AttributePublisher.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Zope3/lib/python/Zope/Publisher/Browser/AttributePublisher.py 1.1.2.14 => 1.1.2.14.2.1 === # ############################################################################## +""" + +$Id$ +""" from IBrowserPublisher import IBrowserPublisher class AttributePublisher(object): From srichter@cbu.edu Thu Apr 4 11:45:21 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:45:21 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher - Publish.py:1.1.2.16.2.1 publisher-meta.zcml:1.1.4.1.6.1 Message-ID: <200204041145.g34BjLJ25469@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Publisher Modified Files: Tag: Zope3-Server-Branch Publish.py publisher-meta.zcml Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Zope3/lib/python/Zope/Publisher/Publish.py 1.1.2.16 => 1.1.2.16.2.1 === # ############################################################################## -__doc__="""Python Object Publisher -- Publish Python objects on web servers +""" +Python Object Publisher -- Publish Python objects on web servers + +$Id$ +""" -$Id$""" -__version__='$Revision$'[11:-2] import sys, os from Exceptions import Retry === Zope3/lib/python/Zope/Publisher/publisher-meta.zcml 1.1.4.1 => 1.1.4.1.6.1 === + From srichter@cbu.edu Thu Apr 4 11:45:20 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:45:20 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication - ZopePublication.py:1.1.2.33.2.1 Message-ID: <200204041145.g34BjK025465@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/App/ZopePublication Modified Files: Tag: Zope3-Server-Branch ZopePublication.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Zope3/lib/python/Zope/App/ZopePublication/ZopePublication.py 1.1.2.33 => 1.1.2.33.2.1 === from PublicationTraverse import PublicationTraverse -from Zope.Publisher.Browser.IBrowserPublisher import IBrowserPublisher - class RequestContainer: # TODO: add security assertion declaring access to REQUEST From srichter@cbu.edu Thu Apr 4 11:45:23 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:45:23 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/HTTP - PublisherHTTPTask.py:1.1.2.2 Message-ID: <200204041145.g34BjNY25491@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/HTTP In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Server/HTTP Modified Files: Tag: Zope3-Server-Branch PublisherHTTPTask.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Zope3/lib/python/Zope/Server/HTTP/PublisherHTTPTask.py 1.1.2.1 => 1.1.2.2 === server = channel.server - while path and path[0] == '/': + while path and path.startswith('/'): path = path[1:] env = {} From srichter@cbu.edu Thu Apr 4 11:45:23 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:45:23 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/Authentication/tests - testDictionaryAuthentication.py:1.1.2.2 Message-ID: <200204041145.g34BjNr25481@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/Authentication/tests In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Server/Authentication/tests Modified Files: Tag: Zope3-Server-Branch testDictionaryAuthentication.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Zope3/lib/python/Zope/Server/Authentication/tests/testDictionaryAuthentication.py 1.1.2.1 => 1.1.2.2 === - def testAuthenticationUsers(self): - self.assertEqual(self.auth.user_class, SimpleUser) - self.assertEqual(self.auth.anonymous_user, AnonymousUser) - - def testAuthenticate(self): - self.assertEqual(self.auth.authenticate('foo', 'bar').username, - SimpleUser('foo').username) - self.assertEqual(self.auth.authenticate('blah', ''), - AnonymousUser) - self.assertEqual(self.auth.authenticate('foo', 'nonesense'), - AnonymousUser) + self.failUnless(self.auth.authenticate('foo', 'bar')[0]) + self.failIf(self.auth.authenticate('blah', '')[0]) + self.failIf(self.auth.authenticate('foo', 'nonesense')[0]) def testInterface(self): From srichter@cbu.edu Thu Apr 4 11:45:22 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:45:22 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/HTTP - DefaultPublisher.py:1.1.2.2.2.1 Message-ID: <200204041145.g34BjMH25475@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/HTTP In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Publisher/HTTP Modified Files: Tag: Zope3-Server-Branch DefaultPublisher.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Zope3/lib/python/Zope/Publisher/HTTP/DefaultPublisher.py 1.1.2.2 => 1.1.2.2.2.1 === # ############################################################################## -""" - -$Id$ -""" -from IHTTPPublisher import IHTTPPublisher - - -class DefaultPublisher: - - __implements__ = IHTTPPublisher - - ############################################################ - # Implementation methods for interface - # Zope.Publisher.HTTP.IHTTPPublisher - - def publishTraverse(self, request, name): - 'See Zope.Publisher.HTTP.IHTTPPublisher.IHTTPPublisher' - - return getattr(self, name) - - # - ############################################################ +"""blisher.py,v 1.1.2.2 2002/04/02 02:20:33 srichter Exp $ +""" +from IHTTPPublisher import IHTTPPublisher + + +class DefaultPublisher: + + __implements__ = IHTTPPublisher + + ############################################################ + # Implementation methods for interface + # Zope.Publisher.HTTP.IHTTPPublisher + + def publishTraverse(self, request, name): + 'See Zope.Publisher.HTTP.IHTTPPublisher.IHTTPPublisher' + + return getattr(self, name) + + # + ############################################################ From srichter@cbu.edu Thu Apr 4 11:45:22 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:45:22 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/Authentication - IAuthentication.py:1.1.2.3 Message-ID: <200204041145.g34BjMP25478@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/Authentication In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Server/Authentication Modified Files: Tag: Zope3-Server-Branch IAuthentication.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Zope3/lib/python/Zope/Server/Authentication/IAuthentication.py 1.1.2.2 => 1.1.2.3 === """ - user_class = Attribute(""" - This attribute contains the user factory that is used - once the user is authenticated. - """) - - anonymous_user = Attribute("""The instance of the anonymous user.""") - - def authenticate(username, password): """ """ From srichter@cbu.edu Thu Apr 4 11:45:23 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:45:23 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/HTTP/tests - testHTTPServer.py:1.1.2.2 Message-ID: <200204041145.g34BjNA25498@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/HTTP/tests In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Server/HTTP/tests Modified Files: Tag: Zope3-Server-Branch testHTTPServer.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Zope3/lib/python/Zope/Server/HTTP/tests/testHTTPServer.py 1.1.2.1 => 1.1.2.2 === import socket -from Zope.Server.medusa.thread import select_trigger from threading import Thread from Zope.Server.TaskThreads import ThreadedTaskDispatcher from Zope.Server.HTTP.HTTPServer import HTTPServer @@ -47,7 +46,7 @@ my_adj.inbuf_overflow = 10000 -class EchoHTTPTask (HTTPTask): +class EchoHTTPTask(HTTPTask): def execute(self): headers = self.request_data.headers @@ -62,12 +61,12 @@ self.write(data) -class EchoHTTPChannel (HTTPServerChannel): +class EchoHTTPChannel(HTTPServerChannel): task_class = EchoHTTPTask -class EchoHTTPServer (HTTPServer): +class EchoHTTPServer(HTTPServer): channel_class = EchoHTTPChannel From srichter@cbu.edu Thu Apr 4 11:45:24 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 06:45:24 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - PublisherFTPServer.py:1.1.2.1 CommonFTPActivityLogger.py:1.1.2.2 FTPServer.py:1.1.2.4 FTPServerChannel.py:1.1.2.8 FTPTask.py:1.1.2.2 Message-ID: <200204041145.g34BjOQ25493@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv21650/lib/python/Zope/Server/FTP Modified Files: Tag: Zope3-Server-Branch CommonFTPActivityLogger.py FTPServer.py FTPServerChannel.py FTPTask.py Added Files: Tag: Zope3-Server-Branch PublisherFTPServer.py Log Message: Worked some more on FTP, especially in regards with the Publisher. - Finally we can get rid of the medusa base. I think I have extracted all of the interesting code. - Started on a PublisherFileSystem. A few methods might work, but most of the FS methods are not hooked up yet. - Started writing VFS Publisher hooks. - Added the FTPServer to the startup registry. It comes up, but do not expect it to work, since no views have been written for VFS yet. === Added File Zope3/lib/python/Zope/Server/FTP/PublisherFTPServer.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: PublisherFTPServer.py,v 1.1.2.1 2002/04/04 11:44:52 srichter Exp $ """ from FTPServer import FTPServer from Zope.Server.VFS.PublisherFileSystem import PublisherFileSystem class PublisherFTPServer(FTPServer): """Zope Publisher-specific HTTP Server""" __implements__ = FTPServer.__implements__ filesystem = PublisherFileSystem('/') def __init__(self, request_factory, sub_protocol=None, *args, **kw): self.request_factory = request_factory self.filesystem.request_factory = self.request_factory if sub_protocol: self.SERVER_IDENT += ' (%s)' %sub_protocol FTPServer.__init__(self, *args, **kw) === Zope3/lib/python/Zope/Server/FTP/CommonFTPActivityLogger.py 1.1.2.1 => 1.1.2.2 === """ -class CommonActivityLogger: - """This logger's output is +import time +import sys + +from Zope.Server.Logger.FileLogger import FileLogger +from Zope.Server.Logger.ResolvingLogger import ResolvingLogger +from Zope.Server.Logger.UnresolvingLogger import UnresolvingLogger + + +class CommonFTPActivityLogger: + """Outputs hits in common HTTP log format. """ - pass + + def __init__(self, logger_object=None, resolver=None): + if logger_object is None: + logger_object = FileLogger(sys.stdout) + + if resolver is not None: + self.output = ResolvingLogger(resolver, logger_object) + else: + self.output = UnresolvingLogger(logger_object) + + + def log(self, task): + """ + Receives a completed task and logs it in the + common log format. + """ + + now = time.localtime(time.time()) + + print now + self.output.log('127.0.0.1', time.strftime('%Y/%m/%d %H:%M', now)) === Zope3/lib/python/Zope/Server/FTP/FTPServer.py 1.1.2.3 => 1.1.2.4 === def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1, hit_log=None, verbose=0, socket_map=None): - super(FTPServer, self).__init__(ip, port, task_dispatcher=None, - adj=None, start=1, hit_log=None, - verbose=0, socket_map=None) + super(FTPServer, self).__init__(ip, port, task_dispatcher, + adj, start, hit_log, + verbose, socket_map) # statistics self.total_sessions = Counter() === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.7 => 1.1.2.8 === +# These are the commands that are accessing the filesystem. +# Since this could be also potentially a longer process, these commands +# are slao the ones that are executed in a different thread. +fs_access_cmds = ('cmd_appe', 'cmd_cdup', 'cmd_cwd', 'cmd_dele', 'cmd_list', + 'cmd_nlst', 'cmd_mdtm', 'cmd_mkd', 'cmd_pass', 'cmd_retr', + 'cmd_rmd', 'cmd_rnfr', 'cmd_rnto', 'cmd_size', 'cmd_stor', + 'cmd_stru') + + class FTPServerChannel(ServerChannelBase): """The FTP Server Channel represents a connection to a particular client. We can therefore store information here.""" @@ -97,33 +106,26 @@ Some commands use an alternate thread. """ - assert isinstance(command, FTPCommandParser) cmd = command.cmd - m = 'cmd_' + cmd.lower() + method = 'cmd_' + cmd.lower() if ( not self.authenticated and - m not in ('cmd_user', 'cmd_pass', 'cmd_quit')): + method not in ('cmd_user', 'cmd_pass', 'cmd_quit')): # The user is not logged in, therefore don't allow anything self.reply(530, 1) - elif m == 'cmd_': - # The empty case is very important, since the server crashes - # otherwise - self.reply(500, 0, ('')) - - elif hasattr(self, m): - # Quick processing - getattr(self, m)(command.args) + elif method in fs_access_cmds: + # Process in another thread. + task = self.task_class(self, command, method) + self.set_sync() + self.server.addTask(task) + return + + elif hasattr(self, method): + getattr(self, method)(command.args) else: - # Process in another thread. - task = self.task_class(self, command, m) - if hasattr(task, m): - self.set_sync() - self.server.addTask(task) - return - else: - self.reply(500, 0, (cmd.upper())) + self.reply(500, 0, (cmd.upper())) self.end_task(0) === Zope3/lib/python/Zope/Server/FTP/FTPTask.py 1.1.2.1 => 1.1.2.2 === import socket +import time from Zope.Server.ITask import ITask @@ -32,6 +33,8 @@ self.m_name = m_name self.args = command.args + self.close_on_finish = 0 + ############################################################ # Implementation methods for interface @@ -43,7 +46,7 @@ try: try: self.start() - getattr(self, self.m_name)(self.args) + getattr(self.channel, self.m_name)(self.args) self.finish() except socket.error: self.close_on_finish = 1 From shane@cvs.zope.org Thu Apr 4 16:24:36 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 11:24:36 -0500 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - SimpleItem.py:1.96 Message-ID: <200204041624.g34GOaJ19943@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv19918/lib/python/OFS Modified Files: SimpleItem.py Log Message: We have to use str() instead of repr() because the error value can be HTML. Ugh. === Zope/lib/python/OFS/SimpleItem.py 1.95 => 1.96 === LOG('OFS', ERROR, 'Exception while rendering an error message', error=sys.exc_info()) - v = repr(error_value) + ( + v = str(error_value) + ( " (Also, an error occurred while attempting " "to render the standard error message.)") raise error_type, v, tb From shane@cvs.zope.org Thu Apr 4 16:25:44 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 11:25:44 -0500 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/SiteErrorLog - SiteErrorLog.py:1.3 Message-ID: <200204041625.g34GPiq20266@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/SiteErrorLog In directory cvs.zope.org:/tmp/cvs-serv20254 Modified Files: SiteErrorLog.py Log Message: When displaying a traceback as text, show it alone with a text/plain content type. === Zope/lib/python/Products/SiteErrorLog/SiteErrorLog.py 1.2 => 1.3 === from zLOG import LOG, ERROR +# Permission names use_error_logging = 'Log Site Errors' log_to_event_log = 'Log to the Event Log' @@ -204,6 +205,18 @@ return entry.copy() return None + security.declareProtected(use_error_logging, 'getLogEntryAsText') + def getLogEntryAsText(self, id, RESPONSE=None): + """Returns the specified log entry. + + Makes a copy to prevent changes. Returns None if not found. + """ + entry = self.getLogEntryById(id) + if entry is None: + return 'Log entry not found or expired' + if RESPONSE is not None: + RESPONSE.setHeader('Content-Type', 'text/plain') + return entry['tb_text'] Globals.InitializeClass(SiteErrorLog) From shane@cvs.zope.org Thu Apr 4 16:25:44 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 11:25:44 -0500 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/SiteErrorLog/www - showEntry.pt:1.3 Message-ID: <200204041625.g34GPiN20267@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/SiteErrorLog/www In directory cvs.zope.org:/tmp/cvs-serv20254/www Modified Files: showEntry.pt Log Message: When displaying a traceback as text, show it alone with a text/plain content type. === Zope/lib/python/Products/SiteErrorLog/www/showEntry.pt 1.2 => 1.3 ===
-
-
-Traceback +
+Traceback (HTML)
+
+Traceback (text)
+
+

Display + string:getLogEntryAsText?id=${entry/id}">Display traceback as text

-
- -
-
-Traceback
-
-

Display - traceback as HTML

-

REQUEST

From shane@cvs.zope.org Thu Apr 4 18:45:58 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 13:45:58 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS/tests - __init__.py:1.1.2.2 testOSFileSystem.py:1.1.2.4 Message-ID: <200204041845.g34Ijwr18115@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS/tests In directory cvs.zope.org:/tmp/cvs-serv17993/VFS/tests Modified Files: Tag: Zope3-Server-Branch __init__.py testOSFileSystem.py Log Message: Just fixed line endings. No carriage returns. === Zope3/lib/python/Zope/Server/VFS/tests/__init__.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ === Zope3/lib/python/Zope/Server/VFS/tests/testOSFileSystem.py 1.1.2.3 => 1.1.2.4 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - - -import unittest -import os -import stat -import tempfile - -from Interface.Verify import verifyClass -from Zope.Server.VFS.IReadFileSystem import IReadFileSystem -from Zope.Server.VFS.IWriteFileSystem import IWriteFileSystem - -from Zope.Server.VFS.OSFileSystem import OSFileSystem - -class OSFileSystemTest(unittest.TestCase): - """This test is constructed in a way that it builds up a directory - structure, whcih is removed at the end. - """ - - filesystem_class = OSFileSystem - root = None - - def setUp(self): - if self.root is None: - self.root = tempfile.mktemp() - self.filesystem = self.filesystem_class(self.root) - - os.mkdir(self.root) - - - def tearDown(self): - os.rmdir(self.root) - - - def testNormalize(self): - - self.assertEqual(self.filesystem.normalize('/foo/bar//'), '/foo/bar') - self.assertEqual(self.filesystem.normalize('/foo//bar'), '/foo/bar') - self.assertEqual(self.filesystem.normalize('///foo/bar'), '/foo/bar') - self.assertEqual(self.filesystem.normalize('///foo//bar////'), - '/foo/bar') - - self.assertEqual(self.filesystem.normalize('../foo/bar'), '/') - self.assertEqual(self.filesystem.normalize('..'), '/') - self.assertEqual(self.filesystem.normalize('/..'), '/') - self.assertEqual(self.filesystem.normalize('/foo/..'), '/') - self.assertEqual(self.filesystem.normalize('/foo/../bar'), '/bar') - self.assertEqual(self.filesystem.normalize('../../'), '/') - - self.assertEqual(self.filesystem.normalize('///../foo/bar'), '/foo/bar') - self.assertEqual(self.filesystem.normalize('/foo/..///'), '/') - self.assertEqual(self.filesystem.normalize('///foo/..//bar'), '/bar') - self.assertEqual(self.filesystem.normalize('..///../'), '/') - - - def testTranslate(self): - - self.assertEqual(self.filesystem.root, self.root) - - self.assertEqual(self.filesystem.translate('/foo/'), - self.filesystem.path_module.join(self.root, 'foo')) - self.assertEqual(self.filesystem.translate('/foo/bar'), - self.filesystem.path_module.join(self.root, - 'foo', 'bar')) - self.assertEqual(self.filesystem.translate('foo/bar'), - self.filesystem.path_module.join(self.root, - 'foo', 'bar')) - - def testExists(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('test') - self.failUnless(self.filesystem.exists('foo')) - os.remove(path) - - - def testIsDir(self): - path = os.path.join(self.root, 'foo') - os.mkdir(path) - self.failUnless(self.filesystem.isdir('foo')) - os.rmdir(path) - - - def testIsFile(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('test') - self.failUnless(self.filesystem.isfile('foo')) - os.remove(path) - - - def testListDir(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('test') - self.assertEqual(self.filesystem.listdir('/', 0).more(), - 'foo\r\n') - os.remove(path) - - - def testLongify(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('test') - stat_info = os.stat(path) - result = self.filesystem.longify(('foo', stat_info)) - self.failUnless(result.endswith('foo')) - os.remove(path) - - - def testOpen(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - self.assertEqual(self.filesystem.open('foo', 'r').read(), 'writing test') - os.remove(path) - - - def testStat(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - self.assertEqual(self.filesystem.stat('foo'), os.stat(path)) - os.remove(path) - - - def testChmod(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - mode = 6*2**6 + 4*2**3 + 4*2**0 # 644 - self.filesystem.chmod('foo', mode) - self.assertEqual(('%o' %os.stat(path)[stat.ST_MODE])[-3:], '644') - os.remove(path) - - - def testChown(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - self.filesystem.chown('foo', 500, 500) - self.assertEqual(os.stat(path)[stat.ST_UID], 500) - self.assertEqual(os.stat(path)[stat.ST_GID], 500) - os.remove(path) - - - def testLink(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - self.filesystem.link('foo', 'foo1') - self.failUnless(os.path.exists(path+'1')) - os.remove(path) - os.remove(path+'1') - - - def testMkdir(self): - path = os.path.join(self.root, 'foo') - self.filesystem.mkdir('foo') - self.failUnless(os.path.exists(path)) - self.failUnless(os.path.isdir(path)) - os.rmdir(path) - - - def testFifo(self): - path = os.path.join(self.root, 'foo') - self.filesystem.mkfifo(path) - self.failUnless(os.path.exists(path)) - os.remove(path) - - - def testRemove(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - self.filesystem.remove('foo') - self.failIf(os.path.exists(path)) - - - def testRmdir(self): - path = os.path.join(self.root, 'foo') - os.mkdir(path) - self.filesystem.rmdir('foo') - self.failIf(os.path.exists(path)) - - - def testRename(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - self.filesystem.rename('foo', 'foo1') - self.failUnless(os.path.exists(path+'1')) - os.remove(path+'1') - - - def testSymlink(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - self.filesystem.symlink('foo', 'foo1') - self.failUnless(os.path.exists(path+'1')) - os.remove(path) - os.remove(path+'1') - - - def testUnlink(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - self.filesystem.unlink('foo') - self.failIf(os.path.exists(path)) - - - def testWrite(self): - path = os.path.join(self.root, 'foo') - file = open(path, 'w') - self.assertEqual(self.filesystem.write(file.fileno(), 'foo bar'), 7) - file.close() - os.remove(path) - - - def testInterface(self): - self.failUnless( - IReadFileSystem.isImplementedByInstancesOf(self.filesystem_class)) - self.failUnless(verifyClass(IReadFileSystem, self.filesystem_class)) - - self.failUnless( - IWriteFileSystem.isImplementedByInstancesOf(self.filesystem_class)) - self.failUnless(verifyClass(IWriteFileSystem, self.filesystem_class)) - - -def test_suite(): - loader = unittest.TestLoader() - return loader.loadTestsFromTestCase(OSFileSystemTest) - -if __name__=='__main__': - unittest.TextTestRunner().run( test_suite() ) +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + + +import unittest +import os +import stat +import tempfile + +from Interface.Verify import verifyClass +from Zope.Server.VFS.IReadFileSystem import IReadFileSystem +from Zope.Server.VFS.IWriteFileSystem import IWriteFileSystem + +from Zope.Server.VFS.OSFileSystem import OSFileSystem + +class OSFileSystemTest(unittest.TestCase): + """This test is constructed in a way that it builds up a directory + structure, whcih is removed at the end. + """ + + filesystem_class = OSFileSystem + root = None + + def setUp(self): + if self.root is None: + self.root = tempfile.mktemp() + self.filesystem = self.filesystem_class(self.root) + + os.mkdir(self.root) + + + def tearDown(self): + os.rmdir(self.root) + + + def testNormalize(self): + + self.assertEqual(self.filesystem.normalize('/foo/bar//'), '/foo/bar') + self.assertEqual(self.filesystem.normalize('/foo//bar'), '/foo/bar') + self.assertEqual(self.filesystem.normalize('///foo/bar'), '/foo/bar') + self.assertEqual(self.filesystem.normalize('///foo//bar////'), + '/foo/bar') + + self.assertEqual(self.filesystem.normalize('../foo/bar'), '/') + self.assertEqual(self.filesystem.normalize('..'), '/') + self.assertEqual(self.filesystem.normalize('/..'), '/') + self.assertEqual(self.filesystem.normalize('/foo/..'), '/') + self.assertEqual(self.filesystem.normalize('/foo/../bar'), '/bar') + self.assertEqual(self.filesystem.normalize('../../'), '/') + + self.assertEqual(self.filesystem.normalize('///../foo/bar'), '/foo/bar') + self.assertEqual(self.filesystem.normalize('/foo/..///'), '/') + self.assertEqual(self.filesystem.normalize('///foo/..//bar'), '/bar') + self.assertEqual(self.filesystem.normalize('..///../'), '/') + + + def testTranslate(self): + + self.assertEqual(self.filesystem.root, self.root) + + self.assertEqual(self.filesystem.translate('/foo/'), + self.filesystem.path_module.join(self.root, 'foo')) + self.assertEqual(self.filesystem.translate('/foo/bar'), + self.filesystem.path_module.join(self.root, + 'foo', 'bar')) + self.assertEqual(self.filesystem.translate('foo/bar'), + self.filesystem.path_module.join(self.root, + 'foo', 'bar')) + + def testExists(self): + path = os.path.join(self.root, 'foo') + open(path, 'w').write('test') + self.failUnless(self.filesystem.exists('foo')) + os.remove(path) + + + def testIsDir(self): + path = os.path.join(self.root, 'foo') + os.mkdir(path) + self.failUnless(self.filesystem.isdir('foo')) + os.rmdir(path) + + + def testIsFile(self): + path = os.path.join(self.root, 'foo') + open(path, 'w').write('test') + self.failUnless(self.filesystem.isfile('foo')) + os.remove(path) + + + def testListDir(self): + path = os.path.join(self.root, 'foo') + open(path, 'w').write('test') + self.assertEqual(self.filesystem.listdir('/', 0).more(), + 'foo\r\n') + os.remove(path) + + + def testLongify(self): + path = os.path.join(self.root, 'foo') + open(path, 'w').write('test') + stat_info = os.stat(path) + result = self.filesystem.longify(('foo', stat_info)) + self.failUnless(result.endswith('foo')) + os.remove(path) + + + def testOpen(self): + path = os.path.join(self.root, 'foo') + open(path, 'w').write('writing test') + self.assertEqual(self.filesystem.open('foo', 'r').read(), 'writing test') + os.remove(path) + + + def testStat(self): + path = os.path.join(self.root, 'foo') + open(path, 'w').write('writing test') + self.assertEqual(self.filesystem.stat('foo'), os.stat(path)) + os.remove(path) + + + def testChmod(self): + path = os.path.join(self.root, 'foo') + open(path, 'w').write('writing test') + mode = 6*2**6 + 4*2**3 + 4*2**0 # 644 + self.filesystem.chmod('foo', mode) + self.assertEqual(('%o' %os.stat(path)[stat.ST_MODE])[-3:], '644') + os.remove(path) + + + def testChown(self): + path = os.path.join(self.root, 'foo') + open(path, 'w').write('writing test') + self.filesystem.chown('foo', 500, 500) + self.assertEqual(os.stat(path)[stat.ST_UID], 500) + self.assertEqual(os.stat(path)[stat.ST_GID], 500) + os.remove(path) + + + def testLink(self): + path = os.path.join(self.root, 'foo') + open(path, 'w').write('writing test') + self.filesystem.link('foo', 'foo1') + self.failUnless(os.path.exists(path+'1')) + os.remove(path) + os.remove(path+'1') + + + def testMkdir(self): + path = os.path.join(self.root, 'foo') + self.filesystem.mkdir('foo') + self.failUnless(os.path.exists(path)) + self.failUnless(os.path.isdir(path)) + os.rmdir(path) + + + def testFifo(self): + path = os.path.join(self.root, 'foo') + self.filesystem.mkfifo(path) + self.failUnless(os.path.exists(path)) + os.remove(path) + + + def testRemove(self): + path = os.path.join(self.root, 'foo') + open(path, 'w').write('writing test') + self.filesystem.remove('foo') + self.failIf(os.path.exists(path)) + + + def testRmdir(self): + path = os.path.join(self.root, 'foo') + os.mkdir(path) + self.filesystem.rmdir('foo') + self.failIf(os.path.exists(path)) + + + def testRename(self): + path = os.path.join(self.root, 'foo') + open(path, 'w').write('writing test') + self.filesystem.rename('foo', 'foo1') + self.failUnless(os.path.exists(path+'1')) + os.remove(path+'1') + + + def testSymlink(self): + path = os.path.join(self.root, 'foo') + open(path, 'w').write('writing test') + self.filesystem.symlink('foo', 'foo1') + self.failUnless(os.path.exists(path+'1')) + os.remove(path) + os.remove(path+'1') + + + def testUnlink(self): + path = os.path.join(self.root, 'foo') + open(path, 'w').write('writing test') + self.filesystem.unlink('foo') + self.failIf(os.path.exists(path)) + + + def testWrite(self): + path = os.path.join(self.root, 'foo') + file = open(path, 'w') + self.assertEqual(self.filesystem.write(file.fileno(), 'foo bar'), 7) + file.close() + os.remove(path) + + + def testInterface(self): + self.failUnless( + IReadFileSystem.isImplementedByInstancesOf(self.filesystem_class)) + self.failUnless(verifyClass(IReadFileSystem, self.filesystem_class)) + + self.failUnless( + IWriteFileSystem.isImplementedByInstancesOf(self.filesystem_class)) + self.failUnless(verifyClass(IWriteFileSystem, self.filesystem_class)) + + +def test_suite(): + loader = unittest.TestLoader() + return loader.loadTestsFromTestCase(OSFileSystemTest) + +if __name__=='__main__': + unittest.TextTestRunner().run( test_suite() ) From shane@cvs.zope.org Thu Apr 4 18:45:58 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 13:45:58 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/tests - MaxSockets.py:1.1.2.2 __init__.py:1.1.2.2.2.1 Message-ID: <200204041845.g34Ijwh18116@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/tests In directory cvs.zope.org:/tmp/cvs-serv17993/tests Modified Files: Tag: Zope3-Server-Branch MaxSockets.py __init__.py Log Message: Just fixed line endings. No carriage returns. === Zope3/lib/python/Zope/Server/tests/MaxSockets.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## import socket @@ -36,7 +36,7 @@ s.close() del sl return num - + def max_client_sockets(): # make a server socket server = socket.socket (socket.AF_INET, socket.SOCK_STREAM) @@ -57,7 +57,7 @@ c.close() del sl return num - + def max_select_sockets(): sl = [] while 1: === Zope3/lib/python/Zope/Server/tests/__init__.py 1.1.2.2 => 1.1.2.2.2.1 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ Unit tests for Zope.Server """ From shane@cvs.zope.org Thu Apr 4 18:46:25 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 13:46:25 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/Authentication - DictionaryAuthentication.py:1.1.2.3 IAuthentication.py:1.1.2.4 IUser.py:1.1.2.2 SimpleUser.py:1.1.2.2 UnixAuthentication.py:1.1.2.2 __init__.py:1.1.2.2 Message-ID: <200204041846.g34IkPj18277@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/Authentication In directory cvs.zope.org:/tmp/cvs-serv17993/Authentication Modified Files: Tag: Zope3-Server-Branch DictionaryAuthentication.py IAuthentication.py IUser.py SimpleUser.py UnixAuthentication.py __init__.py Log Message: Just fixed line endings. No carriage returns. === Zope3/lib/python/Zope/Server/Authentication/DictionaryAuthentication.py 1.1.2.2 => 1.1.2.3 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -from IAuthentication import IAuthentication - - -class DictionaryAuthentication: - """ """ - - __implements__ = IAuthentication - - - def __init__(self, user_dict): - self.user_dict = user_dict - - ############################################################ - # Implementation methods for interface - # Zope.Server.Authentication.IAuthentication. - - def authenticate(self, username, password): - 'See Zope.Server.Authentication.IAuthentication.IAuthentication' - - if username not in self.user_dict.keys(): - return 0, 'No such user.' - elif password == self.user_dict[username]: - return 1, 'Login successful.' - else: - return 0, 'Password invalid.' - - # - ############################################################ - - - def __repr__ (self): - return '' +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +from IAuthentication import IAuthentication + + +class DictionaryAuthentication: + """ """ + + __implements__ = IAuthentication + + + def __init__(self, user_dict): + self.user_dict = user_dict + + ############################################################ + # Implementation methods for interface + # Zope.Server.Authentication.IAuthentication. + + def authenticate(self, username, password): + 'See Zope.Server.Authentication.IAuthentication.IAuthentication' + + if username not in self.user_dict.keys(): + return 0, 'No such user.' + elif password == self.user_dict[username]: + return 1, 'Login successful.' + else: + return 0, 'Password invalid.' + + # + ############################################################ + + + def __repr__ (self): + return '' === Zope3/lib/python/Zope/Server/Authentication/IAuthentication.py 1.1.2.3 => 1.1.2.4 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - - -from Interface import Interface -from Interface.Attribute import Attribute - -class IAuthentication(Interface): - """Authentica - """ - - def authenticate(username, password): - """ - """ - - return Boolean, str("Message") +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + + +from Interface import Interface +from Interface.Attribute import Attribute + +class IAuthentication(Interface): + """Authentica + """ + + def authenticate(username, password): + """ + """ + + return Boolean, str("Message") === Zope3/lib/python/Zope/Server/Authentication/IUser.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - - -from Interface import Interface -from Interface.Attribute import Attribute - -class IUser(Interface): - """In order to have a uniform return type in the authentication model, - a simple user is defined. - - Note: This user can become very complex, supporting groups, permissions, - a personal data storage and so on. - """ - - username = Attribute("The username of the user") +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + + +from Interface import Interface +from Interface.Attribute import Attribute + +class IUser(Interface): + """In order to have a uniform return type in the authentication model, + a simple user is defined. + + Note: This user can become very complex, supporting groups, permissions, + a personal data storage and so on. + """ + + username = Attribute("The username of the user") === Zope3/lib/python/Zope/Server/Authentication/SimpleUser.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -from IUser import IUser - - -class SimpleUser: - """A simple user implementation.""" - - __implements__ = IUser - - username = None - - def __init__(self, username): - - self.username = username - - - -AnonymousUser = SimpleUser('anonymous') +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +from IUser import IUser + + +class SimpleUser: + """A simple user implementation.""" + + __implements__ = IUser + + username = None + + def __init__(self, username): + + self.username = username + + + +AnonymousUser = SimpleUser('anonymous') === Zope3/lib/python/Zope/Server/Authentication/UnixAuthentication.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" -import crypt -import pwd - -from IAuthentication import IAuthentication - - -class UnixAuthentication: - """ """ - - __implements__ = IAuthentication - - - ############################################################ - # Implementation methods for interface - # Zope.Server.Authentication.IAuthentication. - - def authenticate(self, username, password): - 'See Zope.Server.Authentication.IAuthentication.IAuthentication' - try: - info = pwd.getpwnam(username) - except KeyError: - return 0, 'No such user.' - - mangled = info[1] - - print mangled - print password - print crypt.crypt(password, mangled[:2]) - - if crypt.crypt(password, mangled[:2]) == mangled: - return 1, 'Login successful.' - else: - return 0, 'Password invalid.' - - # - ############################################################ - - - def __repr__ (self): - return '' +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" +import crypt +import pwd + +from IAuthentication import IAuthentication + + +class UnixAuthentication: + """ """ + + __implements__ = IAuthentication + + + ############################################################ + # Implementation methods for interface + # Zope.Server.Authentication.IAuthentication. + + def authenticate(self, username, password): + 'See Zope.Server.Authentication.IAuthentication.IAuthentication' + try: + info = pwd.getpwnam(username) + except KeyError: + return 0, 'No such user.' + + mangled = info[1] + + print mangled + print password + print crypt.crypt(password, mangled[:2]) + + if crypt.crypt(password, mangled[:2]) == mangled: + return 1, 'Login successful.' + else: + return 0, 'Password invalid.' + + # + ############################################################ + + + def __repr__ (self): + return '' === Zope3/lib/python/Zope/Server/Authentication/__init__.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" From shane@cvs.zope.org Thu Apr 4 18:46:26 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 13:46:26 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/Authentication/tests - __init__.py:1.1.2.2 testDictionaryAuthentication.py:1.1.2.3 testSimpleUser.py:1.1.2.2 Message-ID: <200204041846.g34IkQa18287@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/Authentication/tests In directory cvs.zope.org:/tmp/cvs-serv17993/Authentication/tests Modified Files: Tag: Zope3-Server-Branch __init__.py testDictionaryAuthentication.py testSimpleUser.py Log Message: Just fixed line endings. No carriage returns. === Zope3/lib/python/Zope/Server/Authentication/tests/__init__.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" === Zope3/lib/python/Zope/Server/Authentication/tests/testDictionaryAuthentication.py 1.1.2.2 => 1.1.2.3 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - - -import unittest -from Interface.Verify import verifyClass -from Zope.Server.Authentication.IAuthentication import IAuthentication -from Zope.Server.Authentication.DictionaryAuthentication import \ - DictionaryAuthentication as DictAuth -from Zope.Server.Authentication.SimpleUser import SimpleUser, AnonymousUser - -class Test( unittest.TestCase ): - - def setUp(self): - self.auth = DictAuth({'foo': 'bar', - 'blah': 'plah', - 'stupid': 'nonesense'}) - - - def testAuthenticate(self): - self.failUnless(self.auth.authenticate('foo', 'bar')[0]) - self.failIf(self.auth.authenticate('blah', '')[0]) - self.failIf(self.auth.authenticate('foo', 'nonesense')[0]) - - - def testInterface(self): - self.failUnless(IAuthentication.isImplementedByInstancesOf(DictAuth)) - self.failUnless(verifyClass(IAuthentication, DictAuth)) - - - -def test_suite(): - loader = unittest.TestLoader() - return loader.loadTestsFromTestCase( Test ) - -if __name__=='__main__': - unittest.TextTestRunner().run( test_suite() ) +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + + +import unittest +from Interface.Verify import verifyClass +from Zope.Server.Authentication.IAuthentication import IAuthentication +from Zope.Server.Authentication.DictionaryAuthentication import \ + DictionaryAuthentication as DictAuth +from Zope.Server.Authentication.SimpleUser import SimpleUser, AnonymousUser + +class Test( unittest.TestCase ): + + def setUp(self): + self.auth = DictAuth({'foo': 'bar', + 'blah': 'plah', + 'stupid': 'nonesense'}) + + + def testAuthenticate(self): + self.failUnless(self.auth.authenticate('foo', 'bar')[0]) + self.failIf(self.auth.authenticate('blah', '')[0]) + self.failIf(self.auth.authenticate('foo', 'nonesense')[0]) + + + def testInterface(self): + self.failUnless(IAuthentication.isImplementedByInstancesOf(DictAuth)) + self.failUnless(verifyClass(IAuthentication, DictAuth)) + + + +def test_suite(): + loader = unittest.TestLoader() + return loader.loadTestsFromTestCase( Test ) + +if __name__=='__main__': + unittest.TextTestRunner().run( test_suite() ) === Zope3/lib/python/Zope/Server/Authentication/tests/testSimpleUser.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -import unittest -from Interface.Verify import verifyClass -from Zope.Server.Authentication.IUser import IUser -from Zope.Server.Authentication.SimpleUser import SimpleUser, AnonymousUser - -class Test( unittest.TestCase ): - - - def testAnonymousUser(self): - self.assertEqual(AnonymousUser.username, 'anonymous') - - - def testSimpleUser(self): - simple_user = SimpleUser('simple') - self.assertEqual(simple_user.username, 'simple') - - - def testInterface(self): - self.failUnless(IUser.isImplementedByInstancesOf(SimpleUser)) - self.failUnless(verifyClass(IUser, SimpleUser)) - - - -def test_suite(): - loader = unittest.TestLoader() - return loader.loadTestsFromTestCase( Test ) - -if __name__=='__main__': - unittest.TextTestRunner().run( test_suite() ) +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +import unittest +from Interface.Verify import verifyClass +from Zope.Server.Authentication.IUser import IUser +from Zope.Server.Authentication.SimpleUser import SimpleUser, AnonymousUser + +class Test( unittest.TestCase ): + + + def testAnonymousUser(self): + self.assertEqual(AnonymousUser.username, 'anonymous') + + + def testSimpleUser(self): + simple_user = SimpleUser('simple') + self.assertEqual(simple_user.username, 'simple') + + + def testInterface(self): + self.failUnless(IUser.isImplementedByInstancesOf(SimpleUser)) + self.failUnless(verifyClass(IUser, SimpleUser)) + + + +def test_suite(): + loader = unittest.TestLoader() + return loader.loadTestsFromTestCase( Test ) + +if __name__=='__main__': + unittest.TextTestRunner().run( test_suite() ) From shane@cvs.zope.org Thu Apr 4 18:46:27 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 13:46:27 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/HTTP/tests - __init__.py:1.1.2.2 testHTTPServer.py:1.1.2.3 testPublisherServer.py:1.1.2.2 Message-ID: <200204041846.g34IkRI18319@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/HTTP/tests In directory cvs.zope.org:/tmp/cvs-serv17993/HTTP/tests Modified Files: Tag: Zope3-Server-Branch __init__.py testHTTPServer.py testPublisherServer.py Log Message: Just fixed line endings. No carriage returns. === Zope3/lib/python/Zope/Server/HTTP/tests/__init__.py 1.1.2.1 => 1.1.2.2 === -# +# # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED === Zope3/lib/python/Zope/Server/HTTP/tests/testHTTPServer.py 1.1.2.2 => 1.1.2.3 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ @@ -195,7 +195,7 @@ "Content-Length: %d\n" "\n" "%s") % (len(data), data) - + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((LOCALHOST, self.port)) sock.send(s) @@ -264,7 +264,7 @@ control_line="20;\r\n" # 20 hex = 32 dec s = 'This string has 32 characters.\r\n' expect = s * 12 - + h = HTTPConnection(LOCALHOST, self.port) h.putrequest('GET', '/') h.putheader('Accept', 'text/plain') === Zope3/lib/python/Zope/Server/HTTP/tests/testPublisherServer.py 1.1.2.1 => 1.1.2.2 === # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. ############################################################################## """ @@ -101,7 +101,7 @@ td.setThreadCount(4) # Bind to any port on localhost. - self.server = PublisherHTTPServer(request_factory, 'Browser', + self.server = PublisherHTTPServer(request_factory, 'Browser', LOCALHOST, 0, task_dispatcher=td) self.port = self.server.socket.getsockname()[1] self.run_loop = 1 From shane@cvs.zope.org Thu Apr 4 18:46:27 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 13:46:27 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/HTTP - Chunking.py:1.1.2.2 CommonHitLogger.py:1.1.2.2 HTTPRequestParser.py:1.1.2.2 HTTPServer.py:1.1.2.2 HTTPServerChannel.py:1.1.2.2 HTTPTask.py:1.1.2.2 PublisherHTTPChannel.py:1.1.2.2 PublisherHTTPServer.py:1.1.2.2 PublisherHTTPTask.py:1.1.2.3 __init__.py:1.1.2.2 http_date.py:1.1.2.2 Message-ID: <200204041846.g34IkRp18331@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/HTTP In directory cvs.zope.org:/tmp/cvs-serv17993/HTTP Modified Files: Tag: Zope3-Server-Branch Chunking.py CommonHitLogger.py HTTPRequestParser.py HTTPServer.py HTTPServerChannel.py HTTPTask.py PublisherHTTPChannel.py PublisherHTTPServer.py PublisherHTTPTask.py __init__.py http_date.py Log Message: Just fixed line endings. No carriage returns. === Zope3/lib/python/Zope/Server/HTTP/Chunking.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ === Zope3/lib/python/Zope/Server/HTTP/CommonHitLogger.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ @@ -37,7 +37,7 @@ self.output = ResolvingLogger(resolver, logger_object) else: self.output = UnresolvingLogger(logger_object) - + def compute_timezone_for_log(self, tz): if tz > 0: neg = 1 @@ -98,4 +98,4 @@ user_agent ) ) - + === Zope3/lib/python/Zope/Server/HTTP/HTTPRequestParser.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ This server uses asyncore to accept connections and do initial @@ -158,7 +158,7 @@ r = [] lines = self.header.split('\n') for line in lines: - if line and line[0] in ' \t': + if line and line[0] in ' \t': r[-1] = r[-1] + line[1:] else: r.append(line) @@ -183,7 +183,7 @@ # path query fragment r'([^?#]*)(\?[^#]*)?(#.*)?' ) - + def split_uri(self): m = self.path_regex.match (self.uri) if m.end() != len(self.uri): === Zope3/lib/python/Zope/Server/HTTP/HTTPServer.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ This server uses asyncore to accept connections and do initial @@ -19,7 +19,7 @@ """ from Zope.Server.ServerBase import ServerBase -from HTTPServerChannel import HTTPServerChannel +from HTTPServerChannel import HTTPServerChannel class HTTPServer(ServerBase): === Zope3/lib/python/Zope/Server/HTTP/HTTPServerChannel.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ === Zope3/lib/python/Zope/Server/HTTP/HTTPTask.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ This server uses asyncore to accept connections and do initial === Zope3/lib/python/Zope/Server/HTTP/PublisherHTTPChannel.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ === Zope3/lib/python/Zope/Server/HTTP/PublisherHTTPServer.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ @@ -27,7 +27,7 @@ channel_class = PublisherHTTPChannel - + def __init__(self, request_factory, sub_protocol=None, *args, **kw): self.request_factory = request_factory @@ -38,4 +38,4 @@ self.SERVER_IDENT += ' (%s)' %sub_protocol HTTPServer.__init__(self, *args, **kw) - + === Zope3/lib/python/Zope/Server/HTTP/PublisherHTTPTask.py 1.1.2.2 => 1.1.2.3 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ @@ -75,7 +75,7 @@ env['REMOTE_HOST'] = remote_host env_has = env.has_key - + for key, value in request_data.headers.items(): value = value.strip() mykey = rename_headers.get(key, None) === Zope3/lib/python/Zope/Server/HTTP/__init__.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" === Zope3/lib/python/Zope/Server/HTTP/http_date.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ @@ -21,14 +21,14 @@ import time def concat (*args): - return ''.join (args) - + return ''.join (args) + def join (seq, field=' '): return field.join (seq) - + def group (s): return '(' + s + ')' - + short_days = ['sun','mon','tue','wed','thu','fri','sat'] long_days = ['sunday','monday','tuesday','wednesday', 'thursday','friday','saturday'] @@ -40,7 +40,7 @@ for i in range(7): daymap[short_days[i]] = i daymap[long_days[i]] = i - + hms_reg = join (3 * [group('[0-9][0-9]')], ':') months = ['jan','feb','mar','apr','may','jun','jul', @@ -49,7 +49,7 @@ monmap = {} for i in range(12): monmap[months[i]] = i+1 - + months_reg = group (join (months, '|')) # From draft-ietf-http-v11-spec-07.txt/3.3.1 @@ -59,11 +59,11 @@ # rfc822 format rfc822_date = join ( - [concat (short_day_reg,','), # day - group('[0-9][0-9]?'), # date - months_reg, # month - group('[0-9]+'), # year - hms_reg, # hour minute second + [concat (short_day_reg,','), # day + group('[0-9][0-9]?'), # date + months_reg, # month + group('[0-9]+'), # year + hms_reg, # hour minute second 'gmt' ], ' ' @@ -75,17 +75,17 @@ g = m.group a = string.atoi return ( - a(g(4)), # year - monmap[g(3)], # month - a(g(2)), # day - a(g(5)), # hour - a(g(6)), # minute - a(g(7)), # second + a(g(4)), # year + monmap[g(3)], # month + a(g(2)), # day + a(g(5)), # hour + a(g(6)), # minute + a(g(7)), # second 0, 0, 0 ) - + # rfc850 format rfc850_date = join ( [concat (long_day_reg,','), @@ -108,20 +108,20 @@ g = m.group a = string.atoi return ( - a(g(4)), # year - monmap[g(3)], # month - a(g(2)), # day - a(g(5)), # hour - a(g(6)), # minute - a(g(7)), # second + a(g(4)), # year + monmap[g(3)], # month + a(g(2)), # day + a(g(5)), # hour + a(g(6)), # minute + a(g(7)), # second 0, 0, 0 ) - - # parsdate.parsedate - ~700/sec. - # parse_http_date - ~1333/sec. - + + # parsdate.parsedate - ~700/sec. + # parse_http_date - ~1333/sec. + weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] monthname = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] From shane@cvs.zope.org Thu Apr 4 18:46:27 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 13:46:27 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/Thread - SelectTrigger.py:1.1.2.2 __init__.py:1.1.2.2 Message-ID: <200204041846.g34IkRc18337@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/Thread In directory cvs.zope.org:/tmp/cvs-serv17993/Thread Modified Files: Tag: Zope3-Server-Branch SelectTrigger.py __init__.py Log Message: Just fixed line endings. No carriage returns. === Zope3/lib/python/Zope/Server/Thread/SelectTrigger.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## # -*- Mode: Python; tab-width: 4 -*- @@ -26,9 +26,9 @@ if os.name == 'posix': class Trigger(asyncore.file_dispatcher): - + "Wake up a call to select() running in the main thread" - + # This is useful in a context where you are using Medusa's I/O # subsystem to deliver data, but the data is generated by another # thread. Normally, if Medusa is in the middle of a call to @@ -37,7 +37,7 @@ # If the trigger is 'pulled' by another thread, it should immediately # generate a READ event on the trigger object, which will force the # select() invocation to return. - + # A common use for this facility: letting Medusa manage I/O for a # large number of connections; but routing each request through a # thread chosen from a fixed-size thread pool. When a thread is @@ -46,7 +46,7 @@ # by Medusa. [picture a server that can process database queries # rapidly, but doesn't want to tie up threads waiting to send data # to low-bandwidth connections] - + # The other major feature provided by this class is the ability to # move work back into the main thread: if you call pull_trigger() # with a thunk argument, when select() wakes up and receives the @@ -56,26 +56,26 @@ # why this is true, imagine this scenario: A thread tries to push some # new data onto a channel's outgoing data queue at the same time that # the main thread is trying to remove some] - + def __init__ (self): r, w = os.pipe() self.trigger = w asyncore.file_dispatcher.__init__ (self, r) self.lock = thread.allocate_lock() self.thunks = [] - + def __repr__ (self): return '' % id(self) - + def readable (self): return 1 - + def writable (self): return 0 - + def handle_connect (self): pass - + def pull_trigger (self, thunk=None): # print 'PULL_TRIGGER: ', len(self.thunks) if thunk: @@ -85,7 +85,7 @@ finally: self.lock.release() os.write (self.trigger, 'x') - + def handle_read (self): self.recv (8192) try: @@ -101,23 +101,23 @@ self.thunks = [] finally: self.lock.release() - + else: # win32-safe version class Trigger (asyncore.dispatcher): - + address = ('127.9.9.9', 19999) - + def __init__ (self): a = socket.socket (socket.AF_INET, socket.SOCK_STREAM) w = socket.socket (socket.AF_INET, socket.SOCK_STREAM) - + # set TCP_NODELAY to true to avoid buffering w.setsockopt(socket.IPPROTO_TCP, 1, 1) - + # tricky: get a pair of connected sockets host='127.0.0.1' port=19999 @@ -130,7 +130,7 @@ if port <= 19950: raise 'Bind Error', 'Cannot bind trigger!' port=port - 1 - + a.listen (1) w.setblocking (0) try: @@ -141,24 +141,24 @@ a.close() w.setblocking (1) self.trigger = w - + asyncore.dispatcher.__init__ (self, r) self.lock = thread.allocate_lock() self.thunks = [] self._trigger_connected = 0 - + def __repr__ (self): return '' % id(self) - + def readable (self): return 1 - + def writable (self): return 0 - + def handle_connect (self): pass - + def pull_trigger (self, thunk=None): if thunk: try: @@ -167,7 +167,7 @@ finally: self.lock.release() self.trigger.send ('x') - + def handle_read (self): self.recv (8192) try: @@ -181,22 +181,22 @@ self.thunks = [] finally: self.lock.release() - - + + the_trigger = None class TriggerFile: "A 'triggered' file object" - + buffer_size = 4096 - + def __init__ (self, parent): global the_trigger if the_trigger is None: the_trigger = trigger() self.parent = parent self.buffer = '' - + def write (self, data): self.buffer = self.buffer + data if len(self.buffer) > self.buffer_size: @@ -204,10 +204,10 @@ the_trigger.pull_trigger ( lambda d=d,p=self.parent: p.push (d) ) - + def writeline (self, line): self.write (line+'\r\n') - + def writelines (self, lines): self.write ( string.joinfields ( @@ -215,33 +215,33 @@ '\r\n' ) + '\r\n' ) - + def flush (self): if self.buffer: d, self.buffer = self.buffer, '' the_trigger.pull_trigger ( lambda p=self.parent,d=d: p.push (d) ) - + def softspace (self, *args): pass - + def close (self): # in a derived class, you may want to call trigger_close() instead. self.flush() self.parent = None - + def trigger_close (self): d, self.buffer = self.buffer, '' p, self.parent = self.parent, None the_trigger.pull_trigger ( lambda p=p,d=d: (p.push(d), p.close_when_done()) ) - + if __name__ == '__main__': import time - + def thread_function (output_file, i, n): print 'entering thread_function' while n: @@ -251,19 +251,19 @@ n = n - 1 output_file.close() print 'exiting thread_function' - + class thread_parent (asynchat.async_chat): - + def __init__ (self, conn, addr): self.addr = addr asynchat.async_chat.__init__ (self, conn) self.set_terminator ('\r\n') self.buffer = '' self.count = 0 - + def collect_incoming_data (self, data): self.buffer = self.buffer + data - + def found_terminator (self): data, self.buffer = self.buffer, '' if not data: @@ -274,20 +274,20 @@ tf = TriggerFile (self) self.count = self.count + 1 thread.start_new_thread (thread_function, (tf, self.count, n)) - + class ThreadServer(asyncore.dispatcher): - + def __init__ (self, family=socket.AF_INET, address=('', 9003)): asyncore.dispatcher.__init__ (self) self.create_socket (family, socket.SOCK_STREAM) self.set_reuse_addr() self.bind (address) self.listen (5) - + def handle_accept (self): conn, addr = self.accept() tp = thread_parent (conn, addr) - + ThreadServer() #asyncore.loop(1.0, use_poll=1) try: === Zope3/lib/python/Zope/Server/Thread/__init__.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" From shane@cvs.zope.org Thu Apr 4 18:46:27 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 13:46:27 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server - Adjustments.py:1.1.2.4.2.3 Buffers.py:1.1.2.3.2.2 Counter.py:1.1.2.2 DualModeChannel.py:1.1.2.4.2.3 FixedStreamReceiver.py:1.1.2.2 IDispatcher.py:1.1.2.2 IDispatcherEventHandler.py:1.1.2.2 IDispatcherLogging.py:1.1.2.2 IHeaderOutput.py:1.1.2.3.2.2 IRequestFactory.py:1.1.4.2.2.2 IServer.py:1.1.2.2 IServerChannel.py:1.1.2.2 ISocket.py:1.1.2.2 IStreamConsumer.py:1.1.2.3.2.2 ITask.py:1.1.2.3.2.2 ITaskDispatcher.py:1.1.2.2.2.2 ServerBase.py:1.1.2.4.2.3 ServerChannelBase.py:1.1.2.3 TaskThreads.py:1.1.2.8.2.2 Utilities.py:1.1.2.3.2.2 ZLogIntegration.py:1.1.2.3.2.2 __init__.py:1.1.2.5.2.2 Message-ID: <200204041846.g34IkRx18334@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server In directory cvs.zope.org:/tmp/cvs-serv17993 Modified Files: Tag: Zope3-Server-Branch Adjustments.py Buffers.py Counter.py DualModeChannel.py FixedStreamReceiver.py IDispatcher.py IDispatcherEventHandler.py IDispatcherLogging.py IHeaderOutput.py IRequestFactory.py IServer.py IServerChannel.py ISocket.py IStreamConsumer.py ITask.py ITaskDispatcher.py ServerBase.py ServerChannelBase.py TaskThreads.py Utilities.py ZLogIntegration.py __init__.py Log Message: Just fixed line endings. No carriage returns. === Zope3/lib/python/Zope/Server/Adjustments.py 1.1.2.4.2.2 => 1.1.2.4.2.3 === -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED === Zope3/lib/python/Zope/Server/Buffers.py 1.1.2.3.2.1 => 1.1.2.3.2.2 === -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. === Zope3/lib/python/Zope/Server/Counter.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -class Counter(object): - "general-purpose counter" - - def __init__ (self, initial_value=0): - self.value = initial_value - - def increment (self, delta=1): - result = self.value - try: - self.value = self.value + delta - except OverflowError: - self.value = long(self.value) + delta - return result - - def decrement (self, delta=1): - result = self.value - try: - self.value = self.value - delta - except OverflowError: - self.value = long(self.value) - delta - return result - - def as_long (self): - return long(self.value) - - def __nonzero__ (self): - return self.value != 0 - - def __repr__ (self): - return '' % (self.value, id(self)) - - def __str__ (self): - return str(long(self.value))[:-1] +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +class Counter(object): + "general-purpose counter" + + def __init__ (self, initial_value=0): + self.value = initial_value + + def increment (self, delta=1): + result = self.value + try: + self.value = self.value + delta + except OverflowError: + self.value = long(self.value) + delta + return result + + def decrement (self, delta=1): + result = self.value + try: + self.value = self.value - delta + except OverflowError: + self.value = long(self.value) - delta + return result + + def as_long (self): + return long(self.value) + + def __nonzero__ (self): + return self.value != 0 + + def __repr__ (self): + return '' % (self.value, id(self)) + + def __str__ (self): + return str(long(self.value))[:-1] === Zope3/lib/python/Zope/Server/DualModeChannel.py 1.1.2.4.2.2 => 1.1.2.4.2.3 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ === Zope3/lib/python/Zope/Server/FixedStreamReceiver.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ === Zope3/lib/python/Zope/Server/IDispatcher.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -from ISocket import ISocket -from IDispatcherEventHandler import IDispatcherEventHandler -from IDispatcherLogging import IDispatcherLogging - - -class IDispatcher(ISocket, IDispatcherEventHandler, IDispatcherLogging): - """The dispatcher is the most low-level component of a server. - - 1. It manages the socket connections and distributes the - request to the appropriate channel. - - 2. It handles the events passed to it, such as reading input, - writing output and handling errors. More about this - functionality can be found in IDispatcherEventHandler. - - 3. It handles logging of the requests passed to the server as - well as other informational messages and erros. Please see - IDispatcherLogging for more details. - - Note: Most of this documentation is taken from the Python - Library Reference. - """ - - def add_channel(map=None): - """After the low-level socket connection negotiation is - completed, a channel is created that handles all requests - and responses until the end of the connection. - """ - - def del_channel(map=None): - """Delete a channel. This should include also closing the - socket to the client. - """ - - def create_socket(family, type): - """This is identical to the creation of a normal socket, and - will use the same options for creation. Refer to the socket - documentation for information on creating sockets. - """ - - def readable(): - """Each time through the select() loop, the set of sockets is - scanned, and this method is called to see if there is any - interest in reading. The default method simply returns 1, - indicating that by default, all channels will be - interested. - """ - - def writable(): - """Each time through the select() loop, the set of sockets is - scanned, and this method is called to see if there is any - interest in writing. The default method simply returns 1, - indicating that by default, all channels will be - interested. - """ +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +from ISocket import ISocket +from IDispatcherEventHandler import IDispatcherEventHandler +from IDispatcherLogging import IDispatcherLogging + + +class IDispatcher(ISocket, IDispatcherEventHandler, IDispatcherLogging): + """The dispatcher is the most low-level component of a server. + + 1. It manages the socket connections and distributes the + request to the appropriate channel. + + 2. It handles the events passed to it, such as reading input, + writing output and handling errors. More about this + functionality can be found in IDispatcherEventHandler. + + 3. It handles logging of the requests passed to the server as + well as other informational messages and erros. Please see + IDispatcherLogging for more details. + + Note: Most of this documentation is taken from the Python + Library Reference. + """ + + def add_channel(map=None): + """After the low-level socket connection negotiation is + completed, a channel is created that handles all requests + and responses until the end of the connection. + """ + + def del_channel(map=None): + """Delete a channel. This should include also closing the + socket to the client. + """ + + def create_socket(family, type): + """This is identical to the creation of a normal socket, and + will use the same options for creation. Refer to the socket + documentation for information on creating sockets. + """ + + def readable(): + """Each time through the select() loop, the set of sockets is + scanned, and this method is called to see if there is any + interest in reading. The default method simply returns 1, + indicating that by default, all channels will be + interested. + """ + + def writable(): + """Each time through the select() loop, the set of sockets is + scanned, and this method is called to see if there is any + interest in writing. The default method simply returns 1, + indicating that by default, all channels will be + interested. + """ === Zope3/lib/python/Zope/Server/IDispatcherEventHandler.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -from Interface import Interface - - -class IDispatcherEventHandler(Interface): - """The Dispatcher can receive several different types of events. This - interface describes the necessary methods that handle these common - event types. - """ - - def handle_read_event(): - """Given a read event, a server has to handle the event and - read the input from the client. - """ - - def handle_write_event(): - """Given a write event, a server has to handle the event and - write the output to the client. - """ - - def handle_expt_event(): - """An exception event was handed to the server. - """ - - def handle_error(): - """An error occured, but we are still trying to fix it. - """ - - def handle_expt(): - """Handle unhandled exceptions. This is usually a time to log. - """ - - def handle_read(): - """Read output from client. - """ - - def handle_write(): - """Write output via the socket to the client. - """ - - def handle_connect(): - """A client requests a connection, now we need to do soemthing. - """ - - def handle_accept(): - """A connection is accepted. - """ - - def handle_close(): - """A connection is being closed. - """ +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +from Interface import Interface + + +class IDispatcherEventHandler(Interface): + """The Dispatcher can receive several different types of events. This + interface describes the necessary methods that handle these common + event types. + """ + + def handle_read_event(): + """Given a read event, a server has to handle the event and + read the input from the client. + """ + + def handle_write_event(): + """Given a write event, a server has to handle the event and + write the output to the client. + """ + + def handle_expt_event(): + """An exception event was handed to the server. + """ + + def handle_error(): + """An error occured, but we are still trying to fix it. + """ + + def handle_expt(): + """Handle unhandled exceptions. This is usually a time to log. + """ + + def handle_read(): + """Read output from client. + """ + + def handle_write(): + """Write output via the socket to the client. + """ + + def handle_connect(): + """A client requests a connection, now we need to do soemthing. + """ + + def handle_accept(): + """A connection is accepted. + """ + + def handle_close(): + """A connection is being closed. + """ === Zope3/lib/python/Zope/Server/IDispatcherLogging.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -from Interface import Interface - - -class IDispatcherLogging(Interface): - """This interface provides methods through which the Dispatcher will - write its logs. A distinction is made between hit and message logging, - since they often go to different output types and can have very - different structure. - """ - - def log (message): - """Logs general requests made to the server. - """ - - def log_info(message, type='info'): - """Logs informational messages, warnings and errors. - """ +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +from Interface import Interface + + +class IDispatcherLogging(Interface): + """This interface provides methods through which the Dispatcher will + write its logs. A distinction is made between hit and message logging, + since they often go to different output types and can have very + different structure. + """ + + def log (message): + """Logs general requests made to the server. + """ + + def log_info(message, type='info'): + """Logs informational messages, warnings and errors. + """ === Zope3/lib/python/Zope/Server/IHeaderOutput.py 1.1.2.3.2.1 => 1.1.2.3.2.2 === -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED === Zope3/lib/python/Zope/Server/IRequestFactory.py 1.1.4.2.2.1 => 1.1.4.2.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE -# +# ############################################################################## """ @@ -30,4 +30,4 @@ """ - + === Zope3/lib/python/Zope/Server/IServer.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -from Interface import Interface -from Interface.Attribute import Attribute - - -class IServer(Interface): - """This interface describes the basic base server. - - The most unusual part about the Zope servers (since they all - implement this interface or inherit its base class) is that it - uses a mix of asynchronous and thread-based mechanism to - serve. While the low-level socket listener uses async, the - actual request is executed in a thread. This has the huge - advantage that if a request takes really long to process, the - server does not hang at that point to wait for the request to - finish. - """ - - channel_class = Attribute(""" - The channel class defines the type of channel - to be used by the server. See IServerChannel - for more information. - """) - - SERVER_IDENT = Attribute(""" - This string identifies the server. By default - this is 'Zope.Server.' and should be - overridden. - """) - +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +from Interface import Interface +from Interface.Attribute import Attribute + + +class IServer(Interface): + """This interface describes the basic base server. + + The most unusual part about the Zope servers (since they all + implement this interface or inherit its base class) is that it + uses a mix of asynchronous and thread-based mechanism to + serve. While the low-level socket listener uses async, the + actual request is executed in a thread. This has the huge + advantage that if a request takes really long to process, the + server does not hang at that point to wait for the request to + finish. + """ + + channel_class = Attribute(""" + The channel class defines the type of channel + to be used by the server. See IServerChannel + for more information. + """) + + SERVER_IDENT = Attribute(""" + This string identifies the server. By default + this is 'Zope.Server.' and should be + overridden. + """) + === Zope3/lib/python/Zope/Server/IServerChannel.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -from Interface import Interface -from Interface.Attribute import Attribute - -class IServerChannel(Interface): - """ - """ - - parser_class = Attribute("Subclasses must provide a parser class") - task_class = Attribute("Subclasses must provide a task class.") - - active_channels = Attribute("Class-specific channel tracker") - next_channel_cleanup = Attribute("Class-specific cleanup time") - - proto_request = Attribute("A request parser instance") - ready_requests = Attribute("A list of requests to be processed.") - last_activity = Attribute("Time of last activity") - running_tasks = Attribute("boolean") - - - def queue_request(self, req): - """Queues a request to be processed in sequence by a task. - """ - - def end_task(self, close): - """Called at the end of a task, may launch another task. - """ - - def create_task(self, req): - """Creates a new task and queues it for execution. - - The task may get executed in another thread. - """ - +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +from Interface import Interface +from Interface.Attribute import Attribute + +class IServerChannel(Interface): + """ + """ + + parser_class = Attribute("Subclasses must provide a parser class") + task_class = Attribute("Subclasses must provide a task class.") + + active_channels = Attribute("Class-specific channel tracker") + next_channel_cleanup = Attribute("Class-specific cleanup time") + + proto_request = Attribute("A request parser instance") + ready_requests = Attribute("A list of requests to be processed.") + last_activity = Attribute("Time of last activity") + running_tasks = Attribute("boolean") + + + def queue_request(self, req): + """Queues a request to be processed in sequence by a task. + """ + + def end_task(self, close): + """Called at the end of a task, may launch another task. + """ + + def create_task(self, req): + """Creates a new task and queues it for execution. + + The task may get executed in another thread. + """ + === Zope3/lib/python/Zope/Server/ISocket.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -from Interface import Interface - - -class ISocket(Interface): - """Represents a socket. - - Note: Most of this documentation is taken from the Python Library - Reference. - """ - - def listen(num): - """Listen for connections made to the socket. The backlog argument - specifies the maximum number of queued connections and should - be at least 1; the maximum value is system-dependent (usually - 5). - """ - - def bind(addr): - """Bind the socket to address. The socket must not already be bound. - """ - - def connect(address): - """Connect to a remote socket at address. - """ - - def accept(): - """Accept a connection. The socket must be bound to an address and - listening for connections. The return value is a pair (conn, - address) where conn is a new socket object usable to send and - receive data on the connection, and address is the address - bound to the socket on the other end of the connection. - """ - - def recv(buffer_size): - """Receive data from the socket. The return value is a string - representing the data received. The maximum amount of data - to be received at once is specified by bufsize. See the - Unix manual page recv(2) for the meaning of the optional - argument flags; it defaults to zero. - """ - - def send(data): - """Send data to the socket. The socket must be connected to a - remote socket. The optional flags argument has the same - meaning as for recv() above. Returns the number of bytes - sent. Applications are responsible for checking that all - data has been sent; if only some of the data was - transmitted, the application needs to attempt delivery of - the remaining data. - """ - - def close(): - """Close the socket. All future operations on the socket - object will fail. The remote end will receive no more data - (after queued data is flushed). Sockets are automatically - closed when they are garbage-collected. - """ +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +from Interface import Interface + + +class ISocket(Interface): + """Represents a socket. + + Note: Most of this documentation is taken from the Python Library + Reference. + """ + + def listen(num): + """Listen for connections made to the socket. The backlog argument + specifies the maximum number of queued connections and should + be at least 1; the maximum value is system-dependent (usually + 5). + """ + + def bind(addr): + """Bind the socket to address. The socket must not already be bound. + """ + + def connect(address): + """Connect to a remote socket at address. + """ + + def accept(): + """Accept a connection. The socket must be bound to an address and + listening for connections. The return value is a pair (conn, + address) where conn is a new socket object usable to send and + receive data on the connection, and address is the address + bound to the socket on the other end of the connection. + """ + + def recv(buffer_size): + """Receive data from the socket. The return value is a string + representing the data received. The maximum amount of data + to be received at once is specified by bufsize. See the + Unix manual page recv(2) for the meaning of the optional + argument flags; it defaults to zero. + """ + + def send(data): + """Send data to the socket. The socket must be connected to a + remote socket. The optional flags argument has the same + meaning as for recv() above. Returns the number of bytes + sent. Applications are responsible for checking that all + data has been sent; if only some of the data was + transmitted, the application needs to attempt delivery of + the remaining data. + """ + + def close(): + """Close the socket. All future operations on the socket + object will fail. The remote end will receive no more data + (after queued data is flushed). Sockets are automatically + closed when they are garbage-collected. + """ === Zope3/lib/python/Zope/Server/IStreamConsumer.py 1.1.2.3.2.1 => 1.1.2.3.2.2 === -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. @@ -15,7 +15,7 @@ """Consumes a data stream until reaching a completion point. The actual amount to be consumed might not be known ahead of time. - """ + """ def received(data): """Accepts data, returning the number of bytes consumed.""" === Zope3/lib/python/Zope/Server/ITask.py 1.1.2.3.2.1 => 1.1.2.3.2.2 === -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED === Zope3/lib/python/Zope/Server/ITaskDispatcher.py 1.1.2.2.2.1 => 1.1.2.2.2.2 === -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. === Zope3/lib/python/Zope/Server/ServerBase.py 1.1.2.4.2.2 => 1.1.2.4.2.3 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ === Zope3/lib/python/Zope/Server/ServerChannelBase.py 1.1.2.2 => 1.1.2.3 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ @@ -213,4 +213,4 @@ self.set_sync() task = self.task_class(self, req) self.server.addTask(task) - + === Zope3/lib/python/Zope/Server/TaskThreads.py 1.1.2.8.2.1 => 1.1.2.8.2.2 === -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED === Zope3/lib/python/Zope/Server/Utilities.py 1.1.2.3.2.1 => 1.1.2.3.2.2 === -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. === Zope3/lib/python/Zope/Server/ZLogIntegration.py 1.1.2.3.2.1 => 1.1.2.3.2.2 === -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED === Zope3/lib/python/Zope/Server/__init__.py 1.1.2.5.2.1 => 1.1.2.5.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ Zope.Server package. From shane@cvs.zope.org Thu Apr 4 18:46:29 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 13:46:29 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - IReadFileSystem.py:1.1.2.2 IWriteFileSystem.py:1.1.2.3 ListProducer.py:1.1.2.2 MSDOSFileSystem.py:1.1.2.2 MergedFileSystem.py:1.1.2.2 OSFileSystem.py:1.1.2.10 PublisherFileSystem.py:1.1.2.2 PublisherVFSTask.py:1.1.2.2 UnixFileSystem.py:1.1.2.4 __init__.py:1.1.2.2 Message-ID: <200204041846.g34IkT418377@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv17993/VFS Modified Files: Tag: Zope3-Server-Branch IReadFileSystem.py IWriteFileSystem.py ListProducer.py MSDOSFileSystem.py MergedFileSystem.py OSFileSystem.py PublisherFileSystem.py PublisherVFSTask.py UnixFileSystem.py __init__.py Log Message: Just fixed line endings. No carriage returns. === Zope3/lib/python/Zope/Server/VFS/IReadFileSystem.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ @@ -35,18 +35,18 @@ def isdir(path): """Test whether a path is a directory. """ - + def isfile(path): """Test whether a path is a file. """ - + def listdir(path, long=0): """Return a listing of the directory at 'path' The empty string indicates the current directory. If 'long' is set, instead return a list of (name, stat_info) tuples """ return list(tuple(str, str)) - + def longify(path): """Return a 'long' representation of the filename [for the output of the LIST command] @@ -56,7 +56,7 @@ """Return an open file object. """ return file - + def stat(path): """Return the equivalent of os.stat() on the given path: === Zope3/lib/python/Zope/Server/VFS/IWriteFileSystem.py 1.1.2.2 => 1.1.2.3 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ === Zope3/lib/python/Zope/Server/VFS/ListProducer.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ $Id$ """ - + class ListProducer: """Produces a string, representing a list of files. Note that not all files will be displayed at once. """ - + def __init__ (self, file_list, long, longify, batch_size=50): self.file_list = file_list self.long = long self.longify = longify - self.batch_size = int(batch_size) + self.batch_size = int(batch_size) self.done = 0 - + def ready(self): if len(self.file_list): return 1 @@ -37,7 +37,7 @@ self.done = 1 return 0 - + def more (self): # Check whether we have elements in the first place if not self.file_list: @@ -58,4 +58,4 @@ # Remove the displayed files from the list. self.file_list = self.file_list[self.batch_size:] return '\r\n'.join(batch) + '\r\n' - + === Zope3/lib/python/Zope/Server/VFS/MSDOSFileSystem.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ $Id$ """ - -from OSFileSystem import OSFileSystem - + +from OSFileSystem import OSFileSystem + class MSDOSFileSystem(OSFileSystem): """This is a generic MS-DOS-like FileSystem. It mimics MS-DOS' output. """ @@ -28,7 +28,7 @@ def longify(self, (path, stat_info)): return msdos_longify(path, stat_info) - + def msdos_longify(file, stat_info): """This matches the output of NT's ftp server (when in MSDOS mode) @@ -41,7 +41,7 @@ date = msdos_date (stat_info[stat.ST_MTIME]) return '%s %s %8d %s' % (date, dir, stat_info[stat.ST_SIZE], file) - + def msdos_date(t): try: info = time.gmtime(t) @@ -54,6 +54,6 @@ info[3] = info[3] - 12 else: merid = 'AM' - + return '%02d-%02d-%02d %02d:%02d%s' % ( info[1], info[2], info[0]%100, info[3], info[4], merid ) === Zope3/lib/python/Zope/Server/VFS/MergedFileSystem.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ $Id$ -""" - +""" + class MergedFileSystem: """A merged filesystem will let you plug other filesystems together. We really need the equivalent of a 'mount' capability - this seems to be the most general idea. So you'd use a 'mount' method to place another filesystem somewhere in the hierarchy. - + Note: this is most likely how I will handle ~user directories with the http server. """ def __init__ (self, *fsys): pass - + === Zope3/lib/python/Zope/Server/VFS/OSFileSystem.py 1.1.2.9 => 1.1.2.10 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ $Id$ """ - + import os import re import stat import time - + from ListProducer import ListProducer from IReadFileSystem import IReadFileSystem @@ -28,7 +28,7 @@ class OSFileSystem: - """Generic OS FileSystem implementation. + """Generic OS FileSystem implementation. The root of this file system is a string describing the path to the directory used as root. @@ -37,7 +37,7 @@ __implements__ = IReadFileSystem, IWriteFileSystem path_module = os.path - + def __init__ (self, root): self.root = root @@ -51,7 +51,7 @@ 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' p = self.translate(path) return self.path_module.exists(p) - + def isdir(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' @@ -174,7 +174,7 @@ def write(self, fd, data): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' return os.write(fd, data) - + # ############################################################ @@ -185,13 +185,13 @@ # watch for the ever-sneaky '/+' path element path = re.sub('/+', '/', path) # Someone is trying to get lower than the permitted root. - # We just ignore it. + # We just ignore it. path = self.path_module.normpath(path) if path.startswith('..') or path.startswith('../'): path = '/' return path - + def translate (self, path): """We need to join together three separate path components, and do it safely. / @@ -202,7 +202,7 @@ """ # Normalize the directory path = os.sep.join(path.split('/')) - path = self.normalize(self.path_module.join(path)) + path = self.normalize(self.path_module.join(path)) # Prepare for joining with root if path[0] == '/': path = path[1:] @@ -210,11 +210,11 @@ path = self.path_module.join(self.root, path) return path - + def __repr__ (self): return '' % self.root - - + + months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] @@ -240,7 +240,7 @@ try: grpname = grp.getgrgid(int(stat_info[stat.ST_GID]))[0] except: grpname = stat_info[stat.ST_GID] - + mode = ('%o' % stat_info[stat.ST_MODE])[-3:] mode = ''.join(map (lambda x: mode_table[x], mode)) @@ -259,8 +259,8 @@ date, file ) - - + + def ls_date (now, t): """Emulate the unix 'ls' command's date field. it has two formats - if the date is more than 180 days in the past, then it's like === Zope3/lib/python/Zope/Server/VFS/PublisherFileSystem.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ $Id$ """ - + import os, re import stat import time - + from IReadFileSystem import IReadFileSystem from IWriteFileSystem import IWriteFileSystem @@ -28,7 +28,7 @@ class PublisherFileSystem: - """Generic Publisher FileSystem implementation. + """Generic Publisher FileSystem implementation. """ __implements__ = IReadFileSystem, IWriteFileSystem @@ -44,7 +44,7 @@ if env is None: env = {} - + env['command'] = command env['path'] = path @@ -61,7 +61,7 @@ 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) return self._execute(path, 'exists') - + def isdir(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' @@ -165,12 +165,12 @@ def unlink(self, path): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' pass - + def write(self, fd, data): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' pass - + # ############################################################ @@ -181,13 +181,13 @@ # watch for the ever-sneaky '/+' path element path = re.sub('/+', '/', path) # Someone is trying to get lower than the permitted root. - # We just ignore it. + # We just ignore it. path = os.path.normpath(path) if path.startswith('..'): path = '/' return path - + def translate (self, path): """We need to join together three separate path components, and do it safely. / @@ -198,7 +198,7 @@ """ # Normalize the directory path = os.sep.join(path.split('/')) - path = self.normalize(self.path_module.join(path)) + path = self.normalize(self.path_module.join(path)) # Prepare for joining with root if path[0] == '/': path = path[1:] @@ -206,13 +206,13 @@ path = self.path_module.join(self.root, path) return path - + def __repr__ (self): return '' % self.root - - + + months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] @@ -238,7 +238,7 @@ try: grpname = grp.getgrgid(int(stat_info[stat.ST_GID]))[0] except: grpname = stat_info[stat.ST_GID] - + mode = ('%o' % stat_info[stat.ST_MODE])[-3:] mode = ''.join(map (lambda x: mode_table[x], mode)) @@ -257,8 +257,8 @@ date, file ) - - + + def ls_date (now, t): """Emulate the unix 'ls' command's date field. it has two formats - if the date is more than 180 days in the past, then it's like === Zope3/lib/python/Zope/Server/VFS/PublisherVFSTask.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -import socket -from Zope.Server.ITask import ITask - - -class FTPTask: - """ - """ - - __implements__ = ITask - - - def __init__(self, channel, command, m_name): - self.channel = channel - self.m_name = m_name - self.args = command.args - - - ############################################################ - # Implementation methods for interface - # Zope.Server.ITask - - def service(self): - """Called to execute the task. - """ - try: - try: - self.start() - getattr(self, self.m_name)(self.args) - self.finish() - except socket.error: - self.close_on_finish = 1 - if self.channel.adj.log_socket_errors: - raise - finally: - self.channel.end_task(self.close_on_finish) - - - def cancel(self): - 'See Zope.Server.ITask.ITask' - self.channel.close_when_done() - - - def defer(self): - 'See Zope.Server.ITask.ITask' - pass - - # - ############################################################ - - def start(self): - now = time.time() - self.start_time = now - - - def finish(self): - hit_log = self.channel.server.hit_log - if hit_log is not None: - hit_log.log(self) +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +import socket +from Zope.Server.ITask import ITask + + +class FTPTask: + """ + """ + + __implements__ = ITask + + + def __init__(self, channel, command, m_name): + self.channel = channel + self.m_name = m_name + self.args = command.args + + + ############################################################ + # Implementation methods for interface + # Zope.Server.ITask + + def service(self): + """Called to execute the task. + """ + try: + try: + self.start() + getattr(self, self.m_name)(self.args) + self.finish() + except socket.error: + self.close_on_finish = 1 + if self.channel.adj.log_socket_errors: + raise + finally: + self.channel.end_task(self.close_on_finish) + + + def cancel(self): + 'See Zope.Server.ITask.ITask' + self.channel.close_when_done() + + + def defer(self): + 'See Zope.Server.ITask.ITask' + pass + + # + ############################################################ + + def start(self): + now = time.time() + self.start_time = now + + + def finish(self): + hit_log = self.channel.server.hit_log + if hit_log is not None: + hit_log.log(self) === Zope3/lib/python/Zope/Server/VFS/UnixFileSystem.py 1.1.2.3 => 1.1.2.4 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ $Id$ """ - + import os from OSFileSystem import OSFileSystem @@ -26,7 +26,7 @@ __implements__ = OSFileSystem.__implements__ - + class SchizophrenicUnixFileSystem(OSFileSystem): """This File System always wants to be called with a specific user in mind. """ @@ -35,17 +35,17 @@ # Get process information - PROCESS_UID = os.getuid() - PROCESS_EUID = os.geteuid() - PROCESS_GID = os.getgid() - PROCESS_EGID = os.getegid() + PROCESS_UID = os.getuid() + PROCESS_EUID = os.geteuid() + PROCESS_GID = os.getgid() + PROCESS_EGID = os.getegid() + - def __init__ (self, root, persona=(None, None)): super(SchizophrenicUnixFileSystem, self).__init__(root, wd) self.persona = persona - + def become_persona (self): if self.persona is not (None, None): uid, gid = self.persona @@ -53,17 +53,17 @@ os.setegid(gid) os.seteuid(uid) - + def become_nobody (self): if self.persona is not (None, None): os.seteuid(self.PROCESS_UID) os.setegid(self.PROCESS_GID) - + ############################################################ # Implementation methods for interface # Zope.Server.VFS.IReadFileSystem.IReadFileSystem - + def open (self, filename, mode): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' try: @@ -73,7 +73,7 @@ finally: self.become_nobody() - + def listdir (self, path, long=0): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' try: === Zope3/lib/python/Zope/Server/VFS/__init__.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ From shane@cvs.zope.org Thu Apr 4 18:46:28 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 13:46:28 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/Logger - FileLogger.py:1.1.2.2 ILogger.py:1.1.2.2 MultiLogger.py:1.1.2.2 ResolvingLogger.py:1.1.2.2 RotatingFileLogger.py:1.1.2.2 SocketLogger.py:1.1.2.2 SyslogLogger.py:1.1.2.2 TailLogger.py:1.1.2.2 UnresolvingLogger.py:1.1.2.2 __init__.py:1.1.2.2 m_syslog.py:1.1.2.2 Message-ID: <200204041846.g34IkSf18369@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/Logger In directory cvs.zope.org:/tmp/cvs-serv17993/Logger Modified Files: Tag: Zope3-Server-Branch FileLogger.py ILogger.py MultiLogger.py ResolvingLogger.py RotatingFileLogger.py SocketLogger.py SyslogLogger.py TailLogger.py UnresolvingLogger.py __init__.py m_syslog.py Log Message: Just fixed line endings. No carriage returns. === Zope3/lib/python/Zope/Server/Logger/FileLogger.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ @@ -25,10 +25,10 @@ """ __implements__ = ILogger - + def __init__ (self, file, flush=1, mode='a'): - """pass this either a path or a file object.""" + """pass this either a path or a file object.""" if type(file) is StringType: if (file == '-'): import sys @@ -38,36 +38,36 @@ else: self.file = file self.do_flush = flush - + def __repr__ (self): return '' % self.file - + def write (self, data): self.file.write (data) self.maybe_flush() - + def writeline (self, line): self.file.writeline (line) self.maybe_flush() - + def writelines (self, lines): self.file.writelines (lines) self.maybe_flush() - + def maybe_flush (self): if self.do_flush: self.file.flush() - + def flush (self): self.file.flush() - + def softspace (self, *args): pass === Zope3/lib/python/Zope/Server/Logger/ILogger.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -from Interface import Interface - - -class ILogger(Interface): - """This interface describes the methods any Logging object has to - implement. - """ - - def log(message): - """Logs the passed message at the appropriate place.""" +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +from Interface import Interface + + +class ILogger(Interface): + """This interface describes the methods any Logging object has to + implement. + """ + + def log(message): + """Logs the passed message at the appropriate place.""" === Zope3/lib/python/Zope/Server/Logger/MultiLogger.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ @@ -27,40 +27,40 @@ class MultiLogger: """Log to multiple places.""" - + def __init__ (self, loggers): self.loggers = loggers - + def __repr__ (self): return '' % (repr(self.loggers)) - + def log (self, message): for logger in self.loggers: logger.log (message) - + class ResolvingLogger: """Feed (ip, message) combinations into this logger to get a resolved hostname in front of the message. The message will not be logged until the PTR request finishes (or fails).""" - + def __init__ (self, resolver, logger): self.resolver = resolver self.logger = logger - + class logger_thunk: def __init__ (self, message, logger): self.message = message self.logger = logger - + def __call__ (self, host, ttl, answer): if not answer: answer = host self.logger.log ('%s%s' % (answer, self.message)) - + def log (self, ip, message): self.resolver.resolve_ptr ( ip, @@ -71,29 +71,29 @@ ) - + class UnresolvingLogger: """Just in case you don't want to resolve""" def __init__ (self, logger): self.logger = logger - + def log (self, ip, message): self.logger.log ('%s%s' % (ip, message)) - - + + def strip_eol (line): while line and line[-1] in '\r\n': line = line[:-1] return line - + class TailLogger: """Keep track of the last log messages""" def __init__ (self, logger, size=500): self.size = size self.logger = logger self.messages = [] - + def log (self, message): self.messages.append (strip_eol (message)) if len (self.messages) > self.size: === Zope3/lib/python/Zope/Server/Logger/ResolvingLogger.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ @@ -17,7 +17,7 @@ """ from ILogger import ILogger - + class ResolvingLogger: """Feed (ip, message) combinations into this logger to get a resolved hostname in front of the message. The message will not @@ -29,12 +29,12 @@ self.resolver = resolver self.logger = logger - + class logger_thunk: def __init__ (self, message, logger): self.message = message self.logger = logger - + def __call__ (self, host, ttl, answer): if not answer: answer = host === Zope3/lib/python/Zope/Server/Logger/RotatingFileLogger.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ @@ -17,11 +17,11 @@ """ import time -import os +import os import stat from FileLogger import FileLogger - + class RotatingFileLogger(FileLogger): """ If freq is non-None we back up 'daily', 'weekly', or 'monthly'. Else if maxsize is non-None we back up whenever @@ -35,7 +35,7 @@ """ __implements__ = FileLogger.__implements__ - + def __init__ (self, file, freq=None, maxsize=None, flush=1, mode='a'): self.filename = file @@ -46,11 +46,11 @@ self.rotate_when = self.next_backup(self.freq) self.do_flush = flush - + def __repr__ (self): return '' % self.file - + # We back up at midnight every 1) day, 2) monday, or 3) 1st of month def next_backup (self, freq): (yr, mo, day, hr, min, sec, wd, jday, dst) = \ @@ -59,19 +59,19 @@ return time.mktime((yr,mo,day+1, 0,0,0, 0,0,-1)) elif freq == 'weekly': # wd(monday)==0 - return time.mktime((yr,mo,day-wd+7, 0,0,0, 0,0,-1)) + return time.mktime((yr,mo,day-wd+7, 0,0,0, 0,0,-1)) elif freq == 'monthly': return time.mktime((yr,mo+1,1, 0,0,0, 0,0,-1)) else: return None # not a date-based backup - + def maybe_flush (self): # rotate first if necessary self.maybe_rotate() if self.do_flush: # from file_logger() self.file.flush() - + def maybe_rotate (self): if self.freq and time.time() > self.rotate_when: self.rotate() @@ -83,7 +83,7 @@ except os.error: # file not found, probably self.rotate() # will create a new file - + def rotate (self): (yr, mo, day, hr, min, sec, wd, jday, dst) = \ time.localtime(time.time()) === Zope3/lib/python/Zope/Server/Logger/SocketLogger.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ @@ -23,21 +23,21 @@ class SocketLogger (asynchat.async_chat): - """Log to a stream socket, asynchronously.""" + """Log to a stream socket, asynchronously.""" __implements__ = ILogger def __init__ (self, address): - + if type(address) == type(''): self.create_socket (socket.AF_UNIX, socket.SOCK_STREAM) else: self.create_socket (socket.AF_INET, socket.SOCK_STREAM) - + self.connect (address) self.address = address - + def __repr__ (self): return '' % (self.address) === Zope3/lib/python/Zope/Server/Logger/SyslogLogger.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ @@ -35,7 +35,7 @@ """ __implements__ = ILogger - + svc_name = 'zope' pid_str = str(os.getpid()) @@ -44,11 +44,11 @@ self.facility = m_syslog.facility_names[facility] self.address=address - + def __repr__ (self): return '' % (repr(self.address)) - + ############################################################ # Implementation methods for interface # Zope.Server.Logger.ILogger === Zope3/lib/python/Zope/Server/Logger/TailLogger.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ @@ -18,7 +18,7 @@ from ILogger import ILogger - + class TailLogger: """Keep track of the last log messages""" === Zope3/lib/python/Zope/Server/Logger/UnresolvingLogger.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ @@ -17,7 +17,7 @@ """ from ILogger import ILogger - + class UnresolvingLogger: """Just in case you don't want to resolve""" @@ -26,7 +26,7 @@ def __init__ (self, logger): self.logger = logger - + ############################################################ # Implementation methods for interface # Zope.Server.Logger.ILogger === Zope3/lib/python/Zope/Server/Logger/__init__.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" === Zope3/lib/python/Zope/Server/Logger/m_syslog.py 1.1.2.1 => 1.1.2.2 === # ====================================================================== # Copyright 1997 by Sam Rushing -# +# # All Rights Reserved -# +# # Permission to use, copy, modify, and distribute this software and # its documentation for any purpose and without fee is hereby # granted, provided that the above copyright notice appear in all @@ -13,7 +13,7 @@ # Rushing not be used in advertising or publicity pertaining to # distribution of the software without specific, written prior # permission. -# +# # SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN # NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR @@ -65,73 +65,73 @@ # # priorities (these are ordered) -LOG_EMERG = 0 # system is unusable -LOG_ALERT = 1 # action must be taken immediately -LOG_CRIT = 2 # critical conditions -LOG_ERR = 3 # error conditions -LOG_WARNING = 4 # warning conditions -LOG_NOTICE = 5 # normal but significant condition -LOG_INFO = 6 # informational -LOG_DEBUG = 7 # debug-level messages - -# facility codes -LOG_KERN = 0 # kernel messages -LOG_USER = 1 # random user-level messages -LOG_MAIL = 2 # mail system -LOG_DAEMON = 3 # system daemons -LOG_AUTH = 4 # security/authorization messages -LOG_SYSLOG = 5 # messages generated internally by syslogd -LOG_LPR = 6 # line printer subsystem -LOG_NEWS = 7 # network news subsystem -LOG_UUCP = 8 # UUCP subsystem -LOG_CRON = 9 # clock daemon -LOG_AUTHPRIV = 10 # security/authorization messages (private) - -# other codes through 15 reserved for system use -LOG_LOCAL0 = 16 # reserved for local use -LOG_LOCAL1 = 17 # reserved for local use -LOG_LOCAL2 = 18 # reserved for local use -LOG_LOCAL3 = 19 # reserved for local use -LOG_LOCAL4 = 20 # reserved for local use -LOG_LOCAL5 = 21 # reserved for local use -LOG_LOCAL6 = 22 # reserved for local use -LOG_LOCAL7 = 23 # reserved for local use +LOG_EMERG = 0 # system is unusable +LOG_ALERT = 1 # action must be taken immediately +LOG_CRIT = 2 # critical conditions +LOG_ERR = 3 # error conditions +LOG_WARNING = 4 # warning conditions +LOG_NOTICE = 5 # normal but significant condition +LOG_INFO = 6 # informational +LOG_DEBUG = 7 # debug-level messages + +# facility codes +LOG_KERN = 0 # kernel messages +LOG_USER = 1 # random user-level messages +LOG_MAIL = 2 # mail system +LOG_DAEMON = 3 # system daemons +LOG_AUTH = 4 # security/authorization messages +LOG_SYSLOG = 5 # messages generated internally by syslogd +LOG_LPR = 6 # line printer subsystem +LOG_NEWS = 7 # network news subsystem +LOG_UUCP = 8 # UUCP subsystem +LOG_CRON = 9 # clock daemon +LOG_AUTHPRIV = 10 # security/authorization messages (private) + +# other codes through 15 reserved for system use +LOG_LOCAL0 = 16 # reserved for local use +LOG_LOCAL1 = 17 # reserved for local use +LOG_LOCAL2 = 18 # reserved for local use +LOG_LOCAL3 = 19 # reserved for local use +LOG_LOCAL4 = 20 # reserved for local use +LOG_LOCAL5 = 21 # reserved for local use +LOG_LOCAL6 = 22 # reserved for local use +LOG_LOCAL7 = 23 # reserved for local use priority_names = { - "alert": LOG_ALERT, - "crit": LOG_CRIT, - "debug": LOG_DEBUG, - "emerg": LOG_EMERG, - "err": LOG_ERR, - "error": LOG_ERR, # DEPRECATED - "info": LOG_INFO, - "notice": LOG_NOTICE, - "panic": LOG_EMERG, # DEPRECATED - "warn": LOG_WARNING, # DEPRECATED - "warning": LOG_WARNING, + "alert": LOG_ALERT, + "crit": LOG_CRIT, + "debug": LOG_DEBUG, + "emerg": LOG_EMERG, + "err": LOG_ERR, + "error": LOG_ERR, # DEPRECATED + "info": LOG_INFO, + "notice": LOG_NOTICE, + "panic": LOG_EMERG, # DEPRECATED + "warn": LOG_WARNING, # DEPRECATED + "warning": LOG_WARNING, } facility_names = { - "auth": LOG_AUTH, - "authpriv": LOG_AUTHPRIV, - "cron": LOG_CRON, - "daemon": LOG_DAEMON, - "kern": LOG_KERN, - "lpr": LOG_LPR, - "mail": LOG_MAIL, - "news": LOG_NEWS, - "security": LOG_AUTH, # DEPRECATED - "syslog": LOG_SYSLOG, - "user": LOG_USER, - "uucp": LOG_UUCP, - "local0": LOG_LOCAL0, - "local1": LOG_LOCAL1, - "local2": LOG_LOCAL2, - "local3": LOG_LOCAL3, - "local4": LOG_LOCAL4, - "local5": LOG_LOCAL5, - "local6": LOG_LOCAL6, - "local7": LOG_LOCAL7, + "auth": LOG_AUTH, + "authpriv": LOG_AUTHPRIV, + "cron": LOG_CRON, + "daemon": LOG_DAEMON, + "kern": LOG_KERN, + "lpr": LOG_LPR, + "mail": LOG_MAIL, + "news": LOG_NEWS, + "security": LOG_AUTH, # DEPRECATED + "syslog": LOG_SYSLOG, + "user": LOG_USER, + "uucp": LOG_UUCP, + "local0": LOG_LOCAL0, + "local1": LOG_LOCAL1, + "local2": LOG_LOCAL2, + "local3": LOG_LOCAL3, + "local4": LOG_LOCAL4, + "local5": LOG_LOCAL5, + "local6": LOG_LOCAL6, + "local7": LOG_LOCAL7, } import socket @@ -155,9 +155,9 @@ , socket.SOCK_DGRAM) self.unix = 0 - + log_format_string = '<%d>%s\000' - + def log (self, message, facility=LOG_USER, priority=LOG_INFO): message = self.log_format_string % ( self.encode_priority (facility, priority), @@ -167,15 +167,15 @@ self.socket.send (message) else: self.socket.sendto (message, self.address) - + def encode_priority (self, facility, priority): if type(facility) == type(''): facility = facility_names[facility] if type(priority) == type(''): - priority = priority_names[priority] + priority = priority_names[priority] return (facility<<3) | priority - + def close (self): if self.unix: self.socket.close() - + From shane@cvs.zope.org Thu Apr 4 18:46:28 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 13:46:28 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - CommonFTPActivityLogger.py:1.1.2.3 FTPCommandParser.py:1.1.2.4 FTPServer.py:1.1.2.5 FTPServerChannel.py:1.1.2.9 FTPStatusMessages.py:1.1.2.5 FTPTask.py:1.1.2.3 FileProducer.py:1.1.2.3 IFTPCommandHandler.py:1.1.2.3 PassiveAcceptor.py:1.1.2.2 PublisherFTPServer.py:1.1.2.2 PublisherFTPTask.py:1.1.2.2 RecvChannel.py:1.1.2.3 XmitChannel.py:1.1.2.2 __init__.py:1.1.2.2 Message-ID: <200204041846.g34IkSZ18346@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv17993/FTP Modified Files: Tag: Zope3-Server-Branch CommonFTPActivityLogger.py FTPCommandParser.py FTPServer.py FTPServerChannel.py FTPStatusMessages.py FTPTask.py FileProducer.py IFTPCommandHandler.py PassiveAcceptor.py PublisherFTPServer.py PublisherFTPTask.py RecvChannel.py XmitChannel.py __init__.py Log Message: Just fixed line endings. No carriage returns. === Zope3/lib/python/Zope/Server/FTP/CommonFTPActivityLogger.py 1.1.2.2 => 1.1.2.3 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - - -import time -import sys - -from Zope.Server.Logger.FileLogger import FileLogger -from Zope.Server.Logger.ResolvingLogger import ResolvingLogger -from Zope.Server.Logger.UnresolvingLogger import UnresolvingLogger - - -class CommonFTPActivityLogger: - """Outputs hits in common HTTP log format. - """ - - def __init__(self, logger_object=None, resolver=None): - if logger_object is None: - logger_object = FileLogger(sys.stdout) - - if resolver is not None: - self.output = ResolvingLogger(resolver, logger_object) - else: - self.output = UnresolvingLogger(logger_object) - - - def log(self, task): - """ - Receives a completed task and logs it in the - common log format. - """ - - now = time.localtime(time.time()) - - print now - self.output.log('127.0.0.1', time.strftime('%Y/%m/%d %H:%M', now)) +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + + +import time +import sys + +from Zope.Server.Logger.FileLogger import FileLogger +from Zope.Server.Logger.ResolvingLogger import ResolvingLogger +from Zope.Server.Logger.UnresolvingLogger import UnresolvingLogger + + +class CommonFTPActivityLogger: + """Outputs hits in common HTTP log format. + """ + + def __init__(self, logger_object=None, resolver=None): + if logger_object is None: + logger_object = FileLogger(sys.stdout) + + if resolver is not None: + self.output = ResolvingLogger(resolver, logger_object) + else: + self.output = UnresolvingLogger(logger_object) + + + def log(self, task): + """ + Receives a completed task and logs it in the + common log format. + """ + + now = time.localtime(time.time()) + + print now + self.output.log('127.0.0.1', time.strftime('%Y/%m/%d %H:%M', now)) === Zope3/lib/python/Zope/Server/FTP/FTPCommandParser.py 1.1.2.3 => 1.1.2.4 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -from Zope.Server.IStreamConsumer import IStreamConsumer - - -class FTPCommandParser: - """FTP Command parser. Arguments are left alone for now.""" - - __implements__ = IStreamConsumer - - - # See Zope.Server.IStreamConsumer.IStreamConsumer - completed = 0 - inbuf = '' - cmd = '' - args = '' - empty = 0 - - - max_line_length = 1024 # Not a hard limit - - - def __init__(self, adj): - """ - adj is an Adjustments object. - """ - self.adj = adj - - - ############################################################ - # Implementation methods for interface - # Zope.Server.IStreamConsumer - - def received(self, data): - 'See Zope.Server.IStreamConsumer.IStreamConsumer' - if self.completed: - return 0 # Can't consume any more. - pos = data.find('\n') - datalen = len(data) - if pos < 0: - self.inbuf = self.inbuf + data - if len(self.inbuf) > self.max_line_length: - # Don't accept any more. - self.completed = 1 - return datalen - else: - # Line finished. - s = data[:pos + 1] - self.inbuf = self.inbuf + s - self.completed = 1 - line = self.inbuf.strip() - self.parseLine(line) - return len(s) - - # - ############################################################ - - - def parseLine(self, line): - parts = line.split(' ', 1) - if len(parts) == 2: - self.cmd, self.args = parts - else: - self.cmd = parts[0] +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +from Zope.Server.IStreamConsumer import IStreamConsumer + + +class FTPCommandParser: + """FTP Command parser. Arguments are left alone for now.""" + + __implements__ = IStreamConsumer + + + # See Zope.Server.IStreamConsumer.IStreamConsumer + completed = 0 + inbuf = '' + cmd = '' + args = '' + empty = 0 + + + max_line_length = 1024 # Not a hard limit + + + def __init__(self, adj): + """ + adj is an Adjustments object. + """ + self.adj = adj + + + ############################################################ + # Implementation methods for interface + # Zope.Server.IStreamConsumer + + def received(self, data): + 'See Zope.Server.IStreamConsumer.IStreamConsumer' + if self.completed: + return 0 # Can't consume any more. + pos = data.find('\n') + datalen = len(data) + if pos < 0: + self.inbuf = self.inbuf + data + if len(self.inbuf) > self.max_line_length: + # Don't accept any more. + self.completed = 1 + return datalen + else: + # Line finished. + s = data[:pos + 1] + self.inbuf = self.inbuf + s + self.completed = 1 + line = self.inbuf.strip() + self.parseLine(line) + return len(s) + + # + ############################################################ + + + def parseLine(self, line): + parts = line.split(' ', 1) + if len(parts) == 2: + self.cmd, self.args = parts + else: + self.cmd = parts[0] + === Zope3/lib/python/Zope/Server/FTP/FTPServer.py 1.1.2.4 => 1.1.2.5 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" -import asyncore -from FTPServerChannel import FTPServerChannel -from Zope.Server.ServerBase import ServerBase -from Zope.Server.Counter import Counter - -from Zope.Server.VFS.UnixFileSystem import UnixFileSystem -from Zope.Server.Authentication.DictionaryAuthentication import \ - DictionaryAuthentication - - -class FTPServer(ServerBase): - """Generic FTP Server""" - - filesystem = UnixFileSystem('/') - auth_source = DictionaryAuthentication({'foo': 'bar'}) - - channel_class = FTPServerChannel - SERVER_IDENT = 'Zope.Server.FTPServer' - - - def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1, - hit_log=None, verbose=0, socket_map=None): - super(FTPServer, self).__init__(ip, port, task_dispatcher, - adj, start, hit_log, - verbose, socket_map) - - # statistics - self.total_sessions = Counter() - self.closed_sessions = Counter() - self.total_files_out = Counter() - self.total_files_in = Counter() - self.total_bytes_out = Counter() - self.total_bytes_in = Counter() - self.total_exceptions = Counter() - - -if __name__ == '__main__': - from Zope.Server.TaskThreads import ThreadedTaskDispatcher - td = ThreadedTaskDispatcher() - td.setThreadCount(4) - FTPServer('', 8021, task_dispatcher=td) - try: - while 1: - asyncore.poll(5) - print 'active channels:', FTPServerChannel.active_channels - except KeyboardInterrupt: - print 'shutting down...' - td.shutdown() +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" +import asyncore +from FTPServerChannel import FTPServerChannel +from Zope.Server.ServerBase import ServerBase +from Zope.Server.Counter import Counter + +from Zope.Server.VFS.UnixFileSystem import UnixFileSystem +from Zope.Server.Authentication.DictionaryAuthentication import \ + DictionaryAuthentication + + +class FTPServer(ServerBase): + """Generic FTP Server""" + + filesystem = UnixFileSystem('/') + auth_source = DictionaryAuthentication({'foo': 'bar'}) + + channel_class = FTPServerChannel + SERVER_IDENT = 'Zope.Server.FTPServer' + + + def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1, + hit_log=None, verbose=0, socket_map=None): + super(FTPServer, self).__init__(ip, port, task_dispatcher, + adj, start, hit_log, + verbose, socket_map) + + # statistics + self.total_sessions = Counter() + self.closed_sessions = Counter() + self.total_files_out = Counter() + self.total_files_in = Counter() + self.total_bytes_out = Counter() + self.total_bytes_in = Counter() + self.total_exceptions = Counter() + + +if __name__ == '__main__': + from Zope.Server.TaskThreads import ThreadedTaskDispatcher + td = ThreadedTaskDispatcher() + td.setThreadCount(4) + FTPServer('', 8021, task_dispatcher=td) + try: + while 1: + asyncore.poll(5) + print 'active channels:', FTPServerChannel.active_channels + except KeyboardInterrupt: + print 'shutting down...' + td.shutdown() === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.8 => 1.1.2.9 === (1103/1203 lines abridged) -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -import os -import stat -import socket -import time - -from Zope.Server.ServerChannelBase import ServerChannelBase -from FTPStatusMessages import status_msgs -from FTPCommandParser import FTPCommandParser -from FTPTask import FTPTask -from FileProducer import FileProducer - -from IFTPCommandHandler import IFTPCommandHandler -from PassiveAcceptor import PassiveAcceptor -from RecvChannel import RecvChannel -from XmitChannel import XmitChannel - - -# These are the commands that are accessing the filesystem. -# Since this could be also potentially a longer process, these commands -# are slao the ones that are executed in a different thread. -fs_access_cmds = ('cmd_appe', 'cmd_cdup', 'cmd_cwd', 'cmd_dele', 'cmd_list', - 'cmd_nlst', 'cmd_mdtm', 'cmd_mkd', 'cmd_pass', 'cmd_retr', - 'cmd_rmd', 'cmd_rnfr', 'cmd_rnto', 'cmd_size', 'cmd_stor', - 'cmd_stru') - - -class FTPServerChannel(ServerChannelBase): - """The FTP Server Channel represents a connection to a particular - client. We can therefore store information here.""" - - __implements__ = IFTPCommandHandler - - task_class = FTPTask [-=- -=- -=- 1103 lines omitted -=- -=- -=-] + + # pretty much the same as xmit, but only right on the verge of + # being worth a merge. + def createRecvChannel(self, fd): + pa = self.passive_acceptor + if pa: + if pa.ready: + # a connection has already been made. + conn, addr = pa.ready + cdc = RecvChannel(self, addr, fd) + cdc.set_socket (conn) + cdc.connected = 1 + self.passive_acceptor.close() + self.passive_acceptor = None + else: + # we're still waiting for a connect to the PASV port. + cdc = RecvChannel(self, None, fd) + else: + # not in PASV mode. + ip, port = self.client_addr + cdc = RecvChannel(self, self.client_addr, fd) + cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) + try: + cdc.connect ((ip, port)) + except socket.error, why: + self.reply(425) + + self.client_dc = cdc + + + def reply(self, code, pos=0, args=(), flush=1): + """ """ + try: + msg = status_msgs[code][pos] %args + except: + # XXX: Somehow handle the nonexisting response. + msg = 'The server created a bad response type (code %i).' %code + code = 500 + + if msg.startswith('-'): + fill = '' + else: + fill = ' ' + + self.write('%i%s%s\r\n' %(code, fill, msg)) + + if flush: + self.flush() + + # XXX: Some logging should go on here. === Zope3/lib/python/Zope/Server/FTP/FTPStatusMessages.py 1.1.2.4 => 1.1.2.5 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - - -status_msgs = { - 150: ('Opening %s mode data connection for file list', - 'Opening %s connection for %s',), - 200: ('%s command successful.', - 'Type set to %s.', - 'STRU F Ok.', - 'MODE S Ok.',), - 213: ('%4d%02d%02d%02d%02d%02d', # A date - '%d Bytes'), # Size - 214: ('-The following commands are recognized', - ''), - 215: ('%s Type: %s',), # Server Type - 220: ('%s FTP server (Zope Async/Thread V0.1) ready.',), - 221: ('Goodbye.',), - 226: ('%s command successful.', - 'Transfer successful.'), - 227: ('Entering Passive Mode (%s,%d,%d)',), - 230: ('Login Successful.',), - 250: ('%s command successful.',), - 257: ('%s command successful.', - "'%s' is the current directory.",), - 331: ('Password required',), - 350: ('Restarting at %d. Send STORE or RETRIEVE to initiate transfer.', - 'File exists, ready for destination.',), - 425: ("Can't build data connection",), - 426: ('Connection closed; transfer aborted.',), - 500: ("'%s': command not understood.",), - 502: ("Unimplemented MODE type",), - 504: ('Byte size must be 8', - 'Unimplemented STRU type',), - 530: ("You are not authorized to perform the '%s' command", - 'Please log in with USER and PASS', - 'The username and password do not match.',), - 550: ('Could not list directory: %s', - '%s: No such directory.', - '%s: No such file.', - '%s: Is not a file', - 'Error creating file.', - 'Error creating directory.', - 'Error deleting file.', - 'Error removing directory.'), - 553: ('Could not open file for reading: %s', - 'Could not open file for writing: %s', - 'Restart on STOR not yet supported',), - - 560: ('Could not rename %s to %s.', - 'No source filename specify. Call RNFR first.',), - } - +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + + +status_msgs = { + 150: ('Opening %s mode data connection for file list', + 'Opening %s connection for %s',), + 200: ('%s command successful.', + 'Type set to %s.', + 'STRU F Ok.', + 'MODE S Ok.',), + 213: ('%4d%02d%02d%02d%02d%02d', # A date + '%d Bytes'), # Size + 214: ('-The following commands are recognized', + ''), + 215: ('%s Type: %s',), # Server Type + 220: ('%s FTP server (Zope Async/Thread V0.1) ready.',), + 221: ('Goodbye.',), + 226: ('%s command successful.', + 'Transfer successful.'), + 227: ('Entering Passive Mode (%s,%d,%d)',), + 230: ('Login Successful.',), + 250: ('%s command successful.',), + 257: ('%s command successful.', + "'%s' is the current directory.",), + 331: ('Password required',), + 350: ('Restarting at %d. Send STORE or RETRIEVE to initiate transfer.', + 'File exists, ready for destination.',), + 425: ("Can't build data connection",), + 426: ('Connection closed; transfer aborted.',), + 500: ("'%s': command not understood.",), + 502: ("Unimplemented MODE type",), + 504: ('Byte size must be 8', + 'Unimplemented STRU type',), + 530: ("You are not authorized to perform the '%s' command", + 'Please log in with USER and PASS', + 'The username and password do not match.',), + 550: ('Could not list directory: %s', + '%s: No such directory.', + '%s: No such file.', + '%s: Is not a file', + 'Error creating file.', + 'Error creating directory.', + 'Error deleting file.', + 'Error removing directory.'), + 553: ('Could not open file for reading: %s', + 'Could not open file for writing: %s', + 'Restart on STOR not yet supported',), + + 560: ('Could not rename %s to %s.', + 'No source filename specify. Call RNFR first.',), + } + === Zope3/lib/python/Zope/Server/FTP/FTPTask.py 1.1.2.2 => 1.1.2.3 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -import socket -import time -from Zope.Server.ITask import ITask - - -class FTPTask: - """ - """ - - __implements__ = ITask - - - def __init__(self, channel, command, m_name): - self.channel = channel - self.m_name = m_name - self.args = command.args - - self.close_on_finish = 0 - - - ############################################################ - # Implementation methods for interface - # Zope.Server.ITask - - def service(self): - """Called to execute the task. - """ - try: - try: - self.start() - getattr(self.channel, self.m_name)(self.args) - self.finish() - except socket.error: - self.close_on_finish = 1 - if self.channel.adj.log_socket_errors: - raise - finally: - self.channel.end_task(self.close_on_finish) - - - def cancel(self): - 'See Zope.Server.ITask.ITask' - self.channel.close_when_done() - - - def defer(self): - 'See Zope.Server.ITask.ITask' - pass - - # - ############################################################ - - def start(self): - now = time.time() - self.start_time = now - - - def finish(self): - hit_log = self.channel.server.hit_log - if hit_log is not None: - hit_log.log(self) +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +import socket +import time +from Zope.Server.ITask import ITask + + +class FTPTask: + """ + """ + + __implements__ = ITask + + + def __init__(self, channel, command, m_name): + self.channel = channel + self.m_name = m_name + self.args = command.args + + self.close_on_finish = 0 + + + ############################################################ + # Implementation methods for interface + # Zope.Server.ITask + + def service(self): + """Called to execute the task. + """ + try: + try: + self.start() + getattr(self.channel, self.m_name)(self.args) + self.finish() + except socket.error: + self.close_on_finish = 1 + if self.channel.adj.log_socket_errors: + raise + finally: + self.channel.end_task(self.close_on_finish) + + + def cancel(self): + 'See Zope.Server.ITask.ITask' + self.channel.close_when_done() + + + def defer(self): + 'See Zope.Server.ITask.ITask' + pass + + # + ############################################################ + + def start(self): + now = time.time() + self.start_time = now + + + def finish(self): + hit_log = self.channel.server.hit_log + if hit_log is not None: + hit_log.log(self) === Zope3/lib/python/Zope/Server/FTP/FileProducer.py 1.1.2.2 => 1.1.2.3 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -class FileProducer: - """ """ - block_size = 16384 - - def __init__(self, server, dc, fd): - self.fd = fd - self.done = 0 - - - def more(self): - if self.done: - return '' - else: - block = self.fd.read(self.block_size) - if not block: - self.fd.close() - self.done = 1 - return block +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +class FileProducer: + """ """ + block_size = 16384 + + def __init__(self, server, dc, fd): + self.fd = fd + self.done = 0 + + + def more(self): + if self.done: + return '' + else: + block = self.fd.read(self.block_size) + if not block: + self.fd.close() + self.done = 1 + return block === Zope3/lib/python/Zope/Server/FTP/IFTPCommandHandler.py 1.1.2.2 => 1.1.2.3 === - -from Interface import Interface - -class IFTPCommandHandler(Interface): - """This interface defines all the FTP commands that are supported by the - server. - - Every command takes the command line as first arguments, since it is - responsible - """ - - def cmd_abor(args): - """Abort operation. No read access required. - """ - - def cmd_appe(args): - """Append to a file. Write access required. - """ - - def cmd_cdup(args): - """Change to parent of current working directory. - """ - - def cmd_cwd(args): - """Change working directory. - """ - - def cmd_dele(args): - """Delete a file. Write access required. - """ - - def cmd_help(args): - """Give help information. No read access required. - """ - - def cmd_list(args): - """Give list files in a directory. - """ - - def cmd_mdtm(args): - """Show last modification time of file. - - Example output: 213 19960301204320 - """ - - def cmd_mkd(args): - """Make a directory. Write access required. - """ - - def cmd_mode(args): - """Set file transfer mode. No read access required. Obselete. - """ - - def cmd_nlst(args): - """Give name list of files in directory. - """ - - def cmd_noop(args): - """Do nothing. No read access required. - """ - - def cmd_pass(args): - """Specify password. - """ - - def cmd_pasv(args): - """Prepare for server-to-server transfer. No read access required. - """ - - def cmd_port(args): - """Specify data connection port. No read access required. - """ - - def cmd_pwd(args): - """Print the current working directory. - """ - - def cmd_quit(args): - """Terminate session. No read access required. - """ - - def cmd_rest(args): - """Restart incomplete transfer. - """ - - def cmd_retr(args): - """Retrieve a file. - """ - - def cmd_rmd(args): - """Remove a directory. Write access required. - """ - - def cmd_rnfr(args): - """Specify rename-from file name. Write access required. - """ - - def cmd_rnto(args): - """Specify rename-to file name. Write access required. - """ - - def cmd_size(args): - """Return size of file. - """ - - def cmd_stat(args): - """Return status of server. No read access required. - """ - - def cmd_stor(args): - """Store a file. Write access required. - """ - - def cmd_stru(args): - """Set file transfer structure. Obselete.""" - - def cmd_syst(args): - """Show operating system type of server system. - - No read access required. - - Replying to this command is of questionable utility, - because this server does not behave in a predictable way - w.r.t. the output of the LIST command. We emulate Unix ls - output, but on win32 the pathname can contain drive - information at the front Currently, the combination of - ensuring that os.sep == '/' and removing the leading slash - when necessary seems to work. [cd'ing to another drive - also works] - - This is how wuftpd responds, and is probably the most - expected. The main purpose of this reply is so that the - client knows to expect Unix ls-style LIST output. - - one disadvantage to this is that some client programs - assume they can pass args to /bin/ls. a few typical - responses: - - 215 UNIX Type: L8 (wuftpd) - 215 Windows_NT version 3.51 - 215 VMS MultiNet V3.3 - 500 'SYST': command not understood. (SVR4) - """ - - def cmd_type(args): - """Specify data transfer type. No read access required. - """ - - def cmd_user(args): - """Specify user name. No read access required. - """ - - - -# this is the command list from the wuftpd man page -# '!' requires write access -# -not_implemented_commands = { - 'acct': 'specify account (ignored)', - 'allo': 'allocate storage (vacuously)', - 'site': 'non-standard commands (see next section)', - 'stou': 'store a file with a unique name', #! - 'xcup': 'change to parent of current working directory (deprecated)', - 'xcwd': 'change working directory (deprecated)', - 'xmkd': 'make a directory (deprecated)', #! - 'xpwd': 'print the current working directory (deprecated)', - 'xrmd': 'remove a directory (deprecated)', #! -} + + +from Interface import Interface + +class IFTPCommandHandler(Interface): + """This interface defines all the FTP commands that are supported by the + server. + + Every command takes the command line as first arguments, since it is + responsible + """ + + def cmd_abor(args): + """Abort operation. No read access required. + """ + + def cmd_appe(args): + """Append to a file. Write access required. + """ + + def cmd_cdup(args): + """Change to parent of current working directory. + """ + + def cmd_cwd(args): + """Change working directory. + """ + + def cmd_dele(args): + """Delete a file. Write access required. + """ + + def cmd_help(args): + """Give help information. No read access required. + """ + + def cmd_list(args): + """Give list files in a directory. + """ + + def cmd_mdtm(args): + """Show last modification time of file. + + Example output: 213 19960301204320 + """ + + def cmd_mkd(args): + """Make a directory. Write access required. + """ + + def cmd_mode(args): + """Set file transfer mode. No read access required. Obselete. + """ + + def cmd_nlst(args): + """Give name list of files in directory. + """ + + def cmd_noop(args): + """Do nothing. No read access required. + """ + + def cmd_pass(args): + """Specify password. + """ + + def cmd_pasv(args): + """Prepare for server-to-server transfer. No read access required. + """ + + def cmd_port(args): + """Specify data connection port. No read access required. + """ + + def cmd_pwd(args): + """Print the current working directory. + """ + + def cmd_quit(args): + """Terminate session. No read access required. + """ + + def cmd_rest(args): + """Restart incomplete transfer. + """ + + def cmd_retr(args): + """Retrieve a file. + """ + + def cmd_rmd(args): + """Remove a directory. Write access required. + """ + + def cmd_rnfr(args): + """Specify rename-from file name. Write access required. + """ + + def cmd_rnto(args): + """Specify rename-to file name. Write access required. + """ + + def cmd_size(args): + """Return size of file. + """ + + def cmd_stat(args): + """Return status of server. No read access required. + """ + + def cmd_stor(args): + """Store a file. Write access required. + """ + + def cmd_stru(args): + """Set file transfer structure. Obselete.""" + + def cmd_syst(args): + """Show operating system type of server system. + + No read access required. + + Replying to this command is of questionable utility, + because this server does not behave in a predictable way + w.r.t. the output of the LIST command. We emulate Unix ls + output, but on win32 the pathname can contain drive + information at the front Currently, the combination of + ensuring that os.sep == '/' and removing the leading slash + when necessary seems to work. [cd'ing to another drive + also works] + + This is how wuftpd responds, and is probably the most + expected. The main purpose of this reply is so that the + client knows to expect Unix ls-style LIST output. + + one disadvantage to this is that some client programs + assume they can pass args to /bin/ls. a few typical + responses: + + 215 UNIX Type: L8 (wuftpd) + 215 Windows_NT version 3.51 + 215 VMS MultiNet V3.3 + 500 'SYST': command not understood. (SVR4) + """ + + def cmd_type(args): + """Specify data transfer type. No read access required. + """ + + def cmd_user(args): + """Specify user name. No read access required. + """ + + + +# this is the command list from the wuftpd man page +# '!' requires write access +# +not_implemented_commands = { + 'acct': 'specify account (ignored)', + 'allo': 'allocate storage (vacuously)', + 'site': 'non-standard commands (see next section)', + 'stou': 'store a file with a unique name', #! + 'xcup': 'change to parent of current working directory (deprecated)', + 'xcwd': 'change working directory (deprecated)', + 'xmkd': 'make a directory (deprecated)', #! + 'xpwd': 'print the current working directory (deprecated)', + 'xrmd': 'remove a directory (deprecated)', #! +} === Zope3/lib/python/Zope/Server/FTP/PassiveAcceptor.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -import asyncore -import socket - - -class PassiveAcceptor(asyncore.dispatcher): - """This socket accepts a data connection, used when the server has - been placed in passive mode. Although the RFC implies that we - ought to be able to use the same acceptor over and over again, - this presents a problem: how do we shut it off, so that we are - accepting connections only when we expect them? [we can't] - - wuftpd, and probably all the other servers, solve this by - allowing only one connection to hit this acceptor. They then - close it. Any subsequent data-connection command will then try - for the default port on the client side [which is of course - never there]. So the 'always-send-PORT/PASV' behavior seems - required. - - Another note: wuftpd will also be listening on the channel as - soon as the PASV command is sent. It does not wait for a data - command first. - - --- we need to queue up a particular behavior: - 1) xmit : queue up producer[s] - 2) recv : the file object - - It would be nice if we could make both channels the same. - Hmmm..""" - - __implements__ = asyncore.dispatcher.__implements__ - - ready = None - - def __init__ (self, control_channel): - asyncore.dispatcher.__init__ (self) - self.control_channel = control_channel - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - # bind to an address on the interface that the - # control connection is coming from. - self.bind ( (self.control_channel.getsockname()[0], 0) ) - self.addr = self.getsockname() - self.listen(1) - - - def log (self, *ignore): - pass - - - def handle_accept (self): - conn, addr = self.accept() - dc = self.control_channel.client_dc - if dc is not None: - dc.set_socket(conn) - dc.addr = addr - dc.connected = 1 - self.control_channel.passive_acceptor = None - else: - self.ready = conn, addr - self.close() +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +import asyncore +import socket + + +class PassiveAcceptor(asyncore.dispatcher): + """This socket accepts a data connection, used when the server has + been placed in passive mode. Although the RFC implies that we + ought to be able to use the same acceptor over and over again, + this presents a problem: how do we shut it off, so that we are + accepting connections only when we expect them? [we can't] + + wuftpd, and probably all the other servers, solve this by + allowing only one connection to hit this acceptor. They then + close it. Any subsequent data-connection command will then try + for the default port on the client side [which is of course + never there]. So the 'always-send-PORT/PASV' behavior seems + required. + + Another note: wuftpd will also be listening on the channel as + soon as the PASV command is sent. It does not wait for a data + command first. + + --- we need to queue up a particular behavior: + 1) xmit : queue up producer[s] + 2) recv : the file object + + It would be nice if we could make both channels the same. + Hmmm..""" + + __implements__ = asyncore.dispatcher.__implements__ + + ready = None + + def __init__ (self, control_channel): + asyncore.dispatcher.__init__ (self) + self.control_channel = control_channel + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + # bind to an address on the interface that the + # control connection is coming from. + self.bind ( (self.control_channel.getsockname()[0], 0) ) + self.addr = self.getsockname() + self.listen(1) + + + def log (self, *ignore): + pass + + + def handle_accept (self): + conn, addr = self.accept() + dc = self.control_channel.client_dc + if dc is not None: + dc.set_socket(conn) + dc.addr = addr + dc.connected = 1 + self.control_channel.passive_acceptor = None + else: + self.ready = conn, addr + self.close() === Zope3/lib/python/Zope/Server/FTP/PublisherFTPServer.py 1.1.2.1 => 1.1.2.2 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ === Zope3/lib/python/Zope/Server/FTP/PublisherFTPTask.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -from FTPTask import FTPTask -from Zope.Publisher.Publish import publish - - -class PublisherFTPTask(FTPTask): - """ """ - - __implements__ = FTPTask.__implements__ - - - def execute(self): - """ """ - server = self.channel.server - env = self.create_environment() - instream = self.request_data.getBodyStream() - - request = server.request_factory(instream, self, env) - publish(request) - - - def create_environment(self): - request_data = self.request_data - channel = self.channel - server = channel.server - - # This should probably change to reflect calling the FileSystem - # methods - env = {'command': request_data.command - 'args': request_data.args - } - - - return env +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +from FTPTask import FTPTask +from Zope.Publisher.Publish import publish + + +class PublisherFTPTask(FTPTask): + """ """ + + __implements__ = FTPTask.__implements__ + + + def execute(self): + """ """ + server = self.channel.server + env = self.create_environment() + instream = self.request_data.getBodyStream() + + request = server.request_factory(instream, self, env) + publish(request) + + + def create_environment(self): + request_data = self.request_data + channel = self.channel + server = channel.server + + # This should probably change to reflect calling the FileSystem + # methods + env = {'command': request_data.command + 'args': request_data.args + } + + + return env === Zope3/lib/python/Zope/Server/FTP/RecvChannel.py 1.1.2.2 => 1.1.2.3 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" -import asyncore -from Zope.Server.Counter import Counter - -class RecvChannel(asyncore.dispatcher): - """ """ - - def __init__ (self, channel, client_addr, fd): - self.channel = channel - self.client_addr = client_addr - self.fd = fd - asyncore.dispatcher.__init__ (self) - self.bytes_in = Counter() - - - def log (self, *ignore): - pass - - - def handle_connect (self): - pass - - - def writable (self): - return 0 - - - def recv (*args): - result = apply (asyncore.dispatcher.recv, args) - self = args[0] - self.bytes_in.increment(len(result)) - return result - - - buffer_size = 8192 - - - def handle_read (self): - block = self.recv (self.buffer_size) - if block: - try: - self.fd.write (block) - except IOError: - self.log_info ('got exception writing block...', 'error') - - - def handle_close (self): - s = self.channel.server - s.total_files_in.increment() - s.total_bytes_in.increment(self.bytes_in.as_long()) - self.fd.close() - self.channel.reply(226, 1) - self.close() +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" +import asyncore +from Zope.Server.Counter import Counter + +class RecvChannel(asyncore.dispatcher): + """ """ + + def __init__ (self, channel, client_addr, fd): + self.channel = channel + self.client_addr = client_addr + self.fd = fd + asyncore.dispatcher.__init__ (self) + self.bytes_in = Counter() + + + def log (self, *ignore): + pass + + + def handle_connect (self): + pass + + + def writable (self): + return 0 + + + def recv (*args): + result = apply (asyncore.dispatcher.recv, args) + self = args[0] + self.bytes_in.increment(len(result)) + return result + + + buffer_size = 8192 + + + def handle_read (self): + block = self.recv (self.buffer_size) + if block: + try: + self.fd.write (block) + except IOError: + self.log_info ('got exception writing block...', 'error') + + + def handle_close (self): + s = self.channel.server + s.total_files_in.increment() + s.total_bytes_in.increment(self.bytes_in.as_long()) + self.fd.close() + self.channel.reply(226, 1) + self.close() === Zope3/lib/python/Zope/Server/FTP/XmitChannel.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -import asynchat - - -class XmitChannel(asynchat.async_chat, object): - - # for an ethernet, you want this to be fairly large, in fact, it - # _must_ be large for performance comparable to an ftpd. [64k] we - # ought to investigate automatically-sized buffers... - ac_out_buffer_size = 16384 - - bytes_out = 0 - - def __init__ (self, channel, client_addr=None): - self.channel = channel - self.client_addr = client_addr - super(XmitChannel, self).__init__() - - - def log (*args): - pass - - - def readable (self): - return not self.connected - - - def writable (self): - return 1 - - - def send (self, data): - result = super(XmitChannel, self).send(data) - self.bytes_out = self.bytes_out + result - return result - - - def handle_error (self): - # usually this is to catch an unexpected disconnect. - # XXX: Helpfule for debugging - import traceback - traceback.print_exc() - self.log_info ('unexpected disconnect on data xmit channel', 'error') - try: - self.close() - except: - pass - - # TODO: there's a better way to do this. we need to be able to - # put 'events' in the producer fifo. to do this cleanly we need - # to reposition the 'producer' fifo as an 'event' fifo. - - # dummy function to suppress warnings caused by some FTP clients - def handle_connect(self): - pass - - - def close (self): - c = self.channel - s = c.server - c.client_dc = None - s.total_files_out.increment() - s.total_bytes_out.increment (self.bytes_out) - if not len(self.producer_fifo): - c.reply(226, 1) - elif not c.closed: - c.reply(426) - del c - del s - del self.channel - asynchat.async_chat.close(self) +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +import asynchat + + +class XmitChannel(asynchat.async_chat, object): + + # for an ethernet, you want this to be fairly large, in fact, it + # _must_ be large for performance comparable to an ftpd. [64k] we + # ought to investigate automatically-sized buffers... + ac_out_buffer_size = 16384 + + bytes_out = 0 + + def __init__ (self, channel, client_addr=None): + self.channel = channel + self.client_addr = client_addr + super(XmitChannel, self).__init__() + + + def log (*args): + pass + + + def readable (self): + return not self.connected + + + def writable (self): + return 1 + + + def send (self, data): + result = super(XmitChannel, self).send(data) + self.bytes_out = self.bytes_out + result + return result + + + def handle_error (self): + # usually this is to catch an unexpected disconnect. + # XXX: Helpfule for debugging + import traceback + traceback.print_exc() + self.log_info ('unexpected disconnect on data xmit channel', 'error') + try: + self.close() + except: + pass + + # TODO: there's a better way to do this. we need to be able to + # put 'events' in the producer fifo. to do this cleanly we need + # to reposition the 'producer' fifo as an 'event' fifo. + + # dummy function to suppress warnings caused by some FTP clients + def handle_connect(self): + pass + + + def close (self): + c = self.channel + s = c.server + c.client_dc = None + s.total_files_out.increment() + s.total_bytes_out.increment (self.bytes_out) + if not len(self.producer_fifo): + c.reply(226, 1) + elif not c.closed: + c.reply(426) + del c + del s + del self.channel + asynchat.async_chat.close(self) === Zope3/lib/python/Zope/Server/FTP/__init__.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" From chrism@zope.com Thu Apr 4 20:21:47 2002 From: chrism@zope.com (Chris McDonough) Date: Thu, 4 Apr 2002 15:21:47 -0500 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/Transience - TransientObject.py:1.3.16.2 Message-ID: <200204042021.g34KLl125964@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/Transience In directory cvs.zope.org:/tmp/cvs-serv25881 Modified Files: Tag: Zope-2_5-branch TransientObject.py Log Message: Fixed bug where ttw code that called: del transientobject['key'] Would fail with a slice error (due to the security machinery). Assigning __garded_delitem__ to __delitem__ solves this problem. === Zope/lib/python/Products/Transience/TransientObject.py 1.3.16.1 => 1.3.16.2 === set = __setitem__ __guarded_setitem__ = __setitem__ + __guarded_delitem__ = __delitem__ delete = __delitem__ # ----------------------------------------------------------------- From chrism@zope.com Thu Apr 4 20:22:43 2002 From: chrism@zope.com (Chris McDonough) Date: Thu, 4 Apr 2002 15:22:43 -0500 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/Transience - TransientObject.py:1.5 Message-ID: <200204042022.g34KMhN26429@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/Transience In directory cvs.zope.org:/tmp/cvs-serv26103 Modified Files: TransientObject.py Log Message: Fixed bug where ttw code that called: del transientobject['key'] Would fail with a slice error (due to the security machinery). Assigning __garded_delitem__ to __delitem__ solves this problem. === Zope/lib/python/Products/Transience/TransientObject.py 1.4 => 1.5 === set = __setitem__ __guarded_setitem__ = __setitem__ + __guarded_delitem__ = __delitem__ delete = __delitem__ # ----------------------------------------------------------------- From chrism@zope.com Thu Apr 4 20:25:26 2002 From: chrism@zope.com (Chris McDonough) Date: Thu, 4 Apr 2002 15:25:26 -0500 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.406.2.38 Message-ID: <200204042025.g34KPQS28073@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv28024 Modified Files: Tag: Zope-2_5-branch CHANGES.txt Log Message: === Zope/doc/CHANGES.txt 1.406.2.37 => 1.406.2.38 === Bugs Fixed + - Fixed bug where TTW code that called: + + del REQUEST.SESSION['key'] + + Would fail with a slice error (due to the security machinery). + Assigning __garded_delitem__ to __delitem__ solves this problem, + and allows del to be called against a SESSION key value. + - Fixed a bug that could cause spurious AttributeErrors and other strange failures when trying to work with methods acquired from within the context of a transient object obtained via From barry@wooz.org Thu Apr 4 22:02:32 2002 From: barry@wooz.org (Barry Warsaw) Date: Thu, 4 Apr 2002 17:02:32 -0500 Subject: [Zope-Checkins] CVS: StandaloneZODB/ZODB - cPickleCache.c:1.54 Message-ID: <200204042202.g34M2WK29914@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZODB In directory cvs.zope.org:/tmp/cvs-serv29907 Modified Files: cPickleCache.c Log Message: cc_ass_sub(): Fixed typo in type check of the key. PyErr_Format() takes an exception object as its first argument, and the return value should be a -1 instead of NULL (this function's signature has an int return). I'm surprised no one else's build caught this compiler warning. === StandaloneZODB/ZODB/cPickleCache.c 1.53 => 1.54 === { if (!PyString_Check(key)) { - PyErr_Format("cPickleCache key must be a string, not a %s", + PyErr_Format(PyExc_TypeError, + "cPickleCache key must be a string, not a %s", key->ob_type->tp_name); - return NULL; + return -1; } if (v) return cc_add_item(self, key, v); From shane@cvs.zope.org Thu Apr 4 23:09:29 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 18:09:29 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server - DualModeChannel.py:1.1.2.4.2.4 Message-ID: <200204042309.g34N9T614859@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server In directory cvs.zope.org:/tmp/cvs-serv14852 Modified Files: Tag: Zope3-Server-Branch DualModeChannel.py Log Message: Added an argument to flush() to allow non-blocking flush, and added more comments. === Zope3/lib/python/Zope/Server/DualModeChannel.py 1.1.2.4.2.3 => 1.1.2.4.2.4 === while len(self.outbuf) >= self.adj.send_bytes: # Send what we can without blocking. - # We propogate errors to the application on purpose - # (to prevent unnecessary work). + # We propagate errors to the application on purpose + # (to stop the application if the connection closes). if not self._flush_some(): break - def flush(self): - """ - Pauses the application while outbuf is flushed. - Normally not a good thing to do. + def flush(self, block=1): + """Sends pending data. + + If block is set, this pauses the application. If it is turned + off, only the amount of data that can be sent without blocking + is sent. """ + if not block: + while self._flush_some(): + pass + return blocked = 0 try: while self.outbuf: - # We propogate errors to the application on purpose. + # We propagate errors to the application on purpose. if not blocked: self.socket.setblocking(1) blocked = 1 @@ -205,6 +211,9 @@ # def _flush_some(self): + """Flushes data. + + Returns 1 if some data was sent.""" outbuf = self.outbuf if outbuf: chunk = outbuf.get(self.adj.send_bytes) @@ -252,6 +261,8 @@ if allocate_lock is None: from thread import allocate_lock + # writelock protects all accesses to outbuf, since reads and + # writes of buffers in this class need to be serialized. writelock = allocate_lock() self._writelock_acquire = writelock.acquire self._writelock_release = writelock.release @@ -295,10 +306,10 @@ finally: self._writelock_release() - def flush(self): + def flush(self, block=1): self._writelock_acquire() try: - DualModeChannel.flush(self) + DualModeChannel.flush(self, block) finally: self._writelock_release() From shane@cvs.zope.org Thu Apr 4 23:22:01 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 18:22:01 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server - ServerChannelBase.py:1.1.2.4 Message-ID: <200204042322.g34NM1f17579@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server In directory cvs.zope.org:/tmp/cvs-serv15173 Modified Files: Tag: Zope3-Server-Branch ServerChannelBase.py Log Message: There was potential DoS vulnerability that appeared once we decided not all requests are serviced by a task: non-task requests that are queued up while a task is running will later be serviced in recursive calls. An attacker could queue a lot of non-task requests and overflow the stack. (process_request() calls end_task(), which calls process_request().) I had to change the API a bit. process_request() now either returns a task or processes the request directly, returning None. This lets the server base have more control over threads. === Zope3/lib/python/Zope/Server/ServerChannelBase.py 1.1.2.3 => 1.1.2.4 === proto_request = None # A request parser instance ready_requests = None # A list + # ready_requests must always be empty when not running tasks. last_activity = 0 # Time of last activity running_tasks = 0 # boolean: true when any task is being executed @@ -104,14 +105,17 @@ """ now = time.time() cutoff = now - self.adj.channel_timeout + class_ = self.__class__ # Kill only channels of our own class. for channel in self.active_channels.values(): if (channel is not self and not channel.running_tasks and - channel.last_activity < cutoff): + channel.last_activity < cutoff and + isinstance(channel, class_)): channel.close() def received(self, data): - """Receives input asynchronously and launches or queues requests. + """Receive input asynchronously and send requests to + receivedCompleteRequest(). """ preq = self.proto_request while data: @@ -121,7 +125,7 @@ if preq.completed: # The request is ready to use. if not preq.empty: - self.queue_request(preq) + self.receivedCompleteRequest(preq) preq = None self.proto_request = None else: @@ -131,14 +135,16 @@ data = data[n:] - def queue_request(self, req): - """Queues a request to be processed in sequence. + def receivedCompleteRequest(self, req): + """If there are tasks running or requests on hold, queue + the request, otherwise execute it. """ do_now = 0 running_lock.acquire() try: if self.running_tasks: - # Wait for the current tasks to finish. + # A task thread is working. It will read from the queue + # when it is finished. rr = self.ready_requests if rr is None: rr = [] @@ -146,12 +152,15 @@ rr.append(req) else: # Do it now. - self.running_tasks = 1 do_now = 1 finally: running_lock.release() if do_now: - self.process_request(req) + task = self.process_request(req) + if task is not None: + self.running_tasks = 1 + self.set_sync() + self.server.addTask(task) def handle_error(self): @@ -172,6 +181,7 @@ # Ignore socket errors. self.close() + # # SYNCHRONOUS METHODS # @@ -180,37 +190,48 @@ """Called at the end of a task and may launch another task. """ if close: + # Note that self.running_tasks is left on, which has the + # side effect of preventing further requests from being + # serviced even if more appear. A good thing. self.close_when_done() return - new_req = None - running_lock.acquire() - try: - rr = self.ready_requests - if rr: - new_req = rr.pop(0) + # Process requests held in the queue, if any. + while 1: + req = None + running_lock.acquire() + try: + rr = self.ready_requests + if rr: + req = rr.pop(0) + else: + # No requests to process. + self.running_tasks = 0 + finally: + running_lock.release() + + if req: + task = self.process_request(req) + if task is not None: + # Add the new task. It will service the queue. + self.server.addTask(task) + break + # else check the queue again. else: - # No requests to service. - self.running_tasks = 0 - finally: - running_lock.release() + # Idle -- Wait for another request on this connection. + self.set_async() + break - if new_req: - # Respond to the next request. - self.process_request(new_req) - else: - # Wait for another request on this connection. - self.set_async() # # BOTH MODES # def process_request(self, req): - """Creates a new task and queues it for execution. + """Returns a task to execute or None if the request is quick and + can be processed in the main thread. - The task may get executed in another thread. + Override to handle some requests in the main thread. """ - self.set_sync() - task = self.task_class(self, req) - self.server.addTask(task) + return self.task_class(self, req) + From shane@cvs.zope.org Thu Apr 4 23:22:49 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 18:22:49 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - FTPServerChannel.py:1.1.2.10 Message-ID: <200204042322.g34NMnG17994@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv17669 Modified Files: Tag: Zope3-Server-Branch FTPServerChannel.py Log Message: Updated to match changes in ServerBase and DualModeChannel. === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.9 => 1.1.2.10 === self.client_dc = None - self.transfer_mode = 'a' + self.transfer_mode = 'i' # Use binary by default self.passive_mode = 0 self.cwd = '/' self._rnfr = None @@ -116,10 +116,7 @@ elif method in fs_access_cmds: # Process in another thread. - task = self.task_class(self, command, method) - self.set_sync() - self.server.addTask(task) - return + return self.task_class(self, command, method) elif hasattr(self, method): getattr(self, method)(command.args) @@ -127,8 +124,6 @@ else: self.reply(500, 0, (cmd.upper())) - self.end_task(0) - ############################################################ # Implementation methods for interface @@ -163,7 +158,7 @@ self.cwd = path self.reply(250, 0, 'CWD') else: - self.reply (550, 1, path) + self.reply(550, 1, path) def cmd_dele(self, args): @@ -597,6 +592,6 @@ self.write('%i%s%s\r\n' %(code, fill, msg)) if flush: - self.flush() + self.flush(0) # XXX: Some logging should go on here. From shane@cvs.zope.org Thu Apr 4 23:24:51 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 4 Apr 2002 18:24:51 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/HTTP - HTTPServerChannel.py:1.1.2.3 Message-ID: <200204042324.g34NOpE18641@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/HTTP In directory cvs.zope.org:/tmp/cvs-serv18110 Modified Files: Tag: Zope3-Server-Branch HTTPServerChannel.py Log Message: The zombie channel tracking no longer requires overriding attributes in each subclass. It's not important enough to make so complicated. :-) === Zope3/lib/python/Zope/Server/HTTP/HTTPServerChannel.py 1.1.2.2 => 1.1.2.3 === task_class = HTTPTask parser_class = HTTPRequestParser - - active_channels = {} # Class-specific channel tracker - next_channel_cleanup = [0] # Class-specific cleanup time From jeremy@zope.com Fri Apr 5 01:12:48 2002 From: jeremy@zope.com (Jeremy Hylton) Date: Thu, 4 Apr 2002 20:12:48 -0500 Subject: [Zope-Checkins] CVS: StandaloneZODB/ZODB - cPersistence.c:1.58 cPersistence.h:1.25 cPickleCache.c:1.55 Message-ID: <200204050112.g351CmD14505@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZODB In directory cvs.zope.org:/tmp/cvs-serv14496 Modified Files: cPersistence.c cPersistence.h cPickleCache.c Log Message: Move cc_oid_unreferenced() into the C API and out of Python. The rationale is that this is an internal detail of the cache implementation called by Per_dealloc(). It's nice to make it fast, and it's good to prevent it from being called with anything other than an about-to-be-freed object. As a result of it being in the C API, omit tests of refcounts. We would have been in Per_dealloc() otherwise. Initialize the percachdel slot of cPersistenceAPIstruct to NULL in cPersistence. In cPickleCache, import the CObject and fill in the struct. Also, reformat many of the comments so that all the text starts to the right of the /*. Fiddle the text of the placeholder comment. I think I understand it now :-). Add an XXX comment about the "old" cache API e.g. fullsweep and reallyfullsweep. Fix cc_get(). object_from_oid() doesn't ever set an exception. Remove a Py_FatalError() check from the end of a module init function. We don't do that anymore. === StandaloneZODB/ZODB/cPersistence.c 1.57 => 1.58 === #include "cPersistence.h" -/* XXX What is this structure used for? */ struct ccobject_head_struct { CACHE_HEAD }; @@ -202,15 +201,11 @@ if (self->state >= 0) ghostify(self); if (self->cache) { - PyObject *v; - - /* XXX should just add this to the C API struct */ - v = PyObject_CallMethod((PyObject *)self->cache, - "_oid_unreferenced", "O", self->oid); - if (v == NULL) - PyErr_Clear(); /* I dont think this should ever happen */ - else - Py_DECREF(v); + /* XXX This function shouldn't be able to fail? If not, maybe + it shouldn't set an exception either. + */ + if (cPersistenceCAPI->percachedel(self->cache, self->oid) < 0) + PyErr_Clear(); /* I don't think this should ever happen */ } Py_XDECREF(self->jar); Py_XDECREF(self->oid); @@ -256,19 +251,22 @@ static PyObject * Per___changed__(cPersistentObject *self, PyObject *args) { - PyObject *v=0; - - if (args && ! PyArg_ParseTuple(args, "|O",&v)) return NULL; - if (! v) return PyObject_GetAttr(OBJECT(self), py__p_changed); + PyObject *v = NULL; - if (PyObject_IsTrue(v)) - { - if (changed(self) < 0) return NULL; + if (args && !PyArg_ParseTuple(args, "|O:__changed__", &v)) + return NULL; + if (!v) + return PyObject_GetAttr(OBJECT(self), py__p_changed); + + if (PyObject_IsTrue(v)) { + if (changed(self) < 0) + return NULL; } - else if (self->state >= 0) self->state=cPersistent_UPTODATE_STATE; + else if (self->state >= 0) + self->state = cPersistent_UPTODATE_STATE; - Py_INCREF(Py_None); - return Py_None; + Py_INCREF(Py_None); + return Py_None; } static PyObject * @@ -295,7 +293,7 @@ } /* need to delay releasing the last reference on instance attributes - until after we have finished accounting for losing our state */ + until after we have finished accounting for losing our state */ if (dict2) { PyDict_Clear(dict2); @@ -807,6 +805,7 @@ deallocated, (intfunctionwithpythonarg)Per_setstate, (pergetattr)Per_getattr, + NULL }; void @@ -826,7 +825,8 @@ Py_DECREF(m); Py_DECREF(s); - if (init_strings() < 0) return; + if (init_strings() < 0) + return; m = Py_InitModule4("cPersistence", cP_methods, cPersistence_doc_string, (PyObject*)NULL, PYTHON_API_VERSION); @@ -837,12 +837,8 @@ PyExtensionClass_Export(d, "Persistent", Pertype); PyExtensionClass_Export(d, "Overridable", Overridable); - cPersistenceCAPI=&truecPersistenceCAPI; - s = PyCObject_FromVoidPtr(cPersistenceCAPI,NULL); + cPersistenceCAPI = &truecPersistenceCAPI; + s = PyCObject_FromVoidPtr(cPersistenceCAPI, NULL); PyDict_SetItemString(d, "CAPI", s); Py_XDECREF(s); - - /* Check for errors */ - if (PyErr_Occurred()) - Py_FatalError("can't initialize module cPersistence"); } === StandaloneZODB/ZODB/cPersistence.h 1.24 => 1.25 === #include +typedef struct CPersistentRing_struct +{ + struct CPersistentRing_struct *prev; + struct CPersistentRing_struct *next; +} CPersistentRing; + #define CACHE_HEAD \ PyObject_HEAD \ CPersistentRing ring_home; \ @@ -42,30 +48,26 @@ #define cPersistent_CHANGED_STATE 1 #define cPersistent_STICKY_STATE 2 -typedef struct CPersistentRing_struct -{ - struct CPersistentRing_struct *prev; - struct CPersistentRing_struct *next; -} CPersistentRing; - typedef struct { cPersistent_HEAD } cPersistentObject; typedef int (*persetattr)(PyObject *, PyObject*, PyObject *, setattrofunc); typedef PyObject *(*pergetattr)(PyObject *, PyObject*, char *, getattrofunc); +typedef int (*percachedelfunc)(PerCache *, PyObject *); typedef struct { - PyMethodChain *methods; - getattrofunc getattro; - setattrofunc setattro; - int (*changed)(cPersistentObject*); - void (*accessed)(cPersistentObject*); - void (*ghostify)(cPersistentObject*); - void (*deallocated)(cPersistentObject*); - int (*setstate)(PyObject*); - pergetattr pergetattro; - persetattr persetattro; + PyMethodChain *methods; + getattrofunc getattro; + setattrofunc setattro; + int (*changed)(cPersistentObject*); + void (*accessed)(cPersistentObject*); + void (*ghostify)(cPersistentObject*); + void (*deallocated)(cPersistentObject*); + int (*setstate)(PyObject*); + pergetattr pergetattro; + persetattr persetattro; + percachedelfunc percachedel; } cPersistenceCAPIstruct; #ifndef DONT_USE_CPERSISTENCECAPI === StandaloneZODB/ZODB/cPickleCache.c 1.54 => 1.55 === #endif -/* This object is the pickle cache. The CACHE_HEAD macro guarantees that -layout of this struct is the same as the start of ccobject_head in -cPersistence.c */ +/* This object is the pickle cache. The CACHE_HEAD macro guarantees + that layout of this struct is the same as the start of + ccobject_head in cPersistence.c */ typedef struct { CACHE_HEAD int klass_count; /* count of persistent classes */ @@ -156,15 +156,15 @@ /* ---------------------------------------------------------------- */ -static PyObject *object_from_oid(ccobject *self, PyObject *key) /* somewhat of a replacement for PyDict_GetItem(self->data.... however this returns a *new* reference */ +static PyObject * +object_from_oid(ccobject *self, PyObject *key) { PyObject *v = PyDict_GetItem(self->data, key); - if(!v) return NULL; - + if (!v) + return NULL; Py_INCREF(v); - return v; } @@ -263,10 +263,11 @@ if (here == &self->ring_home) return 0; - /* At this point we know that the ring only contains nodes from - persistent objects, plus our own home node. We know this because - the ring lock is held. We can safely assume the current ring - node is a persistent object now we know it is not the home */ + /* At this point we know that the ring only contains nodes + from persistent objects, plus our own home node. We know + this because the ring lock is held. We can safely assume + the current ring node is a persistent object now we know it + is not the home */ object = object_from_ring(self, here, "scan_gc_items"); if (!object) return -1; @@ -277,12 +278,15 @@ else if (object->state == cPersistent_UPTODATE_STATE) { /* deactivate it. This is the main memory saver. */ - /* Add a placeholder; a dummy node in the ring. We need to - do this to mark our position in the ring. All the other nodes - come from persistent objects, and they are all liable - to be deallocated before "obj._p_changed = None" returns - to this function. This operation is only safe when the - ring lock is held (and it is) */ + /* Add a placeholder; a dummy node in the ring. We need + to do this to mark our position in the ring. It is + possible that the PyObject_SetAttr() call below will + invoke an __setattr__() hook in Python. If it does, + another thread might run; if that thread accesses a + persistent object and moves it to the head of the ring, + it might cause the gc scan to start working from the + head of the list. + */ placeholder.next = here->next; placeholder.prev = here; @@ -315,7 +319,7 @@ static PyObject * lockgc(ccobject *self, int target_size) { - /* We think this is thread-safe because of the GIL, and there's nothing + /* This is thread-safe because of the GIL, and there's nothing * in between checking the ring_lock and acquiring it that calls back * into Python. */ @@ -361,16 +365,23 @@ if (!PyArg_ParseTuple(args, "|i:incrgc", &n)) return NULL; - return lockgc(self,target_size); + return lockgc(self, target_size); } +/* XXX Does it make sense for full_sweep() and reallyfull_sweep() to + empty the cache completely? I agree that it would if dt is 0, but + don't think it should for other times. Perhaps it should just call + incrgc() if dt > 2; the new cache may be efficient enough that + incrgc() would suffice. +*/ + static PyObject * cc_full_sweep(ccobject *self, PyObject *args) { int dt = 0; if (!PyArg_ParseTuple(args, "|i:full_sweep", &dt)) return NULL; - return lockgc(self,0); + return lockgc(self, 0); } static PyObject * @@ -379,7 +390,7 @@ int dt = 0; if (!PyArg_ParseTuple(args, "|i:reallyfull_sweep", &dt)) return NULL; - return lockgc(self,0); + return lockgc(self, 0); } static void @@ -460,22 +471,19 @@ { PyObject *r, *key, *d=0; - UNLESS (PyArg_ParseTuple(args,"O|O", &key, &d)) return NULL; + if (!PyArg_ParseTuple(args, "O|O:get", &key, &d)) + return NULL; - UNLESS (r=(PyObject *)object_from_oid(self, key)) - { - if (d) - { - PyErr_Clear(); - r=d; + r = (PyObject *)object_from_oid(self, key); + if (!r) { + if (d) { + r = d; Py_INCREF(r); - } - else - { + } else { PyErr_SetObject(PyExc_KeyError, key); return NULL; - } - } + } + } return r; } @@ -522,8 +530,9 @@ return NULL; if (self->ring_lock) { - /* When the ring lock is held, we have no way of know which ring nodes - belong to persistent objects, and which a placeholders. */ + /* When the ring lock is held, we have no way of know which + ring nodes belong to persistent objects, and which a + placeholders. */ PyErr_SetString(PyExc_ValueError, ".lru_items() is unavailable during garbage collection"); return NULL; @@ -562,40 +571,25 @@ return l; } -static PyObject * -cc_oid_unreferenced(ccobject *self, PyObject *args) +static int +cc_oid_unreferenced(ccobject *self, PyObject *oid) { - /* This is called by the persistent object deallocation - function when the reference count on a persistent - object reaches zero. We need to fix up our dictionary; - its reference is now dangling because we stole its - reference count. Be careful to not release the global - interpreter lock until this is complete. */ + /* This is called by the persistent object deallocation function + when the reference count on a persistent object reaches + zero. We need to fix up our dictionary; its reference is now + dangling because we stole its reference count. Be careful to + not release the global interpreter lock until this is + complete. */ - PyObject *oid, *v; - if (!PyArg_ParseTuple(args, "O:_oid_unreferenced", &oid)) - return NULL; + PyObject *v; v = PyDict_GetItem(self->data, oid); if (v == NULL) { PyErr_SetObject(PyExc_KeyError, oid); - /* jeremy debug - fprintf(stderr, "oid_unreferenced: key error\n"); - */ - return NULL; - } - - /* jeremy debug - fprintf(stderr, "oid_unreferenced: %X %d %s\n", v, - v->ob_refcnt, v->ob_type->tp_name); - */ - - if (v->ob_refcnt) { - PyErr_Format(PyExc_ValueError, - "object has reference count of %d, should be zero", v->ob_refcnt); - return NULL; + return -1; } + assert(v->ob_refcnt == 0); /* Need to be very hairy here because a dictionary is about to decref an already deleted object. */ @@ -609,40 +603,33 @@ #else Py_INCREF(v); #endif - - if (v->ob_refcnt != 1) { - PyErr_SetString(PyExc_ValueError, - "refcount is not 1 after resurrection"); - return NULL; - } - - /* return the stolen reference */ + /* Incremement the refcount again, because delitem is going to + DECREF it. If it's refcount reached zero again, we'd call back to + the dealloc function that called us. + */ Py_INCREF(v); + /* XXX what if this fails? */ PyDict_DelItem(self->data, oid); if (v->ob_refcnt != 1) { PyErr_SetString(PyExc_ValueError, "refcount is not 1 after removal from dict"); - return NULL; + return -1; } /* undo the temporary resurrection */ #ifdef Py_TRACE_REFS _Py_ForgetReference(v); #else - v->ob_refcnt=0; + v->ob_refcnt = 0; #endif - Py_INCREF(Py_None); - return Py_None; + return 0; } static struct PyMethodDef cc_methods[] = { - {"_oid_unreferenced", (PyCFunction)cc_oid_unreferenced, METH_VARARGS, - NULL - }, {"lru_items", (PyCFunction)cc_lru_items, METH_VARARGS, "List (oid, object) pairs from the lru list, as 2-tuples.\n" }, @@ -1103,10 +1090,17 @@ initcPickleCache(void) { PyObject *m, *d; + cPersistenceCAPIstruct *capi; + + Cctype.ob_type = &PyType_Type; - Cctype.ob_type=&PyType_Type; + if (!ExtensionClassImported) + return; - UNLESS(ExtensionClassImported) return; + capi = (cPersistenceCAPIstruct *)PyCObject_Import("cPersistence", "CAPI"); + if (!capi) + return; + capi->percachedel = (percachedelfunc)cc_oid_unreferenced; m = Py_InitModule4("cPickleCache", cCM_methods, cPickleCache_doc_string, (PyObject*)NULL, PYTHON_API_VERSION); @@ -1118,11 +1112,11 @@ d = PyModule_GetDict(m); - PyDict_SetItemString(d,"cache_variant",PyString_FromString("stiff/c")); + PyDict_SetItemString(d, "cache_variant", PyString_FromString("stiff/c")); #ifdef MUCH_RING_CHECKING - PyDict_SetItemString(d,"MUCH_RING_CHECKING",PyInt_FromLong(1)); + PyDict_SetItemString(d, "MUCH_RING_CHECKING", PyInt_FromLong(1)); #else - PyDict_SetItemString(d,"MUCH_RING_CHECKING",PyInt_FromLong(0)); + PyDict_SetItemString(d, "MUCH_RING_CHECKING", PyInt_FromLong(0)); #endif } From srichter@cbu.edu Fri Apr 5 01:26:16 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 20:26:16 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/LineReceiver Zope3/lib/python/Zope/Server/LineReceiver - New directory Message-ID: <200204050126.g351QGw17678@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/LineReceiver In directory cvs.zope.org:/tmp/cvs-serv17672/LineReceiver Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/Server/LineReceiver added to the repository --> Using per-directory sticky tag `Zope3-Server-Branch' === Added directory Zope3/lib/python/Zope/Server/LineReceiver === From srichter@cbu.edu Fri Apr 5 01:26:58 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 20:26:58 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/LineReceiver/tests Zope3/lib/python/Zope/Server/LineReceiver/tests - New directory Message-ID: <200204050126.g351Qw817689@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/LineReceiver/tests In directory cvs.zope.org:/tmp/cvs-serv17683/tests Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/Server/LineReceiver/tests added to the repository --> Using per-directory sticky tag `Zope3-Server-Branch' === Added directory Zope3/lib/python/Zope/Server/LineReceiver/tests === From srichter@cbu.edu Fri Apr 5 01:36:24 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 20:36:24 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/LineReceiver/tests - __init__.py:1.1.2.1 Message-ID: <200204050136.g351aOS20161@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/LineReceiver/tests In directory cvs.zope.org:/tmp/cvs-serv20143/LineReceiver/tests Added Files: Tag: Zope3-Server-Branch __init__.py Log Message: This is a first take on providing a generic framework for comamnd line protocols. They share quiet a bit of code, so I think it is worthwhile doing that. I also fixed the FTP server to work with this. === Added File Zope3/lib/python/Zope/Server/LineReceiver/tests/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.2.1 2002/04/05 01:36:23 srichter Exp $ """ From srichter@cbu.edu Fri Apr 5 01:36:24 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 20:36:24 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/LineReceiver - LineCommandParser.py:1.1.2.1 LineServerChannel.py:1.1.2.1 LineTask.py:1.1.2.1 __init__.py:1.1.2.1 Message-ID: <200204050136.g351aOi20160@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/LineReceiver In directory cvs.zope.org:/tmp/cvs-serv20143/LineReceiver Added Files: Tag: Zope3-Server-Branch LineCommandParser.py LineServerChannel.py LineTask.py __init__.py Log Message: This is a first take on providing a generic framework for comamnd line protocols. They share quiet a bit of code, so I think it is worthwhile doing that. I also fixed the FTP server to work with this. === Added File Zope3/lib/python/Zope/Server/LineReceiver/LineCommandParser.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: LineCommandParser.py,v 1.1.2.1 2002/04/05 01:36:23 srichter Exp $ """ from Zope.Server.IStreamConsumer import IStreamConsumer class LineCommandParser: """Line Command parser. Arguments are left alone for now.""" __implements__ = IStreamConsumer # See Zope.Server.IStreamConsumer.IStreamConsumer completed = 0 inbuf = '' cmd = '' args = '' empty = 0 max_line_length = 1024 # Not a hard limit def __init__(self, adj): """ adj is an Adjustments object. """ self.adj = adj ############################################################ # Implementation methods for interface # Zope.Server.IStreamConsumer def received(self, data): 'See Zope.Server.IStreamConsumer.IStreamConsumer' if self.completed: return 0 # Can't consume any more. pos = data.find('\n') datalen = len(data) if pos < 0: self.inbuf = self.inbuf + data if len(self.inbuf) > self.max_line_length: # Don't accept any more. self.completed = 1 return datalen else: # Line finished. s = data[:pos + 1] self.inbuf = self.inbuf + s self.completed = 1 line = self.inbuf.strip() self.parseLine(line) return len(s) # ############################################################ def parseLine(self, line): parts = line.split(' ', 1) if len(parts) == 2: self.cmd, self.args = parts else: self.cmd = parts[0] === Added File Zope3/lib/python/Zope/Server/LineReceiver/LineServerChannel.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: LineServerChannel.py,v 1.1.2.1 2002/04/05 01:36:23 srichter Exp $ """ import os import stat import socket import time from Zope.Server.ServerChannelBase import ServerChannelBase from LineCommandParser import LineCommandParser from LineTask import LineTask class LineServerChannel(ServerChannelBase): """The Line Server Channel represents a connection to a particular client. We can therefore store information here.""" __implements__ = ServerChannelBase.__implements__ # Wrapper class that is used to execute a command in a different thread task_class = LineTask # Class that is being initialized to parse the input parser_class = LineCommandParser # List of commands that are always available special_commands = ('cmd_quit') # Commands that are run in a separate thread thread_commands = () # Define the authentication status of the channel. Note that only the # "special commands" can be executed without having authenticated. authenticated = 0 # Define the reply code for non-authenticated responses not_auth_reply = (530, 0) # Define the reply code for an unrecognized command unknown_reply = (500, 0) # Define the status messages status_messages = { 500: ("'%s': command not understood.",), 530: ('Please log in with USER and PASS',) } def process_request(self, command): """Processes a command. Some commands use an alternate thread. """ assert isinstance(command, LineCommandParser) cmd = command.cmd method = 'cmd_' + cmd.lower() if ( not self.authenticated and method not in self.special_commands): # The user is not logged in, therefore don't allow anything self.reply(self.not_auth_reply[0], self.not_auth_reply[1]) elif method in self.thread_commands: # Process in another thread. return self.task_class(self, command, method) elif hasattr(self, method): getattr(self, method)(command.args) else: self.reply(self.unknown_reply[0], self.unknown_reply[1], cmd.upper()) def reply(self, code, pos=0, args=(), flush=1): """ """ try: msg = self.status_messages[code][pos] %args except: msg = 'The server created a bad response type (code %i).' %code code = 500 if msg.startswith('-'): fill = '' else: fill = ' ' self.write('%i%s%s\r\n' %(code, fill, msg)) if flush: self.flush(0) # XXX: Some logging should go on here. === Added File Zope3/lib/python/Zope/Server/LineReceiver/LineTask.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: LineTask.py,v 1.1.2.1 2002/04/05 01:36:23 srichter Exp $ """ import socket import time from Zope.Server.ITask import ITask class LineTask: """This is a generic task that can be used with command line protocols to handle commands in a separate thread. """ __implements__ = ITask def __init__(self, channel, command, m_name): self.channel = channel self.m_name = m_name self.args = command.args self.close_on_finish = 0 ############################################################ # Implementation methods for interface # Zope.Server.ITask def service(self): """Called to execute the task. """ try: try: self.start() getattr(self.channel, self.m_name)(self.args) self.finish() except socket.error: self.close_on_finish = 1 if self.channel.adj.log_socket_errors: raise finally: self.channel.end_task(self.close_on_finish) def cancel(self): 'See Zope.Server.ITask.ITask' self.channel.close_when_done() def defer(self): 'See Zope.Server.ITask.ITask' pass # ############################################################ def start(self): now = time.time() self.start_time = now def finish(self): hit_log = self.channel.server.hit_log if hit_log is not None: hit_log.log(self) === Added File Zope3/lib/python/Zope/Server/LineReceiver/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.2.1 2002/04/05 01:36:23 srichter Exp $ """ From srichter@cbu.edu Fri Apr 5 01:36:35 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 4 Apr 2002 20:36:35 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - FTPServer.py:1.1.2.6 FTPServerChannel.py:1.1.2.11 FTPCommandParser.py:NONE FTPTask.py:NONE Message-ID: <200204050136.g351aZl20174@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv20145/FTP Modified Files: Tag: Zope3-Server-Branch FTPServer.py FTPServerChannel.py Removed Files: Tag: Zope3-Server-Branch FTPCommandParser.py FTPTask.py Log Message: This is a first take on providing a generic framework for comamnd line protocols. They share quiet a bit of code, so I think it is worthwhile doing that. I also fixed the FTP server to work with this. === Zope3/lib/python/Zope/Server/FTP/FTPServer.py 1.1.2.5 => 1.1.2.6 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" -import asyncore -from FTPServerChannel import FTPServerChannel -from Zope.Server.ServerBase import ServerBase -from Zope.Server.Counter import Counter - -from Zope.Server.VFS.UnixFileSystem import UnixFileSystem -from Zope.Server.Authentication.DictionaryAuthentication import \ - DictionaryAuthentication - - -class FTPServer(ServerBase): - """Generic FTP Server""" - - filesystem = UnixFileSystem('/') - auth_source = DictionaryAuthentication({'foo': 'bar'}) - - channel_class = FTPServerChannel - SERVER_IDENT = 'Zope.Server.FTPServer' - - - def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1, - hit_log=None, verbose=0, socket_map=None): - super(FTPServer, self).__init__(ip, port, task_dispatcher, - adj, start, hit_log, - verbose, socket_map) - - # statistics - self.total_sessions = Counter() - self.closed_sessions = Counter() - self.total_files_out = Counter() - self.total_files_in = Counter() - self.total_bytes_out = Counter() - self.total_bytes_in = Counter() - self.total_exceptions = Counter() - - -if __name__ == '__main__': - from Zope.Server.TaskThreads import ThreadedTaskDispatcher - td = ThreadedTaskDispatcher() - td.setThreadCount(4) - FTPServer('', 8021, task_dispatcher=td) - try: - while 1: - asyncore.poll(5) - print 'active channels:', FTPServerChannel.active_channels - except KeyboardInterrupt: - print 'shutting down...' - td.shutdown() +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" +import asyncore +from FTPServerChannel import FTPServerChannel +from Zope.Server.ServerBase import ServerBase +from Zope.Server.Counter import Counter + +from Zope.Server.VFS.UnixFileSystem import UnixFileSystem +from Zope.Server.Authentication.DictionaryAuthentication import \ + DictionaryAuthentication + + +class FTPServer(ServerBase): + """Generic FTP Server""" + + filesystem = UnixFileSystem('/') + auth_source = DictionaryAuthentication({'foo': 'bar'}) + + channel_class = FTPServerChannel + SERVER_IDENT = 'Zope.Server.FTPServer' + + + def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1, + hit_log=None, verbose=0, socket_map=None): + super(FTPServer, self).__init__(ip, port, task_dispatcher, + adj, start, hit_log, + verbose, socket_map) + + # statistics + self.total_sessions = Counter() + self.closed_sessions = Counter() + self.total_files_out = Counter() + self.total_files_in = Counter() + self.total_bytes_out = Counter() + self.total_bytes_in = Counter() + self.total_exceptions = Counter() + + +if __name__ == '__main__': + from Zope.Server.TaskThreads import ThreadedTaskDispatcher + td = ThreadedTaskDispatcher() + td.setThreadCount(4) + FTPServer('', 8021, task_dispatcher=td) + try: + while 1: + asyncore.poll(5) + print 'active channels:', FTPServerChannel.active_channels + except KeyboardInterrupt: + print 'shutting down...' + td.shutdown() === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.10 => 1.1.2.11 === import time -from Zope.Server.ServerChannelBase import ServerChannelBase +from Zope.Server.LineReceiver.LineServerChannel import LineServerChannel from FTPStatusMessages import status_msgs -from FTPCommandParser import FTPCommandParser -from FTPTask import FTPTask from FileProducer import FileProducer from IFTPCommandHandler import IFTPCommandHandler @@ -33,24 +31,34 @@ from XmitChannel import XmitChannel -# These are the commands that are accessing the filesystem. -# Since this could be also potentially a longer process, these commands -# are also the ones that are executed in a different thread. -fs_access_cmds = ('cmd_appe', 'cmd_cdup', 'cmd_cwd', 'cmd_dele', 'cmd_list', - 'cmd_nlst', 'cmd_mdtm', 'cmd_mkd', 'cmd_pass', 'cmd_retr', - 'cmd_rmd', 'cmd_rnfr', 'cmd_rnto', 'cmd_size', 'cmd_stor', - 'cmd_stru') - - -class FTPServerChannel(ServerChannelBase): +class FTPServerChannel(LineServerChannel): """The FTP Server Channel represents a connection to a particular client. We can therefore store information here.""" - __implements__ = IFTPCommandHandler + __implements__ = LineServerChannel.__implements__, IFTPCommandHandler + + + # List of commands that are always available + special_commands = ('cmd_quit', 'cmd_user', 'cmd_pass') + + # These are the commands that are accessing the filesystem. + # Since this could be also potentially a longer process, these commands + # are also the ones that are executed in a different thread. + thread_commands = ('cmd_appe', 'cmd_cdup', 'cmd_cwd', 'cmd_dele', + 'cmd_list', 'cmd_nlst', 'cmd_mdtm', 'cmd_mkd', + 'cmd_pass', 'cmd_retr', 'cmd_rmd', 'cmd_rnfr', + 'cmd_rnto', 'cmd_size', 'cmd_stor', 'cmd_stru') + + # Define the reply code for non-authenticated responses + not_auth_reply = (530, 1) - task_class = FTPTask - parser_class = FTPCommandParser + # Define the reply code for an unrecognized command + unknown_reply = (500, 0) + # Define the status messages + status_messages = status_msgs + + # Define the type of directory listing this server is returning system = ('UNIX', 'L8') # comply with (possibly troublesome) RFC959 requirements @@ -61,20 +69,9 @@ restart_position = 0 + type_map = {'a':'ASCII', 'i':'Binary', 'e':'EBCDIC', 'l':'Binary'} - type_map = { - 'a':'ASCII', - 'i':'Binary', - 'e':'EBCDIC', - 'l':'Binary' - } - - type_mode_map = { - 'a':'t', - 'i':'b', - 'e':'b', - 'l':'b' - } + type_mode_map = {'a':'t', 'i':'b', 'e':'b', 'l':'b'} def __init__(self, server, conn, addr, adj=None, socket_map=None): @@ -96,35 +93,10 @@ self.username = '' self.password = '' - self.authenticated = 0 self.reply(220, 0, self.server.server_name) - def process_request(self, command): - """Processes an FTP command. - - Some commands use an alternate thread. - """ - assert isinstance(command, FTPCommandParser) - cmd = command.cmd - method = 'cmd_' + cmd.lower() - if ( not self.authenticated and - method not in ('cmd_user', 'cmd_pass', 'cmd_quit')): - # The user is not logged in, therefore don't allow anything - self.reply(530, 1) - - elif method in fs_access_cmds: - # Process in another thread. - return self.task_class(self, command, method) - - elif hasattr(self, method): - getattr(self, method)(command.args) - - else: - self.reply(500, 0, (cmd.upper())) - - ############################################################ # Implementation methods for interface # Zope.Server.FTP.IFTPCommandHandler @@ -573,25 +545,3 @@ self.reply(425) self.client_dc = cdc - - - def reply(self, code, pos=0, args=(), flush=1): - """ """ - try: - msg = status_msgs[code][pos] %args - except: - # XXX: Somehow handle the nonexisting response. - msg = 'The server created a bad response type (code %i).' %code - code = 500 - - if msg.startswith('-'): - fill = '' - else: - fill = ' ' - - self.write('%i%s%s\r\n' %(code, fill, msg)) - - if flush: - self.flush(0) - - # XXX: Some logging should go on here. === Removed File Zope3/lib/python/Zope/Server/FTP/FTPCommandParser.py === === Removed File Zope3/lib/python/Zope/Server/FTP/FTPTask.py === From tdickenson@geminidataloggers.com Fri Apr 5 11:13:11 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Fri, 5 Apr 2002 06:13:11 -0500 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/ZCatalog - ZCatalog.py:1.106 Message-ID: <200204051113.g35BDBs20887@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/ZCatalog In directory cvs.zope.org:/tmp/cvs-serv20880 Modified Files: ZCatalog.py Log Message: No need to use a full sweep now. the incremental collector is sufficiently effective at keeping memory usage in check, and does not have the severe performance implications === Zope/lib/python/Products/ZCatalog/ZCatalog.py 1.105 => 1.106 === if self._v_total > self.threshold: get_transaction().commit(1) - self._p_jar.cacheFullSweep(3) + self._p_jar.cacheGC() self._v_total = 0 def uncatalog_object(self, uid): From shane@cvs.zope.org Fri Apr 5 15:01:05 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 5 Apr 2002 10:01:05 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/LineReceiver - LineCommandParser.py:1.1.2.2 LineServerChannel.py:1.1.2.2 LineTask.py:1.1.2.2 __init__.py:1.1.2.2 Message-ID: <200204051501.g35F15d17498@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/LineReceiver In directory cvs.zope.org:/tmp/cvs-serv17395/LineReceiver Modified Files: Tag: Zope3-Server-Branch LineCommandParser.py LineServerChannel.py LineTask.py __init__.py Log Message: Fixed line endings again (I hope no one minds me doing this. I have a tool that does it automatically :-) === Zope3/lib/python/Zope/Server/LineReceiver/LineCommandParser.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -from Zope.Server.IStreamConsumer import IStreamConsumer - - -class LineCommandParser: - """Line Command parser. Arguments are left alone for now.""" - - __implements__ = IStreamConsumer - - # See Zope.Server.IStreamConsumer.IStreamConsumer - completed = 0 - inbuf = '' - cmd = '' - args = '' - empty = 0 - - max_line_length = 1024 # Not a hard limit - - - def __init__(self, adj): - """ - adj is an Adjustments object. - """ - self.adj = adj - - - ############################################################ - # Implementation methods for interface - # Zope.Server.IStreamConsumer - - def received(self, data): - 'See Zope.Server.IStreamConsumer.IStreamConsumer' - if self.completed: - return 0 # Can't consume any more. - pos = data.find('\n') - datalen = len(data) - if pos < 0: - self.inbuf = self.inbuf + data - if len(self.inbuf) > self.max_line_length: - # Don't accept any more. - self.completed = 1 - return datalen - else: - # Line finished. - s = data[:pos + 1] - self.inbuf = self.inbuf + s - self.completed = 1 - line = self.inbuf.strip() - self.parseLine(line) - return len(s) - - # - ############################################################ - - - def parseLine(self, line): - parts = line.split(' ', 1) - if len(parts) == 2: - self.cmd, self.args = parts - else: - self.cmd = parts[0] +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +from Zope.Server.IStreamConsumer import IStreamConsumer + + +class LineCommandParser: + """Line Command parser. Arguments are left alone for now.""" + + __implements__ = IStreamConsumer + + # See Zope.Server.IStreamConsumer.IStreamConsumer + completed = 0 + inbuf = '' + cmd = '' + args = '' + empty = 0 + + max_line_length = 1024 # Not a hard limit + + + def __init__(self, adj): + """ + adj is an Adjustments object. + """ + self.adj = adj + + + ############################################################ + # Implementation methods for interface + # Zope.Server.IStreamConsumer + + def received(self, data): + 'See Zope.Server.IStreamConsumer.IStreamConsumer' + if self.completed: + return 0 # Can't consume any more. + pos = data.find('\n') + datalen = len(data) + if pos < 0: + self.inbuf = self.inbuf + data + if len(self.inbuf) > self.max_line_length: + # Don't accept any more. + self.completed = 1 + return datalen + else: + # Line finished. + s = data[:pos + 1] + self.inbuf = self.inbuf + s + self.completed = 1 + line = self.inbuf.strip() + self.parseLine(line) + return len(s) + + # + ############################################################ + + + def parseLine(self, line): + parts = line.split(' ', 1) + if len(parts) == 2: + self.cmd, self.args = parts + else: + self.cmd = parts[0] === Zope3/lib/python/Zope/Server/LineReceiver/LineServerChannel.py 1.1.2.1 => 1.1.2.2 === __implements__ = ServerChannelBase.__implements__ - # Wrapper class that is used to execute a command in a different thread + # Wrapper class that is used to execute a command in a different thread task_class = LineTask # Class that is being initialized to parse the input parser_class = LineCommandParser - # List of commands that are always available + # List of commands that are always available special_commands = ('cmd_quit') # Commands that are run in a separate thread === Zope3/lib/python/Zope/Server/LineReceiver/LineTask.py 1.1.2.1 => 1.1.2.2 === class LineTask: """This is a generic task that can be used with command line - protocols to handle commands in a separate thread. + protocols to handle commands in a separate thread. """ __implements__ = ITask === Zope3/lib/python/Zope/Server/LineReceiver/__init__.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" From shane@cvs.zope.org Fri Apr 5 15:01:05 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 5 Apr 2002 10:01:05 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/LineReceiver/tests - __init__.py:1.1.2.2 Message-ID: <200204051501.g35F15e17499@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/LineReceiver/tests In directory cvs.zope.org:/tmp/cvs-serv17395/LineReceiver/tests Modified Files: Tag: Zope3-Server-Branch __init__.py Log Message: Fixed line endings again (I hope no one minds me doing this. I have a tool that does it automatically :-) === Zope3/lib/python/Zope/Server/LineReceiver/tests/__init__.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" From shane@cvs.zope.org Fri Apr 5 15:01:35 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 5 Apr 2002 10:01:35 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - FTPServer.py:1.1.2.7 FTPServerChannel.py:1.1.2.12 Message-ID: <200204051501.g35F1Zt17505@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv17395/FTP Modified Files: Tag: Zope3-Server-Branch FTPServer.py FTPServerChannel.py Log Message: Fixed line endings again (I hope no one minds me doing this. I have a tool that does it automatically :-) === Zope3/lib/python/Zope/Server/FTP/FTPServer.py 1.1.2.6 => 1.1.2.7 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" -import asyncore -from FTPServerChannel import FTPServerChannel -from Zope.Server.ServerBase import ServerBase -from Zope.Server.Counter import Counter - -from Zope.Server.VFS.UnixFileSystem import UnixFileSystem -from Zope.Server.Authentication.DictionaryAuthentication import \ - DictionaryAuthentication - - -class FTPServer(ServerBase): - """Generic FTP Server""" - - filesystem = UnixFileSystem('/') - auth_source = DictionaryAuthentication({'foo': 'bar'}) - - channel_class = FTPServerChannel - SERVER_IDENT = 'Zope.Server.FTPServer' - - - def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1, - hit_log=None, verbose=0, socket_map=None): - super(FTPServer, self).__init__(ip, port, task_dispatcher, - adj, start, hit_log, - verbose, socket_map) - - # statistics - self.total_sessions = Counter() - self.closed_sessions = Counter() - self.total_files_out = Counter() - self.total_files_in = Counter() - self.total_bytes_out = Counter() - self.total_bytes_in = Counter() - self.total_exceptions = Counter() - - -if __name__ == '__main__': - from Zope.Server.TaskThreads import ThreadedTaskDispatcher - td = ThreadedTaskDispatcher() - td.setThreadCount(4) - FTPServer('', 8021, task_dispatcher=td) - try: - while 1: - asyncore.poll(5) - print 'active channels:', FTPServerChannel.active_channels - except KeyboardInterrupt: - print 'shutting down...' - td.shutdown() +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" +import asyncore +from FTPServerChannel import FTPServerChannel +from Zope.Server.ServerBase import ServerBase +from Zope.Server.Counter import Counter + +from Zope.Server.VFS.UnixFileSystem import UnixFileSystem +from Zope.Server.Authentication.DictionaryAuthentication import \ + DictionaryAuthentication + + +class FTPServer(ServerBase): + """Generic FTP Server""" + + filesystem = UnixFileSystem('/') + auth_source = DictionaryAuthentication({'foo': 'bar'}) + + channel_class = FTPServerChannel + SERVER_IDENT = 'Zope.Server.FTPServer' + + + def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1, + hit_log=None, verbose=0, socket_map=None): + super(FTPServer, self).__init__(ip, port, task_dispatcher, + adj, start, hit_log, + verbose, socket_map) + + # statistics + self.total_sessions = Counter() + self.closed_sessions = Counter() + self.total_files_out = Counter() + self.total_files_in = Counter() + self.total_bytes_out = Counter() + self.total_bytes_in = Counter() + self.total_exceptions = Counter() + + +if __name__ == '__main__': + from Zope.Server.TaskThreads import ThreadedTaskDispatcher + td = ThreadedTaskDispatcher() + td.setThreadCount(4) + FTPServer('', 8021, task_dispatcher=td) + try: + while 1: + asyncore.poll(5) + print 'active channels:', FTPServerChannel.active_channels + except KeyboardInterrupt: + print 'shutting down...' + td.shutdown() === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.11 => 1.1.2.12 === - # List of commands that are always available + # List of commands that are always available special_commands = ('cmd_quit', 'cmd_user', 'cmd_pass') # These are the commands that are accessing the filesystem. From srichter@cbu.edu Fri Apr 5 15:18:48 2002 From: srichter@cbu.edu (Stephan Richter) Date: Fri, 5 Apr 2002 10:18:48 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/LineReceiver - LineServerChannel.py:1.1.2.3 Message-ID: <200204051518.g35FImI22153@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/LineReceiver In directory cvs.zope.org:/tmp/cvs-serv20940/LineReceiver Modified Files: Tag: Zope3-Server-Branch LineServerChannel.py Log Message: Changed Status messages mechanism. === Zope3/lib/python/Zope/Server/LineReceiver/LineServerChannel.py 1.1.2.2 => 1.1.2.3 === # Define the reply code for non-authenticated responses - not_auth_reply = (530, 0) + not_auth_reply = 'LOGIN_REQUIRED' # Define the reply code for an unrecognized command - unknown_reply = (500, 0) + unknown_reply = 'CMD_UNKNOWN' # Define the status messages status_messages = { - 500: ("'%s': command not understood.",), - 530: ('Please log in with USER and PASS',) + 'CMD_UNKNOWN' : "500 '%s': command not understood.", + 'LOGIN_REQUIRED' : '530 Please log in with USER and PASS', } @@ -71,7 +71,7 @@ method = 'cmd_' + cmd.lower() if ( not self.authenticated and method not in self.special_commands): # The user is not logged in, therefore don't allow anything - self.reply(self.not_auth_reply[0], self.not_auth_reply[1]) + self.reply(self.not_auth_reply) elif method in self.thread_commands: # Process in another thread. @@ -81,24 +81,17 @@ getattr(self, method)(command.args) else: - self.reply(self.unknown_reply[0], - self.unknown_reply[1], cmd.upper()) + self.reply(self.unknown_reply, cmd.upper()) - def reply(self, code, pos=0, args=(), flush=1): + def reply(self, code, args=(), flush=1): """ """ try: - msg = self.status_messages[code][pos] %args + msg = self.status_messages[code] %args except: - msg = 'The server created a bad response type (code %i).' %code - code = 500 + msg = '500 Unknown Response: %i.' %code - if msg.startswith('-'): - fill = '' - else: - fill = ' ' - - self.write('%i%s%s\r\n' %(code, fill, msg)) + self.write('%s\r\n' %msg) if flush: self.flush(0) From srichter@cbu.edu Fri Apr 5 15:18:48 2002 From: srichter@cbu.edu (Stephan Richter) Date: Fri, 5 Apr 2002 10:18:48 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - FTPServerChannel.py:1.1.2.13 FTPStatusMessages.py:1.1.2.6 RecvChannel.py:1.1.2.4 XmitChannel.py:1.1.2.3 Message-ID: <200204051518.g35FImf22152@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv20940/FTP Modified Files: Tag: Zope3-Server-Branch FTPServerChannel.py FTPStatusMessages.py RecvChannel.py XmitChannel.py Log Message: Changed Status messages mechanism. === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.12 => 1.1.2.13 === 'cmd_rnto', 'cmd_size', 'cmd_stor', 'cmd_stru') - # Define the reply code for non-authenticated responses - not_auth_reply = (530, 1) - - # Define the reply code for an unrecognized command - unknown_reply = (500, 0) - # Define the status messages status_messages = status_msgs @@ -94,7 +88,7 @@ self.username = '' self.password = '' - self.reply(220, 0, self.server.server_name) + self.reply('SERVER_READY', self.server.server_name) ############################################################ @@ -105,7 +99,7 @@ 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' if self.client_dc: self.client_dc.close() - self.reply(226, 0, 'ABOR') + self.reply('TRANS_SUCCESS', 'ABOR') def cmd_appe (self, args): @@ -118,9 +112,9 @@ path = self._generatePath('../') if self.server.filesystem.exists(path): self.cwd = path - self.reply(250, 0, 'CDUP') + self.reply('SUCCESS_250', 'CDUP') else: - self.reply(550, 2, path) + self.reply('ERR_NO_FILE', path) def cmd_cwd(self, args): @@ -128,32 +122,32 @@ path = self._generatePath(args) if self.server.filesystem.exists(path): self.cwd = path - self.reply(250, 0, 'CWD') + self.reply('SUCCESS_250', 'CWD') else: - self.reply(550, 1, path) + self.reply('ERR_NO_DIR', path) def cmd_dele(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' if not args: - self.reply(500, 0, 'DELE') + self.reply('CMD_UNKNOWN', 'DELE') else: path = self._generatePath(args) try: self.server.filesystem.unlink(path) - self.reply(250, 0, 'DELE') + self.reply('SUCCESS_250', 'DELE') except: - self.reply(550, 6) + self.reply('ERR_DELETE_FILE') else: - self.reply(550, 2, file) + self.reply('NO_FILE', file) def cmd_help(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' - self.reply(214, flush=0) + self.reply('HELP_START') self.write('Help goes here somewhen.\r\n') - self.reply(214, 1) + self.reply('HELP_END') def cmd_list(self, args): @@ -162,10 +156,10 @@ try: producer = self.getDirectoryList(args, 1) except os.error, why: - self.reply(550, 0, repr(why)) + self.reply('ERR_NO_LIST', repr(why)) return - self.reply(150, 0, self.type_map[self.transfer_mode]) + self.reply('OPEN_DATA_CONN', self.type_map[self.transfer_mode]) self.createXmitChannel() self.client_dc.push_with_producer(producer) self.client_dc.close_when_done() @@ -175,35 +169,35 @@ 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' path = self._generatePath(args) if not self.server.filesystem.isfile(path): - self.reply(550, 3, path) + self.reply('ERR_IS_NOT_FILE', path) else: mtime = time.gmtime( self.server.filesystem.stat(path)[stat.ST_MTIME] ) - self.reply(213, 0, (mtime[0], mtime[1], mtime[2], - mtime[3], mtime[4], mtime[5]) ) + self.reply('FILE_DATE', (mtime[0], mtime[1], mtime[2], + mtime[3], mtime[4], mtime[5]) ) def cmd_mkd(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' if not args: - self.reply(500, 0, 'MKD') + self.reply('CMD_UNKNOWN', 'MKD') else: path = self._generatePath(args) try: self.server.filesystem.mkdir(path) - self.reply(257, 0, 'MKD') + self.reply('SUCCESS_257', 'MKD') except: - self.reply (550, 5) + self.reply('ERR_CREATE_DIR') def cmd_mode(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' if len(args) == 1 and args in 'sS': - self.reply(200, 3) + self.reply('MODE_OK') else: - self.reply(502) + self.reply('MODE_UNKNOWN') def cmd_nlst(self, args): @@ -216,18 +210,18 @@ try: producer = self.getDirectoryList(args, 0) except os.error, why: - self.reply( 550, 0, (repr(why),) ) + self.reply('ERR_NO_LIST', repr(why)) return self.createXmitChannel() self.client_dc.push_with_producer(producer) self.client_dc.close_when_done() - self.reply(150, 0, (self.type_map[self.transfer_mode],)) + self.reply('OPEN_DATA_CONN', (self.type_map[self.transfer_mode],)) def cmd_noop(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' - self.reply(200, 0, ('NOOP')) + self.reply('SUCCESS_200', 'NOOP') def cmd_pass(self, args): @@ -237,9 +231,9 @@ self.authenticated, message = auth.authenticate(self.username, self.password) if self.authenticated: - self.reply(230) + self.reply('LOGIN_SUCCESS') else: - self.reply(530, 2) + self.reply('LOGIN_MISMATCH') self.close_when_done() @@ -249,9 +243,9 @@ self.client_dc = None port = pc.addr[1] ip_addr = pc.control_channel.getsockname()[0] - self.reply(227, args=( ','.join(ip_addr.split('.')), - port/256, - port%256 ) ) + self.reply('PASV_MODE_MSG', (','.join(ip_addr.split('.')), + port/256, + port%256 ) ) def cmd_port(self, args): @@ -266,27 +260,26 @@ # XXX: we should (optionally) verify that the # ip number belongs to the client. [wu-ftpd does this?] self.client_addr = (ip, port) - self.reply(200, 0, 'PORT') + self.reply('SUCCESS_200', 'PORT') except: - return self.reply(550, 0, 'PORT') - + return self.reply('CMD_UNKNOWN', 'PORT') def cmd_pwd(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' - self.reply(257, 0, self.cwd) + self.reply('SUCCESS_257', self.cwd) def cmd_quit(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' - self.reply(221) + self.reply('GOODBYE') self.close_when_done() def cmd_retr(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' if not args: - self.reply(550, 0, 'RETR') + self.reply('CMD_UNKNOWN', 'RETR') else: path = self._generatePath(args) @@ -299,9 +292,10 @@ mode = 'r'+self.type_mode_map[self.transfer_mode] fd = self.server.filesystem.open(path, mode) except IOError, why: - self.reply(553, 0, repre(why)) + self.reply('ERR_OPEN_READ', repre(why)) return - self.reply(150, 1, (self.type_map[self.transfer_mode], path) ) + self.reply('OPEN_CONN', + (self.type_map[self.transfer_mode], path) ) self.createXmitChannel() if self.restart_position: @@ -325,22 +319,22 @@ try: pos = int(args) except ValueError: - self.reply(500, 0, 'REST') + self.reply('CMD_UNKNWON', 'REST') self.restart_position = pos - self.reply(350, 0, pos) + self.reply('RESTART_TRANSFER', pos) def cmd_rmd(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' if not args: - self.reply(500, 0, 'RMD') + self.reply('CMD_UNKNOWN', 'RMD') else: path = self._generatePath(args) try: self.server.filesystem.rmdir(path) - self.reply(250, 0, 'RMD') + self.reply('SUCCESS_250', 'RMD') except: - self.reply(550, 7) + self.reply('ERR_DELETE_DIR') def cmd_rnfr(self, args): @@ -348,21 +342,21 @@ path = self._generatePath(args) if self.server.filesystem.exists(path): self._rnfr = path - self.reply(350, 1) + self.reply('READY_FOR_DEST') else: - self.reply(550, 2, path) + self.reply('ERR_NO_FILE', path) def cmd_rnto(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' path = self._generatePath(args) if self._rnfr is None: - self.reply(560, 1) + self.reply('ERR_RENAME') try: self.server.filesystem.rename(self._rnfr, path) - self.reply(250, 0, 'RNTO') + self.reply('SUCCESS_250', 'RNTO') except: - self.reply(560, 0, (self._rnfr, rnto)) + self.reply('ERR_RENAME', (self._rnfr, rnto)) self._rnfr = None @@ -370,44 +364,44 @@ 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' path = self._generatePath(args) if not self.server.filesystem.isfile(path): - self.reply(550, 2, path) + self.reply('ERR_NO_FILE', path) else: - self.reply(213, 1, + self.reply('FILE_SIZE', self.server.filesystem.stat(path)[stat.ST_SIZE]) def cmd_stor(self, args, mode='wb'): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' if not args: - self.reply(550, 0, 'STOR') + self.reply('CMD_UNKNOWN', 'STOR') else: path = self._generatePath(args) if self.restart_position: restart_position = 0 - self.reply(553, 2) + self.reply('ERR_RESTART_STOR') return # todo: handle that type flag try: fd = self.server.filesystem.open(args, mode) except IOError, why: - self.reply(553, 1, repr(why)) + self.reply('ERR_OPEN_WRITE', repr(why)) return - self.reply(150, 1, (self.type_map[self.transfer_mode], file) ) + self.reply('OPEN_CONN', (self.type_map[self.transfer_mode], file) ) self.createRecvChannel(fd) def cmd_stru(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' if len(args) == 1 and args in 'fF': - self.reply(200, 2) + self.reply('STRU_OK') else: - self.reply(504, 1) + self.reply('STRU_UNKNOWN') def cmd_syst(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' - self.reply(215, 0, self.system) + self.reply('SERVER_TYPE', self.system) def cmd_type(self, args): @@ -418,24 +412,24 @@ # no support for EBCDIC # if t not in ['a','e','i','l']: if t not in ['a','i','l']: - self.reply(500, 0, args=('TYPE',)) + self.reply('CMD_UNKNOWN', 'TYPE') elif t == 'l' and (len(args) > 2 and args[2] != '8'): - self.reply(504, 0) + self.reply('WRONG_BYTE_SIZE') else: if t == 'a': self.transfer_mode = t - self.reply(200, 1, self.type_map[t]) + self.reply('TYPE_SET_OK', self.type_map[t]) def cmd_user(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' if len(args) > 1: self.username = args - self.reply(331) # Or whatever the code should be + self.reply('PASS_REQUIRED') else: - self.reply(500, 0, ('USER')) + self.reply('CMD_UNKNOWN', 'USER') # ############################################################ === Zope3/lib/python/Zope/Server/FTP/FTPStatusMessages.py 1.1.2.5 => 1.1.2.6 === status_msgs = { - 150: ('Opening %s mode data connection for file list', - 'Opening %s connection for %s',), - 200: ('%s command successful.', - 'Type set to %s.', - 'STRU F Ok.', - 'MODE S Ok.',), - 213: ('%4d%02d%02d%02d%02d%02d', # A date - '%d Bytes'), # Size - 214: ('-The following commands are recognized', - ''), - 215: ('%s Type: %s',), # Server Type - 220: ('%s FTP server (Zope Async/Thread V0.1) ready.',), - 221: ('Goodbye.',), - 226: ('%s command successful.', - 'Transfer successful.'), - 227: ('Entering Passive Mode (%s,%d,%d)',), - 230: ('Login Successful.',), - 250: ('%s command successful.',), - 257: ('%s command successful.', - "'%s' is the current directory.",), - 331: ('Password required',), - 350: ('Restarting at %d. Send STORE or RETRIEVE to initiate transfer.', - 'File exists, ready for destination.',), - 425: ("Can't build data connection",), - 426: ('Connection closed; transfer aborted.',), - 500: ("'%s': command not understood.",), - 502: ("Unimplemented MODE type",), - 504: ('Byte size must be 8', - 'Unimplemented STRU type',), - 530: ("You are not authorized to perform the '%s' command", - 'Please log in with USER and PASS', - 'The username and password do not match.',), - 550: ('Could not list directory: %s', - '%s: No such directory.', - '%s: No such file.', - '%s: Is not a file', - 'Error creating file.', - 'Error creating directory.', - 'Error deleting file.', - 'Error removing directory.'), - 553: ('Could not open file for reading: %s', - 'Could not open file for writing: %s', - 'Restart on STOR not yet supported',), - - 560: ('Could not rename %s to %s.', - 'No source filename specify. Call RNFR first.',), + 'OPEN_DATA_CONN' : '150 Opening %s mode data connection for file list', + 'OPEN_CONN' : '150 Opening %s connection for %s', + 'SUCCESS_200' : '200 %s command successful.', + 'TYPE_SET_OK' : '200 Type set to %s.', + 'STRU_OK' : '200 STRU F Ok.', + 'MODE_OK' : '200 MODE S Ok.', + 'FILE_DATE' : '213 %4d%02d%02d%02d%02d%02d', + 'FILE_SIZE' : '213 %d Bytes', + 'HELP_START' : '214-The following commands are recognized', + 'HELP_END' : '214 Help done.', + 'SERVER_TYPE' : '215 %s Type: %s', + 'SERVER_READY' : '220 %s FTP server (Zope Async/Thread V0.1) ready.', + 'GOODBYE' : '221 Goodbye.', + 'SUCCESS_226' : '226 %s command successful.', + 'TRANS_SUCCESS' : '226 Transfer successful.', + 'PASV_MODE_MSG' : '227 Entering Passive Mode (%s,%d,%d)', + 'LOGIN_SUCCESS' : '230 Login Successful.', + 'SUCCESS_250' : '250 %s command successful.', + 'SUCCESS_257' : '257 %s command successful.', + 'ALREADY_CURRENT' : "257 '%s' is the current directory.", + 'PASS_REQUIRED' : '331 Password required', + 'RESTART_TRANSFER' : '350 Restarting at %d. Send STORE or ' + 'RETRIEVE to initiate transfer.', + 'READY_FOR_DEST' : '350 File exists, ready for destination.', + 'NO_DATA_CONN' : "425 Can't build data connection", + 'TRANSFER_ABORTED' : '426 Connection closed; transfer aborted.', + 'CMD_UNKNOWN' : "500 '%s': command not understood.", + 'MODE_UNKOWN' : '502 Unimplemented MODE type', + 'WRONG_BYTE_SIZE' : '504 Byte size must be 8', + 'STRU_UNKNOWN' : '504 Unimplemented STRU type', + 'NOT_AUTH' : "530 You are not authorized to perform the " + "'%s' command", + 'LOGIN_REQUIRED' : '530 Please log in with USER and PASS', + 'LOGIN_MISMATCH' : '530 The username and password do not match.', + 'ERR_NO_LIST' : '550 Could not list directory: %s', + 'ERR_NO_DIR' : '550 %s: No such directory.', + 'ERR_NO_FILE' : '550 %s: No such file.', + 'ERR_IS_NOT_FILE' : '550 %s: Is not a file', + 'ERR_CREATE_FILE' : '550 Error creating file.', + 'ERR_CREATE_DIR' : '550 Error creating directory.', + 'ERR_DELETE_FILE' : '550 Error deleting file.', + 'ERR_DELETE_DIR' : '550 Error removing directory.', + 'ERR_OPEN_READ' : '553 Could not open file for reading: %s', + 'ERR_OPEN_WRITE' : '553 Could not open file for writing: %s', + 'ERR_RESTART_STOR' : '553 Restart on STOR not yet supported', + 'ERR_RENAME' : '560 Could not rename %s to %s.', + 'ERR_RNFR_SOURCE' : '560 No source filename specify. Call RNFR first.', } === Zope3/lib/python/Zope/Server/FTP/RecvChannel.py 1.1.2.3 => 1.1.2.4 === s.total_bytes_in.increment(self.bytes_in.as_long()) self.fd.close() - self.channel.reply(226, 1) + self.channel.reply('TRANS_SUCCESS') self.close() === Zope3/lib/python/Zope/Server/FTP/XmitChannel.py 1.1.2.2 => 1.1.2.3 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -import asynchat - - -class XmitChannel(asynchat.async_chat, object): - - # for an ethernet, you want this to be fairly large, in fact, it - # _must_ be large for performance comparable to an ftpd. [64k] we - # ought to investigate automatically-sized buffers... - ac_out_buffer_size = 16384 - - bytes_out = 0 - - def __init__ (self, channel, client_addr=None): - self.channel = channel - self.client_addr = client_addr - super(XmitChannel, self).__init__() - - - def log (*args): - pass - - - def readable (self): - return not self.connected - - - def writable (self): - return 1 - - - def send (self, data): - result = super(XmitChannel, self).send(data) - self.bytes_out = self.bytes_out + result - return result - - - def handle_error (self): - # usually this is to catch an unexpected disconnect. - # XXX: Helpfule for debugging - import traceback - traceback.print_exc() - self.log_info ('unexpected disconnect on data xmit channel', 'error') - try: - self.close() - except: - pass - - # TODO: there's a better way to do this. we need to be able to - # put 'events' in the producer fifo. to do this cleanly we need - # to reposition the 'producer' fifo as an 'event' fifo. - - # dummy function to suppress warnings caused by some FTP clients - def handle_connect(self): - pass - - - def close (self): - c = self.channel - s = c.server - c.client_dc = None - s.total_files_out.increment() - s.total_bytes_out.increment (self.bytes_out) - if not len(self.producer_fifo): - c.reply(226, 1) - elif not c.closed: - c.reply(426) - del c - del s - del self.channel - asynchat.async_chat.close(self) +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +import asynchat + + +class XmitChannel(asynchat.async_chat, object): + + # for an ethernet, you want this to be fairly large, in fact, it + # _must_ be large for performance comparable to an ftpd. [64k] we + # ought to investigate automatically-sized buffers... + ac_out_buffer_size = 16384 + + bytes_out = 0 + + def __init__ (self, channel, client_addr=None): + self.channel = channel + self.client_addr = client_addr + super(XmitChannel, self).__init__() + + + def log (*args): + pass + + + def readable (self): + return not self.connected + + + def writable (self): + return 1 + + + def send (self, data): + result = super(XmitChannel, self).send(data) + self.bytes_out = self.bytes_out + result + return result + + + def handle_error (self): + # usually this is to catch an unexpected disconnect. + # XXX: Helpfule for debugging + import traceback + traceback.print_exc() + self.log_info ('unexpected disconnect on data xmit channel', 'error') + try: + self.close() + except: + pass + + # TODO: there's a better way to do this. we need to be able to + # put 'events' in the producer fifo. to do this cleanly we need + # to reposition the 'producer' fifo as an 'event' fifo. + + # dummy function to suppress warnings caused by some FTP clients + def handle_connect(self): + pass + + + def close (self): + c = self.channel + s = c.server + c.client_dc = None + s.total_files_out.increment() + s.total_bytes_out.increment (self.bytes_out) + if not len(self.producer_fifo): + c.reply('TRANS_SUCCESS') + elif not c.closed: + c.reply('TRANSFER_ABORTED') + del c + del s + del self.channel + asynchat.async_chat.close(self) From tdickenson@geminidataloggers.com Fri Apr 5 16:00:17 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Fri, 5 Apr 2002 11:00:17 -0500 Subject: [Zope-Checkins] CVS: Zope/lib/python/ZPublisher - HTTPResponse.py:1.57 Message-ID: <200204051600.g35G0H432120@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/ZPublisher In directory cvs.zope.org:/tmp/cvs-serv30976/ZPublisher Modified Files: HTTPResponse.py Log Message: Decide whether a body is html by looking at the body we are actually going to use, rather than the body we were originally given. We may have given it an html wrapper a few lines earlier. === Zope/lib/python/ZPublisher/HTTPResponse.py 1.56 => 1.57 === if not self.headers.has_key('content-type'): - isHTML=self.isHTML(body) + isHTML=self.isHTML(self.body) if isHTML: c='text/html' else: c='text/plain' self.setHeader('content-type', c) From tdickenson@geminidataloggers.com Fri Apr 5 16:01:56 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Fri, 5 Apr 2002 11:01:56 -0500 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - SimpleItem.py:1.97 Message-ID: <200204051601.g35G1uk32246@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv32235/OFS Modified Files: SimpleItem.py Log Message: support for exceptions who raise an exception in str(). They get represented as === Zope/lib/python/OFS/SimpleItem.py 1.96 => 1.97 === LOG('OFS', ERROR, 'Exception while rendering an error message', error=sys.exc_info()) - v = str(error_value) + ( + try: + strv = str(error_value) + except: + strv = '' % str(type(error_value).__name__) + v = strv + ( " (Also, an error occurred while attempting " "to render the standard error message.)") raise error_type, v, tb From tdickenson@geminidataloggers.com Fri Apr 5 16:01:56 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Fri, 5 Apr 2002 11:01:56 -0500 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/SiteErrorLog - SiteErrorLog.py:1.4 Message-ID: <200204051601.g35G1u832248@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/SiteErrorLog In directory cvs.zope.org:/tmp/cvs-serv32235/Products/SiteErrorLog Modified Files: SiteErrorLog.py Log Message: support for exceptions who raise an exception in str(). They get represented as === Zope/lib/python/Products/SiteErrorLog/SiteErrorLog.py 1.3 => 1.4 === pass + try: + strv = str(info[1]) + except: + strv = '' % str(type(info[1]).__name__) + log = self._getLog() log.append({ 'type': str(getattr(info[0], '__name__', info[0])), - 'value': str(info[1]), + 'value': strv, 'time': now, 'id': str(now) + str(random()), # Low chance of collision 'tb_text': tb_text, From srichter@cbu.edu Fri Apr 5 17:12:39 2002 From: srichter@cbu.edu (Stephan Richter) Date: Fri, 5 Apr 2002 12:12:39 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/POP3 Zope3/lib/python/Zope/Server/POP3 - New directory Message-ID: <200204051712.g35HCdh17373@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/POP3 In directory cvs.zope.org:/tmp/cvs-serv17367/POP3 Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/Server/POP3 added to the repository --> Using per-directory sticky tag `Zope3-Server-Branch' === Added directory Zope3/lib/python/Zope/Server/POP3 === From srichter@cbu.edu Fri Apr 5 17:12:47 2002 From: srichter@cbu.edu (Stephan Richter) Date: Fri, 5 Apr 2002 12:12:47 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/SMTP Zope3/lib/python/Zope/Server/SMTP - New directory Message-ID: <200204051712.g35HCl117384@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/SMTP In directory cvs.zope.org:/tmp/cvs-serv17378/SMTP Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/Server/SMTP added to the repository --> Using per-directory sticky tag `Zope3-Server-Branch' === Added directory Zope3/lib/python/Zope/Server/SMTP === From srichter@cbu.edu Fri Apr 5 17:13:06 2002 From: srichter@cbu.edu (Stephan Richter) Date: Fri, 5 Apr 2002 12:13:06 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/POP3/tests Zope3/lib/python/Zope/Server/POP3/tests - New directory Message-ID: <200204051713.g35HD6H17492@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/POP3/tests In directory cvs.zope.org:/tmp/cvs-serv17461/tests Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/Server/POP3/tests added to the repository --> Using per-directory sticky tag `Zope3-Server-Branch' === Added directory Zope3/lib/python/Zope/Server/POP3/tests === From srichter@cbu.edu Fri Apr 5 17:15:59 2002 From: srichter@cbu.edu (Stephan Richter) Date: Fri, 5 Apr 2002 12:15:59 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/SMTP/tests Zope3/lib/python/Zope/Server/SMTP/tests - New directory Message-ID: <200204051715.g35HFxw18122@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/SMTP/tests In directory cvs.zope.org:/tmp/cvs-serv18116/tests Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/Server/SMTP/tests added to the repository --> Using per-directory sticky tag `Zope3-Server-Branch' === Added directory Zope3/lib/python/Zope/Server/SMTP/tests === From srichter@cbu.edu Fri Apr 5 17:16:39 2002 From: srichter@cbu.edu (Stephan Richter) Date: Fri, 5 Apr 2002 12:16:39 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/POP3/tests - __init__.py:1.1.2.1 Message-ID: <200204051716.g35HGdG18218@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/POP3/tests In directory cvs.zope.org:/tmp/cvs-serv18114/POP3/tests Added Files: Tag: Zope3-Server-Branch __init__.py Log Message: Transcribed the shiks! POP3 code to our server model. Nothing is working yet, I merely copied and adapted code. === Added File Zope3/lib/python/Zope/Server/POP3/tests/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.2.1 2002/04/05 17:16:38 srichter Exp $ """ From srichter@cbu.edu Fri Apr 5 17:16:39 2002 From: srichter@cbu.edu (Stephan Richter) Date: Fri, 5 Apr 2002 12:16:39 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/POP3 - IPOP3CommandHandler.py:1.1.2.1 POP3Server.py:1.1.2.1 POP3ServerChannel.py:1.1.2.1 POP3StatusMessages.py:1.1.2.1 __init__.py:1.1.2.1 Message-ID: <200204051716.g35HGdD18219@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/POP3 In directory cvs.zope.org:/tmp/cvs-serv18114/POP3 Added Files: Tag: Zope3-Server-Branch IPOP3CommandHandler.py POP3Server.py POP3ServerChannel.py POP3StatusMessages.py __init__.py Log Message: Transcribed the shiks! POP3 code to our server model. Nothing is working yet, I merely copied and adapted code. === Added File Zope3/lib/python/Zope/Server/POP3/IPOP3CommandHandler.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IPOP3CommandHandler.py,v 1.1.2.1 2002/04/05 17:16:38 srichter Exp $ """ from Interface import Interface class IPOP3CommandHandler(Interface): """ """ def cmd_apop(args): """APOP name digest Arguments: a string identifying a mailbox and a MD5 digest string (both required) Restrictions: may only be given in the AUTHORIZATION state after the POP3 greeting Discussion: Normally, each POP3 session starts with a USER/PASS exchange. This results in a server/user-id specific password being sent in the clear on the network. For intermittent use of POP3, this may not introduce a sizable risk. However, many POP3 client implementations connect to the POP3 server on a regular basis -- to check for new mail. Further the interval of session initiation may be on the order of five minutes. Hence, the risk of password capture is greatly enhanced. An alternate method of authentication is required which provides for both origin authentication and replay protection, but which does not involve sending a password in the clear over the network. The APOP command provides this functionality. A POP3 server which implements the APOP command will include a timestamp in its banner greeting. The syntax of the timestamp corresponds to the `msg-id' in [RFC822], and MUST be different each time the POP3 server issues a banner greeting. For example, on a UNIX implementation in which a separate UNIX process is used for each instance of a POP3 server, the syntax of the timestamp might be: where `process-ID' is the decimal value of the process's PID, clock is the decimal value of the system clock, and hostname is the fully-qualified domain-name corresponding to the host where the POP3 server is running. The POP3 client makes note of this timestamp, and then issues the APOP command. The `name' parameter has identical semantics to the `name' parameter of the USER command. The `digest' parameter is calculated by applying the MD5 algorithm [RFC1321] to a string consisting of the timestamp (including angle-brackets) followed by a shared secret. This shared secret is a string known only to the POP3 client and server. Great care should be taken to prevent unauthorized disclosure of the secret, as knowledge of the secret will allow any entity to successfully masquerade as the named user. The `digest' parameter itself is a 16-octet value which is sent in hexadecimal format, using lower-case ASCII characters. When the POP3 server receives the APOP command, it verifies the digest provided. If the digest is correct, the POP3 server issues a positive response, and the POP3 session enters the TRANSACTION state. Otherwise, a negative response is issued and the POP3 session remains in the AUTHORIZATION state. Note that as the length of the shared secret increases, so does the difficulty of deriving it. As such, shared secrets should be long strings (considerably longer than the 8-character example shown below). Possible Responses: +OK maildrop locked and ready -ERR permission denied Examples: S: +OK POP3 server ready <1896.697170952@dbc.mtview.ca.us> C: APOP mrose c4c9334bac560ecc979e58001b3e22fb S: +OK maildrop has 1 message (369 octets) In this example, the shared secret is the string `tan- staaf'. Hence, the MD5 algorithm is applied to the string <1896.697170952@dbc.mtview.ca.us>tanstaaf which produces a digest value of c4c9334bac560ecc979e58001b3e22fb """ def cmd_dele(args): """DELE msg Arguments: a message-number (required) which may not refer to a message marked as deleted Restrictions: may only be given in the TRANSACTION state Discussion: The POP3 server marks the message as deleted. Any future reference to the message-number associated with the message in a POP3 command generates an error. The POP3 server does not actually delete the message until the POP3 session enters the UPDATE state. Possible Responses: +OK message deleted -ERR no such message Examples: C: DELE 1 S: +OK message 1 deleted ... C: DELE 2 S: -ERR message 2 already deleted """ def cmd_list(args): """LIST [msg] Arguments: a message-number (optional), which, if present, may NOT refer to a message marked as deleted Restrictions: may only be given in the TRANSACTION state Discussion: If an argument was given and the POP3 server issues a positive response with a line containing information for that message. This line is called a "scan listing" for that message. If no argument was given and the POP3 server issues a positive response, then the response given is multi-line. After the initial +OK, for each message in the maildrop, the POP3 server responds with a line containing information for that message. This line is also called a "scan listing" for that message. In order to simplify parsing, all POP3 servers are required to use a certain format for scan listings. A scan listing consists of the message-number of the message, followed by a single space and the exact size of the message in octets. This memo makes no requirement on what follows the message size in the scan listing. Minimal implementations should just end that line of the response with a CRLF pair. Note that messages marked as deleted are not listed. Possible Responses: +OK scan listing follows -ERR no such message Examples: C: LIST S: +OK 2 messages (320 octets) S: 1 120 S: 2 200 S: . ... C: LIST 2 S: +OK 2 200 ... C: LIST 3 S: -ERR no such message, only 2 messages in maildrop """ def cmd_pass(args): """PASS string Arguments: a server/mailbox-specific password (required) Restrictions: may only be given in the AUTHORIZATION state after a successful USER command Discussion: Since the PASS command has exactly one argument, a POP3 server may treat spaces in the argument as part of the password, instead of as argument separators. Possible Responses: +OK maildrop locked and ready -ERR invalid password -ERR unable to lock maildrop Examples: C: USER mrose S: +OK mrose is a real hoopy frood C: PASS secret S: +OK mrose's maildrop has 2 messages (320 octets) ... C: USER mrose S: +OK mrose is a real hoopy frood C: PASS secret S: -ERR maildrop already locked""" def cmd_quit(args): """QUIT Arguments: none Restrictions: none Discussion: The POP3 server removes all messages marked as deleted from the maildrop. It then releases any exclusive-access lock on the maildrop and replies as to the status of these operations. The TCP connection is then closed. Possible Responses: +OK Examples: C: QUIT S: +OK dewey POP3 server signing off (maildrop empty) ... C: QUIT S: +OK dewey POP3 server signing off (2 messages left) ... """ def cmd_retr(args): """RETR msg Arguments: a message-number (required) which may not refer to a message marked as deleted Restrictions: may only be given in the TRANSACTION state Discussion: If the POP3 server issues a positive response, then the response given is multi-line. After the initial +OK, the POP3 server sends the message corresponding to the given message-number, being careful to byte-stuff the termination character (as with all multi-line responses). Possible Responses: +OK message follows -ERR no such message Examples: C: RETR 1 S: +OK 120 octets S: S: . """ def cmd_rset(args): """RSET Arguments: none Restrictions: may only be given in the TRANSACTION state Discussion: If any messages have been marked as deleted by the POP3 server, they are unmarked. The POP3 server then replies with a positive response. Possible Responses: +OK Examples: C: RSET S: +OK maildrop has 2 messages (320 octets) """ def cmd_stat(args): """STAT Arguments: none Restrictions: may only be given in the TRANSACTION state Discussion: The POP3 server issues a positive response with a line containing information for the maildrop. This line is called a "drop listing" for that maildrop. In order to simplify parsing, all POP3 servers required to use a certain format for drop listings. The positive response consists of "+OK" followed by a single space, the number of messages in the maildrop, a single space, and the size of the maildrop in octets. This memo makes no requirement on what follows the maildrop size. Minimal implementations should just end that line of the response with a CRLF pair. More advanced implementations may include other information. Note that messages marked as deleted are not counted in either total. Possible Responses: +OK nn mm Examples: C: STAT S: +OK 2 320 """ def cmd_top(args): """TOP msg n Arguments: a message-number (required) which may NOT refer to a message marked as deleted, and a non-negative number (required) Restrictions: may only be given in the TRANSACTION state Discussion: If the POP3 server issues a positive response, then the response given is multi-line. After the initial +OK, the POP3 server sends the headers of the message, the blank line separating the headers from the body, and then the number of lines indicated message's body, being careful to byte-stuff the termination character (as with all multi- line responses). Note that if the number of lines requested by the POP3 client is greater than than the number of lines in the body, then the POP3 server sends the entire message. Possible Responses: +OK top of message follows -ERR no such message Examples: C: TOP 1 10 S: +OK S: S: . ... C: TOP 100 3 S: -ERR no such message """ def cmd_uidl(args): """UIDL [msg] Arguments: a message-number (optionally) If a message-number is given, it may NOT refer to a message marked as deleted. Restrictions: may only be given in the TRANSACTION state. Discussion: If an argument was given and the POP3 server issues a positive response with a line containing information for that message. This line is called a "unique-id listing" for that message. If no argument was given and the POP3 server issues a positive response, then the response given is multi-line. After the initial +OK, for each message in the maildrop, the POP3 server responds with a line containing information for that message. This line is called a "unique-id listing" for that message. In order to simplify parsing, all POP3 servers are required to use a certain format for unique-id listings. A unique-id listing consists of the message-number of the message, followed by a single space and the unique-id of the message. No information follows the unique-id in the unique-id listing. The unique-id of a message is an arbitrary server-determined string, consisting of characters in the range 0x21 to 0x7E, which uniquely identifies a message within a maildrop and which persists across sessions. The server should never reuse an unique-id in a given maildrop, for as long as the entity using the unique-id exists. Note that messages marked as deleted are not listed. Possible Responses: +OK unique-id listing follows -ERR no such message Examples: C: UIDL S: +OK S: 1 whqtswO00WBw418f9t5JxYwZ S: 2 QhdPYR:00WBw1Ph7x7 S: . ... C: UIDL 2 S: +OK 2 QhdPYR:00WBw1Ph7x7 ... C: UIDL 3 S: -ERR no such message, only 2 messages in maildrop """ def cmd_user(args): """USER name Arguments: a string identifying a mailbox (required), which is of significance ONLY to the server Restrictions: may only be given in the AUTHORIZATION state after the POP3 greeting or after an unsuccessful USER or PASS command Possible Responses: +OK name is a valid mailbox -ERR never heard of mailbox name Examples: C: USER mrose S: +OK mrose is a real hoopy frood ... C: USER frated S: -ERR sorry, no mailbox for frated here """ === Added File Zope3/lib/python/Zope/Server/POP3/POP3Server.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: POP3Server.py,v 1.1.2.1 2002/04/05 17:16:38 srichter Exp $ """ from POP3ServerChannel import POP3ServerChannel from Zope.Server.ServerBase import ServerBase class POP3Server(ServerBase): """Generic FTP Server""" channel_class = POP3ServerChannel SERVER_IDENT = 'Zope.Server.POP3Server' def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1, hit_log=None, verbose=0, socket_map=None): super(FTPServer, self).__init__(ip, port, task_dispatcher, adj, start, hit_log, verbose, socket_map) if __name__ == '__main__': import asyncore from Zope.Server.TaskThreads import ThreadedTaskDispatcher td = ThreadedTaskDispatcher() td.setThreadCount(4) POP3Server('', 8110, task_dispatcher=td) try: while 1: asyncore.poll(5) print 'active channels:', POP3ServerChannel.active_channels except KeyboardInterrupt: print 'shutting down...' td.shutdown() === Added File Zope3/lib/python/Zope/Server/POP3/POP3ServerChannel.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: POP3ServerChannel.py,v 1.1.2.1 2002/04/05 17:16:38 srichter Exp $ """ import os import stat import socket import time from Zope.Server.LineReceiver.LineServerChannel import LineServerChannel from POP3StatusMessages import status_msgs from FileProducer import FileProducer from IPOP3CommandHandler import IPOP3CommandHandler from PassiveAcceptor import PassiveAcceptor from RecvChannel import RecvChannel from XmitChannel import XmitChannel class POP3ServerChannel(LineServerChannel): """The POP3 Server Channel represents a connection to a particular client. We can therefore store information here.""" __implements__ = LineServerChannel.__implements__, IPOP3CommandHandler # These are the commands that are allowed without the channel being in # "Transaction State", as the POP3 RFC calls it. special_commands = ('cmd_quit', 'cmd_user', 'cmd_pass') # These are the commands that are accessing the filesystem. # Since this could be also potentially a longer process, these commands # are also the ones that are executed in a different thread. thread_commands = ('cmd_apop', 'cmd_dele', 'cmd_list', 'cmd_pass', 'cmd_retr', 'cmd_rset', 'cmd_stat', 'cmd_top', 'cmd_uidl') # Define the status messages status_messages = status_msgs def __init__(self, server, conn, addr, adj=None, socket_map=None): super(POP3ServerChannel, self).__init__(server, conn, addr, adj, socket_map) self.username = '' self.password = '' self.messagelist = [] ############################################################ # Implementation methods for interface # Zope.Server.POP3.IPOP3CommandHandler def cmd_apop(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' pass def cmd_dele(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' try: msg_index = int(args)-1 except: return self.reply('ERR_MSG_UNKNOWN') msg_list = self.messagelist if msg_index >= 0 and msg_index < len(msg_list): # mark message as deleted self.msg_list[msg_index].deleted = 1 return self.reply('OK_DELETE') return self.reply('ERR_MSG_UNKNOWN') def cmd_list(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' msg_list = self.messagelist if args: # A message id was passed, so let's work with it. try: msg_index = int(args)-1 except: return self.reply('ERR_MSG_UNKNOWN') if msg_index >= 0 and msg_index < len(msg_list): return self.reply('ERR_MSG_UNKNOWN') message = msg_list[msg_index] self.reply('OK_SINGLE_LIST', (msg_index+1, message.size) else: usedbytes = self.getTotalSize(msg_list) total_msgs = len(map(lambda msg: not msg.deleted, msg_list)) self.reply('OK_MSG_LIST', (len(msg_list), usedbytes)) for msg in msg_list: if msg.deleted: continue self.write("%d %d\r\n" % (msg_list.index(msg)+1, msg.size)) self.write('.\r\n') self.flush() def cmd_pass(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' self.password = args if self.authenticated: return self.reply('ERR_INV_STATE') if not self.username: return self.reply('ERR_NO_USER') auth = self.server.auth_source self.authenticated, message = auth.authenticate(self.username, self.password) if self.authenticated: self.reply('OK_LOGIN') else: self.reply('ERR_LOGIN_MISMATCH') self.close_when_done() def cmd_quit(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' self.reply('OK_QUIT') # XXX Should de;ete messages self.close_when_done() def cmd_retr(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' try: msg_index = int(args)-1 except: return self.reply('ERR_MSG_UNKNOWN') msg_list = self.messagelist if msg_index >= 0 and msg_index < len(msg_list): # mark message as deleted self.write(msg.body) return self.reply('OK_RETR') return self.reply('ERR_MSG_UNKNOWN') def cmd_rset(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' for msg in self.messagelist): # mark all messages as not-deleted msg.deleted = 0 self.reply('OK_RSET') def cmd_stat(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' usedbytes = self.getTotalSize(msg_list) total_msgs = len(map(lambda msg: not msg.deleted, msg_list)) self.reply('OK_STAT', (total_msgs, usedbytes)) def cmd_top(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' try: msg_index, nroflines = args.split() msg_index = int(args)-1 nroflines = int(nroflines) except: return self.reply('ERR_MSG_UNKNOWN') msg_list = self.messagelist if msg_index >= 0 and msg_index < len(msg_list): # Split message body into lines/ lines = self.messagelist[msg_index].body.split("\r\n") found, isHeader, line = -1, 1, 0 # XXX: This is too complicated. It can be done easier. while line < len(nroflines): if isHeader: # skip header lines. Header lines have a : if lines[line].find(':') == 0: isHeader = 0 else: found += 1 if found == nroflines: break self.reply('OK_TOP', line) lines = lines[:line] self.write("\r\n".join(lines)) self.write('.\r\n') self.flush() else: return self.reply('ERR_MSG_UNKNOWN') def cmd_uidl(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' pass def cmd_user(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' if self.authenticated: return self.reply('ERR_INV_STATE') if self.auth.hasUser(args): self.reply('OK_USER', args) else: self.reply('ERR_NOT_USER') # ############################################################ === Added File Zope3/lib/python/Zope/Server/POP3/POP3StatusMessages.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: POP3StatusMessages.py,v 1.1.2.1 2002/04/05 17:16:38 srichter Exp $ """ status_msgs = { 'OK_GENERAL' : '+OK', 'OK_LOGIN' : '+OK login successful', 'OK_USER' : '+OK %s is a valid name box', 'OK_QUIT' : '+OK', 'OK_SINGLE_LIST' : '+OK %i %i', 'OK_MSG_LIST' : '+OK %i message (%i octets)', 'OK_DELETE' : '+OK The message was successfully deleted' 'OK_RETR' : '+OK message follows', 'OK_RSET' : '+OK Resetting all messages done', 'OKTOP' : '+OK top %i lines of message follows', 'OK_APOP' : '+OK maildrop locked and ready', 'OK_UIDL' : '+OK unique-id listing follows', 'ERR_CMD_UNKNOWN' : '-ERR unknown command', 'ERR_MSG_UNKNOWN' : '-ERR unknown or invalid message id', 'ERR_INV_STATE' : '-ERR Invalid State', 'ERR_NO_USER' : '-ERR No user was yet specified' 'ERR_NOT_USER' : '-ERR never heard of mailbox name', 'ERR_LOGIN_MISMATH' : '-ERR username and password did not match', } === Added File Zope3/lib/python/Zope/Server/POP3/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.2.1 2002/04/05 17:16:38 srichter Exp $ """ From srichter@cbu.edu Fri Apr 5 17:19:54 2002 From: srichter@cbu.edu (Stephan Richter) Date: Fri, 5 Apr 2002 12:19:54 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/SMTP/tests - __init__.py:1.1.2.1 Message-ID: <200204051719.g35HJsg20211@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/SMTP/tests In directory cvs.zope.org:/tmp/cvs-serv18691/SMTP/tests Added Files: Tag: Zope3-Server-Branch __init__.py Log Message: First cut of SMTP. Same as for POP3. I have only transcribed shick! code to our model. Since the shiks! code depends on SQL, there is quiet a bit of stuff to write to make it work for us. But at least all commands and status messages are covered now. === Added File Zope3/lib/python/Zope/Server/SMTP/tests/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.2.1 2002/04/05 17:19:53 srichter Exp $ """ From srichter@cbu.edu Fri Apr 5 17:19:54 2002 From: srichter@cbu.edu (Stephan Richter) Date: Fri, 5 Apr 2002 12:19:54 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/SMTP - ISMTPCommandHandler.py:1.1.2.1 SMTPServer.py:1.1.2.1 SMTPServerChannel.py:1.1.2.1 SMTPSpamFilter.py:1.1.2.1 SMTPStatusMessages.py:1.1.2.1 SMTPUtilities.py:1.1.2.1 SpamData.py:1.1.2.1 __init__.py:1.1.2.1 Message-ID: <200204051719.g35HJsl20215@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/SMTP In directory cvs.zope.org:/tmp/cvs-serv18691/SMTP Added Files: Tag: Zope3-Server-Branch ISMTPCommandHandler.py SMTPServer.py SMTPServerChannel.py SMTPSpamFilter.py SMTPStatusMessages.py SMTPUtilities.py SpamData.py __init__.py Log Message: First cut of SMTP. Same as for POP3. I have only transcribed shick! code to our model. Since the shiks! code depends on SQL, there is quiet a bit of stuff to write to make it work for us. But at least all commands and status messages are covered now. === Added File Zope3/lib/python/Zope/Server/SMTP/ISMTPCommandHandler.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: ISMTPCommandHandler.py,v 1.1.2.1 2002/04/05 17:19:53 srichter Exp $ """ from Interface import Interface class ISMTPCommandHandler(Interface): """This interface defines all the SMTP commands that are supported by the server. Every command takes the args as first arguments, since it is responsible for parsing the rest of the input (which is usually easy). """ def cmd_data(args): """DATA (DATA) The receiver treats the lines following the command as mail data from the sender. This command causes the mail data from this command to be appended to the mail data buffer. The mail data may contain any of the 128 ASCII character codes. The mail data is terminated by a line containing only a period, that is the character sequence "." (see Section 4.5.2 on Transparency). This is the end of mail data indication. The end of mail data indication requires that the receiver must now process the stored mail transaction information. This processing consumes the information in the reverse-path buffer, the forward-path buffer, and the mail data buffer, and on the completion of this command these buffers are cleared. If the processing is successful the receiver must send an OK reply. If the processing fails completely the receiver must send a failure reply. When the receiver-SMTP accepts a message either for relaying or for final delivery it inserts at the beginning of the mail data a time stamp line. The time stamp line indicates the identity of the host that sent the message, and the identity of the host that received the message (and is inserting this time stamp), and the date and time the message was received. Relayed messages will have multiple time stamp lines. When the receiver-SMTP makes the "final delivery" of a message it inserts at the beginning of the mail data a return path line. The return path line preserves the information in the from the MAIL command. Here, final delivery means the message leaves the SMTP world. Normally, this would mean it has been delivered to the destination user, but in some cases it may be further processed and transmitted by another mail system. It is possible for the mailbox in the return path be different from the actual sender's mailbox, for example, if error responses are to be delivered a special error handling mailbox rather than the message senders. The preceding two paragraphs imply that the final mail data will begin with a return path line, followed by one or more time stamp lines. These lines will be followed by the mail data header and body [2]. See Example 8. Special mention is needed of the response and further action required when the processing following the end of mail data indication is partially successful. This could arise if after accepting several recipients and the mail data, the receiver-SMTP finds that the mail data can be successfully delivered to some of the recipients, but it cannot be to others (for example, due to mailbox space allocation problems). In such a situation, the response to the DATA command must be an OK reply. But, the receiver-SMTP must compose and send an "undeliverable mail" notification message to the originator of the message. Either a single notification which lists all of the recipients that failed to get the message, or separate notification messages must be sent for each failed recipient (see Example 7). All undeliverable mail notification messages are sent using the MAIL command (even if they result from processing a SEND, SOML, or SAML command).""" def cmd_ehlo(args): """Extended Greeting. See http://www.faqs.org/rfcs/rfc2821.html for details """ def cmd_expn(args): """EXPAND (EXPN) This command asks the receiver to confirm that the argument identifies a mailing list, and if so, to return the membership of that list. The full name of the users (if known) and the fully specified mailboxes are returned in a multiline reply. This command has no effect on any of the reverse-path buffer, the forward-path buffer, or the mail data buffer. """ def cmd_helo(args): """HELLO (HELO) This command is used to identify the sender-SMTP to the receiver-SMTP. The argument field contains the host name of the sender-SMTP. The receiver-SMTP identifies itself to the sender-SMTP in the connection greeting reply, and in the response to this command. This command and an OK reply to it confirm that both the sender-SMTP and the receiver-SMTP are in the initial state, that is, there is no transaction in progress and all state tables and buffers are cleared. """ def cmd_help(args): """HELP (HELP) This command causes the receiver to send helpful information to the sender of the HELP command. The command may take an argument (e.g., any command name) and return more specific information as a response. This command has no effect on any of the reverse-path buffer, the forward-path buffer, or the mail data buffer. """ def cmd_mail(args): """MAIL (MAIL) MAIL FROM: This command is used to initiate a mail transaction in which the mail data is delivered to one or more mailboxes. The argument field contains a reverse-path. The reverse-path consists of an optional list of hosts and the sender mailbox. When the list of hosts is present, it is a "reverse" source route and indicates that the mail was relayed through each host on the list (the first host in the list was the most recent relay). This list is used as a source route to return non-delivery notices to the sender. As each relay host adds itself to the beginning of the list, it must use its name as known in the IPCE to which it is relaying the mail rather than the IPCE from which the mail came (if they are different). In some types of error reporting messages (for example, undeliverable mail notifications) the reverse-path may be null (see Example 7). This command clears the reverse-path buffer, the forward-path buffer, and the mail data buffer; and inserts the reverse-path information from this command into the reverse-path buffer. """ def cmd_noop(args): """NOOP (NOOP) This command does not affect any parameters or previously entered commands. It specifies no action other than that the receiver send an OK reply. This command has no effect on any of the reverse-path buffer, the forward-path buffer, or the mail data buffer. """ def cmd_quit(args): """QUIT (QUIT) This command specifies that the receiver must send an OK reply, and then close the transmission channel. The receiver should not close the transmission channel until it receives and replies to a QUIT command (even if there was an error). The sender should not close the transmission channel until it send a QUIT command and receives the reply (even if there was an error response to a previous command). If the connection is closed prematurely the receiver should act as if a RSET command had been received (canceling any pending transaction, but not undoing any previously completed transaction), the sender should act as if the command or transaction in progress had received a temporary error (4xx). """ def cmd_rcpt(args): """RECIPIENT (RCPT) This command is used to identify an individual recipient of the mail data; multiple recipients are specified by multiple use of this command. The forward-path consists of an optional list of hosts and a required destination mailbox. When the list of hosts is present, it is a source route and indicates that the mail must be relayed to the next host on the list. If the receiver-SMTP does not implement the relay function it may user the same reply it would for an unknown local user (550). When mail is relayed, the relay host must remove itself from the beginning forward-path and put itself at the beginning of the reverse-path. When mail reaches its ultimate destination (the forward-path contains only a destination mailbox), the receiver-SMTP inserts it into the destination mailbox in accordance with its host mail conventions. For example, mail received at relay host A with arguments FROM: TO:<@HOSTA.ARPA,@HOSTB.ARPA:USERC@HOSTD.ARPA> will be relayed on to host B with arguments FROM:<@HOSTA.ARPA:USERX@HOSTY.ARPA> TO:<@HOSTB.ARPA:USERC@HOSTD.ARPA>. This command causes its forward-path argument to be appended to the forward-path buffer. """ def cmd_rset(args): """RESET (RSET) This command specifies that the current mail transaction is to be aborted. Any stored sender, recipients, and mail data must be discarded, and all buffers and state tables cleared. The receiver must send an OK reply. """ def cmd_vrfy(args): """VERIFY (VRFY) This command asks the receiver to confirm that the argument identifies a user. If it is a user name, the full name of the user (if known) and the fully specified mailbox are returned. This command has no effect on any of the reverse-path buffer, the forward-path buffer, or the mail data buffer. """ === Added File Zope3/lib/python/Zope/Server/SMTP/SMTPServer.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: SMTPServer.py,v 1.1.2.1 2002/04/05 17:19:53 srichter Exp $ """ import asyncore from FTPServerChannel import FTPServerChannel from Zope.Server.ServerBase import ServerBase from Zope.Server.Counter import Counter from Zope.Server.VFS.UnixFileSystem import UnixFileSystem from Zope.Server.Authentication.DictionaryAuthentication import \ DictionaryAuthentication class SMTPServer(ServerBase): """Generic FTP Server""" channel_class = SMTPServerChannel SERVER_IDENT = 'Zope.Server.SMTPServer' relay_smtp_server_name = 'mail.cbu.edu' storage = UnixFileSystem('/opt/ZopeMail') auth_source = DictionaryAuthentication({'foo': 'bar'}) refresh_relay_rules = 1 relay_rules = [] allow_unknown_receiver_default = 1 allow_unknown_sender_default = 1 admin_account = "" default_local_domain = "" unknown_account = "" ip_address_range = None def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1, hit_log=None, verbose=0, socket_map=None): super(SMTPServer, self).__init__(ip, port, task_dispatcher, adj, start, hit_log, verbose, socket_map) self.counter = Counter() if __name__ == '__main__': from Zope.Server.TaskThreads import ThreadedTaskDispatcher td = ThreadedTaskDispatcher() td.setThreadCount(4) SMTPServer('', 8025, task_dispatcher=td) try: while 1: asyncore.poll(5) print 'active channels:', SMTPServerChannel.active_channels except KeyboardInterrupt: print 'shutting down...' td.shutdown() === Added File Zope3/lib/python/Zope/Server/SMTP/SMTPServerChannel.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: SMTPServerChannel.py,v 1.1.2.1 2002/04/05 17:19:53 srichter Exp $ """ from Zope.Server.ServerChannelBase import ServerChannelBase from SMTPimport status_msgs from SMTPTask import SMTPTask from ISMTPCommandHandler import ISMTPCommandHandler class SMTPServerChannel(LineServerChannel): """The SMTP Server Channel represents a connection to a particular client. We can therefore store information here.""" __implements__ = ISMTPCommandHandler # Commands that are run in a separate thread thread_commands = ('cmd_mail', 'cmd_vrfy', 'cmd_data') # Define the authentication status of the channel. Note that only the # "special commands" can be executed without having authenticated. authenticated = 1 # Define the reply code for an unrecognized command unknown_reply = (500, 0) # Define the status messages status_messages = status_msgs def __init__(self, server, conn, addr, adj=None, socket_map=None): super(SMTPServerChannel, self).__init__(server, conn, addr, adj, socket_map) self._sender_host = None self.terminated = 0 self.receiving_data = 0 self.reply(220, 0, self.server.server_name) ############################################################ # Implementation methods for interface # Zope.Server.SMTP.ISMTPCommandHandler def cmd_data(self, args): 'See Zope.Server.SMTP.ISMTPCommandHandler.ISMTPCommandHandler' if not self.is_local_connection and not self.canSendMessage(): self.terminated = 1 return self.reply(551) self.receiving_data = 1 self.reply(354) def cmd_ehlo(self, args): 'See Zope.Server.SMTP.ISMTPCommandHandler.ISMTPCommandHandler' return cmd_helo(args) def cmd_expn(self, args): 'See Zope.Server.SMTP.ISMTPCommandHandler.ISMTPCommandHandler' self.reply(550) def cmd_helo(self, args): 'See Zope.Server.SMTP.ISMTPCommandHandler.ISMTPCommandHandler' args = args.strip() if len(args): self.sender_host = args self.reply(250) def cmd_help(self, args): 'See Zope.Server.SMTP.ISMTPCommandHandler.ISMTPCommandHandler' self.reply(214) def cmd_mail(self, args): 'See Zope.Server.SMTP.ISMTPCommandHandler.ISMTPCommandHandler' args = args.split() if args[1].upper() != 'FROM:': return self.reply(501) if not self.isSenderAllowed(args[2]): return self.reply(551) self.message["FROM"] = request[2] self.reply(250) def cmd_noop(self, args): 'See Zope.Server.SMTP.ISMTPCommandHandler.ISMTPCommandHandler' self.reply(250) def cmd_quit(self, args): 'See Zope.Server.SMTP.ISMTPCommandHandler.ISMTPCommandHandler' self.reply(221) self.close_when_done() def cmd_rcpt(self, args): 'See Zope.Server.SMTP.ISMTPCommandHandler.ISMTPCommandHandler' args = args.split() if args[1].upper() != 'TO:': return self.reply(501) if not self.isReceiverAllowed(args[2]): return self.reply(551) self.message["TO"].append(request[2]) self.reply(250) def cmd_rset(self, args): 'See Zope.Server.SMTP.ISMTPCommandHandler.ISMTPCommandHandler' self.resetMessage() self.reply(250) def cmd_vrfy(self, args): 'See Zope.Server.SMTP.ISMTPCommandHandler.ISMTPCommandHandler' name = self.getExpandedName(args) if name: self.reply(250, 1, name) else: self.reply(550, 1) # ############################################################ def resetMessage(self): self.message = {'FROM':None, 'TO': [], 'MSG': []} def getExpandedName(self,name): # THIS HAS NOT YET BEEN TESTED :) if name[0] == '<' and name[-1] == '>': name = name[1:-1] # step 1: look up address directly" result = self.getUID() if result: userid = result[0][0] # ok, its a directly known address friendlyname = self.getFriendlyName(result) if friendlyname: return "%s <%s>" % (friendlyname[0][0], name) print "Warning, didn't find user for id %s" % str(userid) return "<%s>" % name # step 2: look up aliases result = 1 # maildb.DbQuery("SELECT AID FROM aliases WHERE NAME='%s'" % name) if result: addressid = result result = '2', 'srichter@cbu.edu' # maildb.DbQuery("SELECT UID,MAIL FROM addresses # WHERE ID=%d" % addressid) if result: userid = result[0][0] mailaddr = result[0][1] # ok, its a directly known address friendlyname = 'Stephan Richter' # maildb.DbQuery("SELECT FRIENDLYNAME FROM users # WHERE ID=%d" % userid) if friendlyname: return "%s <%s>" % (friendlyname,mailaddr) print "Warning, didn't find user for id %s" % str(userid) return "%s <%s>" % (name,mailaddr) def isReceiverAllowed(self,address): global RELAY_RULES, ALLOW_UNKNOWN_RECEIVER_DEFAULT if address[0] == '<' or address[-1] == '>': address = address[1:-1] # New in Version 0.4: If the sender is a local address, it must # come from a local IP, otherwise access is denied if (self.strict_relay_test and self.ip_address_range and not self.is_local_connection): is_local_address = 1 # maildb.DbQuery("SELECT COUNT(*) FROM addresses WHERE "\ # "UID<>-1 AND MAIL='%s'" % # maildb.EscapeSqlString(address))[0] if is_local_address[0]: print "Target address '%s' is local." % address else: print "Attempt to send message from '%s' to '%s' denied." % ( str(self.message["FROM"]), address) self.SendAdminMail(None, """Warning, an attempt has been made to send a message from '%s' to '%s'. The access has been denied.""" % (str(self.message["FROM"]), address)) return 0 self.RefreshRelayRules() # set default allow = ALLOW_UNKNOWN_RECEIVER_DEFAULT # enumerate all rules. they are priority-sorted, with higher # priorities comming later for rule in RELAY_RULES: # if this rule applies to the given address if fnmatch.fnmatch(address,rule[0]): # let it apply. further rules will modify this. allow = rule[2] print "Rule '%s' applies to '%s': %s receiving." % ( rule,address,allow and "allow" or "deny") if not allow: # self.SendAdminMail(None, """Warning, an attempt # has been made to send a message from '%s' to # '%s'. The domain '%s' is disallowed on this # host. The access has been denied.""" % # (str(self.message["FROM"]), address, rule)) return 0 return allow def isSenderAllowed(self,address): if address[0] == '<' or address[-1] == '>': address = address[1:-1] # New in Version 0.4: If the sender is a local address, it must # come from a local IP, otherwise access is denied if (self.strict_relay_test and self.ip_address_range and not self.is_local_connection): # XXX: Is local address? is_local_address = 1 # self.isLocalAccess() if is_local_address[0]: print ("Error, sender '%s' has a local e-mail address, but " + "comes from a remote IP '%s'" % ( address, self.ip_address_string)) # self.SendAdminMail(None, """Warning, an attempt has # been made to send a message from IP '%s' with the # local e-mail address '%s'. The access has been # denied.""" % (self.ip_address_string, address)) return 0 else: # print "Sender '%s' is not a known local address, so # use of remote IP "\ "'%s' is possible." % (address, # self.ip_address_string) pass self.refreshRelayRules() # set default allow = self.allow_unknown_sender_default # enumerate all rules. they are priority-sorted, with higher # priorities comming later for rule in self.relay_rules: # if this rule applies to the given address if fnmatch.fnmatch(address,rule[0]): # let it apply. further rules will modify this. allow = rule[1] # print "Rule '%s' applies to '%s': %s sending." % # (rule,address,allow and "allow" or "deny") if not allow: # self.SendAdminMail(None, """Warning, an attempt # has been made to send a message from '%s' to # '%s'. The domain '%s' is disallowed on this # host. The access has been denied.""" % # (str(self.message["FROM"]), address, rule)) return 0 return allow def refreshRelayRules(self): if self.refresh_relay_rules or not self.relay_rules: self.relay_rules = maildb.DbQuery("SELECT PATTERN,\ CANSEND, CANRECEIVE FROM relayrules ORDER BY PRIO") def canSendMessage(self): # step 1: test if this is a message from a local user, or from # an outside user sender_id, sender_cansend = self.getAddressID(self.message['FROM']) # if the sender is a local mailbox, the message can be sent if sender_id and sender_cansend: return 1 # it is a message from somebody outside can_process_message, remote_receivers = 1, 0 for receiver in self.message['TO']: rid, rcs = self.getAddressID(receiver) if self.strict_relay_test: # if strict testing is enabled, ALL receivers must be local if not rid: return 0 continue elif rid: # if strict testing is disabled, at least one reciever # must be local return 1 remote_receivers = 1 if remote_receivers: can_process_message = 0 assert (not self.strict_relay_test) return can_process_message def getAddressID(self,address): if address[0] == '<' or address[-1] == '>': address = address[1:-1] # GK wegen der DVG if address.find("'") >= 0: address = maildb.EscapeSqlString(address) row = maildb.DbQuery("SELECT UID FROM addresses WHERE MAIL='%s'" % address ) if len(row): if row[0][0] == -1: # this is an imported address to validate, but not to # indicate a local user return (0,0) return (row[0][0],1) if DomainOfAddress(address).lower() == DEFAULT_LOCAL_DOMAIN.lower(): row = maildb.DbQuery("SELECT UID FROM addresses WHERE MAIL='%s'" % UNKNOWN_ACCOUNT) if len(row): return (row[0][0],1) return (0,0) === Added File Zope3/lib/python/Zope/Server/SMTP/SMTPSpamFilter.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: SMTPSpamFilter.py,v 1.1.2.1 2002/04/05 17:19:53 srichter Exp $ """ import spam_data def isSpamSubjectLine(subject): subject = subject.lower() reload(spam_data) weight = float(reduce(lambda x,y:x+y,map(ord,subject)))/len(subject) if weight > 128: print "Weight %.2f indicates spam mail." % weight return 1 for token_tuple in spam_data.subject_tokens: found = 0 for token in token_tuple: if subject.find(token) >= 0: found += 1 if found == len(token_tuple): print "Tokens '%s' indicate spam mail." % str(token_tuple).strip() return 1 tokens = subject.split() try: isdigit = int(tokens[-1]) isdigit = len(tokens[-1]) > 3 except: isdigit = 0 if isdigit: print "Integer as last token indicates spam mail." return 1 return 0 def checkSpamMail(lines): index = -1 for line in lines: index += 1 if line.strip() == "": break s = line.find(':') if s < 0: continue tokens = (line[:s],line[s:]) keyword = tokens[0].lower() if keyword == 'subject': if IsSpamSubjectLine(tokens[1]): print "SPAM SUBJECT: "+tokens[1].strip() new_subject_line = line[:9] + "[SPAM] " + line[9:] lines[index] = new_subject_line else: print "NOT SPAM SUBJECT: "+ tokens[1].strip() break return lines === Added File Zope3/lib/python/Zope/Server/SMTP/SMTPStatusMessages.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: SMTPStatusMessages.py,v 1.1.2.1 2002/04/05 17:19:53 srichter Exp $ """ status_msgs = { 214: ("Help not available. RTFM!",), 220: ("Zope Service ready",), 221: ("SHICKS! Service closing transmission channel",), 250: ('OK', '%s', # Username and location 'Zope 3.0 ready.', # = 'SIZE', # | 'VRFY', # | 'HELP',), # +--> These are all for HELO 251: ("User not local; will forward to ",), 354: ("Start mail input; end with .",), 421: ("Zope Service not available",), 450: ("Requested mail action not taken: mailbox unavailable",), 500: ('Syntax error, command unrecognized"',), 501: ("Syntax error in parameters or arguments",), 502: ("Command not implemented",), 503: (" Bad sequence of commands",), 504: ("Command parameter not implemented",), 550: (" Requested action not taken: mailbox unknown", 'String does not match anything.'), 551: ("ACCESS DENIED.",), 554: ("Transaction failed",), } === Added File Zope3/lib/python/Zope/Server/SMTP/SMTPUtilities.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: SMTPUtilities.py,v 1.1.2.1 2002/04/05 17:19:53 srichter Exp $ """ def getLongIpAddress(ipaddr): """ """ tokens = ipaddr.split(".") if len(tokens) != 4: raise "ERROR, IP-Address '%s' invalid" % ipaddr tokens = map(long,tokens) return ( tokens[0] * (256 * 256 * 256) + tokens[1] * (256 * 256) + tokens[2] * (256) + tokens[3] ) def decodeValidIpRanges(data): """ """ data = data.split(",") for i in xrange(len(data)): item = map(GetLongIpAddress,data[i].split("-")) if len(item) == 1: item.append(item[0]) elif len(item) > 2: raise "ERROR, IP-Addressrange '%s' invalid" % data[i] data[i] = tuple(item) return tuple(data) def domainOfAddress(address): x = address.find('@') if x >= 0: return address[x+1:] return "" def splitMailHeader(s): result = [] startindex = -1 index = 0 while index < len(s): c = s[index] if c == ' ': # ok, split if startindex != -1: result.append(s[startindex:index]) startindex = -1 elif c == ':': # ok, split if startindex != -1: result.append(s[startindex:index+1]) startindex = -1 # ok, split *including* this character elif startindex == -1: startindex = index index += 1 if startindex != -1: result.append(s[startindex:]) return result import spam_data === Added File Zope3/lib/python/Zope/Server/SMTP/SpamData.py === subject_tokens = [ ["!!",], ["!","free"], ["!","your"], ["!","you"], ["hosting"], ["money"], ["business"], ["adult"], ["your","site"], ["-","$"], ["only",":"], ["!","website"], ["advertisement"], ["software","free"],[".","$"],["your","web"],["!","this"],["link"],["search"],["home"],["amateur"], ["more"],["engines"],["!","get"],["cash"],["marketing"],["sex"],["$$"],["!",".."],[".","free"], ["!","software"],["million"],[":","ad"],["accept"],["cards"],["your site"],["webmaster"], ["your","?"],["to","$"],["message"],["scouting"],["get","your"],["live"],["phone"],["!","site"], ["your","free"],["!","now"],["send"],["$","free"],["-",".."],["mlm"],["advertising"],["you","..."], ["your","website"],["!","new"],["$$$"],["....."],["do","you"],["??"],["!","hot"],["you","i"],["offer"], ["your","traffic"],["your","$"],["in","$"],["don't"],["increase"],["know"],["per"],["income"], ["fuckin"],["stock","alert"],["fortune"],["babes","love"],["hardcore"],["hello!"],["christmas"], ["*~*~*"],["equities"],["lesbian"],["huge","cock"],["pussy"],["investment"],["vhs","dvd"], ["growth","potential"],["crazy"],["$$$"],["investor","alert"],["tax","break"],["web","design"], ["geschlecht"],["download"],["dildo"],["yen","market"],["prescription"],["adv:"],["adv."], ["lolitas"],["domain"],["national"],["guide"],["celebrities"],["xxx"],["lawyer"],["great"], ["huge"],["need","help"],["take","hard"],["video"],["interest"],["bulk"],["porn"],["breast"], ["junk"],["holiday"],["merchant"],["anything","anyone"],["alleine?"],["erwachsen"],["tax"], ["iso 9000"],["squirrel"],["attraction"],["..."],["hetero"],["amazing"],["blond"],["debt"], ["believe"],["pocket"],["traffic"],["special","report"],["fellowship"],["stock"],["cigar"], ["abbildung"],["casino"],["urgent"],["info","requested"],["vacation"],["free","fun"], ["nude","pics"],["girls"],["naked"],["this","really","worked"],["sick","shit"]] === Added File Zope3/lib/python/Zope/Server/SMTP/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.2.1 2002/04/05 17:19:53 srichter Exp $ """ From shane@cvs.zope.org Fri Apr 5 22:46:04 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 5 Apr 2002 17:46:04 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server - MaxSockets.py:1.1.2.1 Adjustments.py:1.1.2.4.2.4 Message-ID: <200204052246.g35Mk4318535@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server In directory cvs.zope.org:/tmp/cvs-serv18521 Modified Files: Tag: Zope3-Server-Branch Adjustments.py Added Files: Tag: Zope3-Server-Branch MaxSockets.py Log Message: Added a copy_bytes adjustment and moved MaxSockets out of the tests subdir, removing the copyright declaration since we might not own the copyright. === Added File Zope3/lib/python/Zope/Server/MaxSockets.py === # Medusa max_sockets module. import socket import select # several factors here we might want to test: # 1) max we can create # 2) max we can bind # 3) max we can listen on # 4) max we can connect def max_server_sockets(): sl = [] while 1: try: s = socket.socket (socket.AF_INET, socket.SOCK_STREAM) s.bind (('',0)) s.listen(5) sl.append (s) except: break num = len(sl) for s in sl: s.close() del sl return num def max_client_sockets(): # make a server socket server = socket.socket (socket.AF_INET, socket.SOCK_STREAM) server.bind (('', 9999)) server.listen (5) sl = [] while 1: try: s = socket.socket (socket.AF_INET, socket.SOCK_STREAM) s.connect (('', 9999)) conn, addr = server.accept() sl.append ((s,conn)) except: break num = len(sl) for s,c in sl: s.close() c.close() del sl return num def max_select_sockets(): sl = [] while 1: try: num = len(sl) for i in range(1 + len(sl) * 0.05): # Increase exponentially. s = socket.socket (socket.AF_INET, socket.SOCK_STREAM) s.bind (('',0)) s.listen(5) sl.append (s) select.select(sl,[],[],0) except: break for s in sl: s.close() del sl return num === Zope3/lib/python/Zope/Server/Adjustments.py 1.1.2.4.2.3 => 1.1.2.4.2.4 === # FOR A PARTICULAR PURPOSE. -from tests import MaxSockets +import MaxSockets class Adjustments: @@ -21,6 +21,9 @@ # send_bytes is the number of bytes to send to socket.send(). send_bytes = 8192 + # copy_bytes is the number of bytes to copy from one file to another. + copy_bytes = 65536 + # Create a tempfile if the pending output data gets larger # than outbuf_overflow. With RAM so cheap, this probably # ought to be set to the 16-32 MB range (circa 2001) for @@ -41,7 +44,7 @@ # Maximum seconds to leave an inactive connection open. channel_timeout = 900 - # Boolean: turn off to ignore premature client disconnects. + # Boolean: turn off to not log premature client disconnects. log_socket_errors = 1 From shane@cvs.zope.org Fri Apr 5 22:46:04 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 5 Apr 2002 17:46:04 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/tests - MaxSockets.py:NONE Message-ID: <200204052246.g35Mk4B18536@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/tests In directory cvs.zope.org:/tmp/cvs-serv18521/tests Removed Files: Tag: Zope3-Server-Branch MaxSockets.py Log Message: Added a copy_bytes adjustment and moved MaxSockets out of the tests subdir, removing the copyright declaration since we might not own the copyright. === Removed File Zope3/lib/python/Zope/Server/tests/MaxSockets.py === From shane@cvs.zope.org Fri Apr 5 22:46:42 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 5 Apr 2002 17:46:42 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - FileProducer.py:NONE Message-ID: <200204052246.g35Mkgi18649@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv18608/FTP Removed Files: Tag: Zope3-Server-Branch FileProducer.py Log Message: These two modules are not needed any more. === Removed File Zope3/lib/python/Zope/Server/FTP/FileProducer.py === From shane@cvs.zope.org Fri Apr 5 22:46:41 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 5 Apr 2002 17:46:41 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server - Counter.py:NONE Message-ID: <200204052246.g35Mkfc18641@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server In directory cvs.zope.org:/tmp/cvs-serv18608 Removed Files: Tag: Zope3-Server-Branch Counter.py Log Message: These two modules are not needed any more. === Removed File Zope3/lib/python/Zope/Server/Counter.py === From shane@cvs.zope.org Fri Apr 5 22:50:08 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 5 Apr 2002 17:50:08 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server - DualModeChannel.py:1.1.2.4.2.5 Message-ID: <200204052250.g35Mo8w20807@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server In directory cvs.zope.org:/tmp/cvs-serv20800 Modified Files: Tag: Zope3-Server-Branch DualModeChannel.py Log Message: Simplified the DualModeChannel constructor, since the server attribute is not needed. Made sure data is written only when the socket is connected. Fixed close_when_done(), which was inexplicably pulling the async thread trigger in async mode. === Zope3/lib/python/Zope/Server/DualModeChannel.py 1.1.2.4.2.4 => 1.1.2.4.2.5 === async_mode = 1 - def __init__(self, server, conn, addr, adj=None, socket_map=None): - self.server = server + def __init__(self, conn, addr, adj=None, socket_map=None): self.addr = addr if adj is None: adj = default_adj @@ -215,7 +214,7 @@ Returns 1 if some data was sent.""" outbuf = self.outbuf - if outbuf: + if outbuf and self.connected: chunk = outbuf.get(self.adj.send_bytes) num_sent = self.send(chunk) if num_sent: @@ -224,19 +223,16 @@ return 0 def close_when_done(self): - if self.async_mode: - self.will_close = 1 - self.pull_trigger() + # We might be able close immediately. + while self._flush_some(): + pass + if not self.outbuf: + # Quick exit. + self.close() else: - # We might be able close immediately. - while self._flush_some(): - pass - if not self.outbuf: - # Quick exit. - self.close() - else: - # Wait until outbuf is flushed. - self.will_close = 1 + # Wait until outbuf is flushed. + self.will_close = 1 + if not self.async_mode: self.async_mode = 1 self.pull_trigger() @@ -256,7 +252,7 @@ __implements__ = asyncore.dispatcher.__implements__ - def __init__(self, server, conn, addr, adj=None, socket_map=None): + def __init__(self, conn, addr, adj=None, socket_map=None): global allocate_lock if allocate_lock is None: from thread import allocate_lock @@ -267,7 +263,7 @@ self._writelock_acquire = writelock.acquire self._writelock_release = writelock.release self._writelock_locked = writelock.locked - DualModeChannel.__init__(self, server, conn, addr, adj, socket_map) + DualModeChannel.__init__(self, conn, addr, adj, socket_map) # # ASYNCHRONOUS METHODS From shane@cvs.zope.org Fri Apr 5 22:51:46 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 5 Apr 2002 17:51:46 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server - ServerChannelBase.py:1.1.2.5 Message-ID: <200204052251.g35Mpkb21460@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server In directory cvs.zope.org:/tmp/cvs-serv21444 Modified Files: Tag: Zope3-Server-Branch ServerChannelBase.py Log Message: Updated to match DualModeChannel constructor, made sure active_channel attributes in instances are ignored since they would not make sense, and exposed start_task() as a method. === Zope3/lib/python/Zope/Server/ServerChannelBase.py 1.1.2.4 => 1.1.2.5 === def __init__(self, server, conn, addr, adj=None, socket_map=None): - ChannelBaseClass.__init__(self, server, conn, addr, adj, socket_map) + ChannelBaseClass.__init__(self, conn, addr, adj, socket_map) + self.server = server self.last_activity = t = self.creation_time self.check_maintenance(t) @@ -70,14 +71,14 @@ """This hook keeps track of opened HTTP channels. """ ChannelBaseClass.add_channel(self, map) - self.active_channels[self._fileno] = self + self.__class__.active_channels[self._fileno] = self def del_channel(self, map=None): """This hook keeps track of closed HTTP channels. """ ChannelBaseClass.del_channel(self, map) - ac = self.active_channels + ac = self.__class__.active_channels fd = self._fileno if ac.has_key(fd): del ac[fd] @@ -86,9 +87,10 @@ def check_maintenance(self, now): """Performs maintenance if necessary. """ - if now < self.next_channel_cleanup[0]: + ncc = self.__class__.next_channel_cleanup + if now < ncc[0]: return - self.next_channel_cleanup[0] = now + self.adj.cleanup_interval + ncc[0] = now + self.adj.cleanup_interval self.maintenance() @@ -105,11 +107,9 @@ """ now = time.time() cutoff = now - self.adj.channel_timeout - class_ = self.__class__ # Kill only channels of our own class. for channel in self.active_channels.values(): if (channel is not self and not channel.running_tasks and - channel.last_activity < cutoff and - isinstance(channel, class_)): + channel.last_activity < cutoff): channel.close() @@ -158,9 +158,17 @@ if do_now: task = self.process_request(req) if task is not None: - self.running_tasks = 1 - self.set_sync() - self.server.addTask(task) + self.start_task(task) + + + def start_task(self, task): + """Starts the given task. + + *** For thread safety, this should only be called from the main + (async) thread. ***""" + self.running_tasks = 1 + self.set_sync() + self.server.addTask(task) def handle_error(self): @@ -209,7 +217,7 @@ finally: running_lock.release() - if req: + if req is not None: task = self.process_request(req) if task is not None: # Add the new task. It will service the queue. From shane@cvs.zope.org Fri Apr 5 22:52:13 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 5 Apr 2002 17:52:13 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/HTTP - HTTPServer.py:1.1.2.3 Message-ID: <200204052252.g35MqDc21593@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/HTTP In directory cvs.zope.org:/tmp/cvs-serv21582 Modified Files: Tag: Zope3-Server-Branch HTTPServer.py Log Message: Forgotten import === Zope3/lib/python/Zope/Server/HTTP/HTTPServer.py 1.1.2.2 => 1.1.2.3 === try: + import asyncore while 1: asyncore.poll(5) From shane@cvs.zope.org Fri Apr 5 22:53:04 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 5 Apr 2002 17:53:04 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/LineReceiver - LineServerChannel.py:1.1.2.4 Message-ID: <200204052253.g35Mr4121971@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/LineReceiver In directory cvs.zope.org:/tmp/cvs-serv21961 Modified Files: Tag: Zope3-Server-Branch LineServerChannel.py Log Message: Made returning None explicit and fixed the catch-all response. === Zope3/lib/python/Zope/Server/LineReceiver/LineServerChannel.py 1.1.2.3 => 1.1.2.4 === else: self.reply(self.unknown_reply, cmd.upper()) + return None def reply(self, code, args=(), flush=1): """ """ try: - msg = self.status_messages[code] %args + msg = self.status_messages[code] % args except: - msg = '500 Unknown Response: %i.' %code + msg = '500 Unknown Response: %s.' % repr(code) self.write('%s\r\n' %msg) From shane@cvs.zope.org Fri Apr 5 22:53:55 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 5 Apr 2002 17:53:55 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS/tests - testOSFileSystem.py:1.1.2.5 Message-ID: <200204052253.g35MrtV22507@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS/tests In directory cvs.zope.org:/tmp/cvs-serv22490/VFS/tests Modified Files: Tag: Zope3-Server-Branch testOSFileSystem.py Log Message: listdir() no longer returns a producer, just a string or stream. === Zope3/lib/python/Zope/Server/VFS/tests/testOSFileSystem.py 1.1.2.4 => 1.1.2.5 === path = os.path.join(self.root, 'foo') open(path, 'w').write('test') - self.assertEqual(self.filesystem.listdir('/', 0).more(), + self.assertEqual(self.filesystem.listdir('/', 0), 'foo\r\n') os.remove(path) From shane@cvs.zope.org Fri Apr 5 22:53:55 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 5 Apr 2002 17:53:55 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - OSFileSystem.py:1.1.2.11 PublisherFileSystem.py:1.1.2.3 Message-ID: <200204052253.g35Mrta22505@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv22490/VFS Modified Files: Tag: Zope3-Server-Branch OSFileSystem.py PublisherFileSystem.py Log Message: listdir() no longer returns a producer, just a string or stream. === Zope3/lib/python/Zope/Server/VFS/OSFileSystem.py 1.1.2.10 => 1.1.2.11 === import time -from ListProducer import ListProducer - from IReadFileSystem import IReadFileSystem from IWriteFileSystem import IWriteFileSystem @@ -73,22 +71,20 @@ ld = os.listdir(p) ld.sort() if not long: - return ListProducer (ld, 0, None) + result = ld else: - try: - result = [] - for file in ld: - path = self.path_module.join(p, file) - stat = safe_stat(path) - if stat is not None: - result.append((file, safe_stat(path))) - finally: - return ListProducer(result, 1, self.longify) + result = [] + for file in ld: + path = self.path_module.join(p, file) + stat = safe_stat(path) + if stat is not None: + result.append(self.longify(file, safe_stat(path))) + return '\r\n'.join(result) + '\r\n' - def longify(self, (path, stat_info)): + def longify(self, path, stat_info): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' - return unix_longify (path, stat_info) + return unix_longify(path, stat_info) def open(self, path, mode): === Zope3/lib/python/Zope/Server/VFS/PublisherFileSystem.py 1.1.2.2 => 1.1.2.3 === ld.sort() if not long: - return ListProducer(ld, 0, None) + result = ld else: - return ListProducer(result, 1, self.longify) + result = map(self.longify, ld) + return '\r\n'.join(result) + '\r\n' def longify(self, (path, stat_info)): From shane@cvs.zope.org Fri Apr 5 22:54:38 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 5 Apr 2002 17:54:38 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - FTPServer.py:1.1.2.8 Message-ID: <200204052254.g35Mscx23463@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv23383 Modified Files: Tag: Zope3-Server-Branch FTPServer.py Log Message: No need for the statistics counters for now. === Zope3/lib/python/Zope/Server/FTP/FTPServer.py 1.1.2.7 => 1.1.2.8 === from FTPServerChannel import FTPServerChannel from Zope.Server.ServerBase import ServerBase -from Zope.Server.Counter import Counter from Zope.Server.VFS.UnixFileSystem import UnixFileSystem from Zope.Server.Authentication.DictionaryAuthentication import \ @@ -42,13 +41,13 @@ verbose, socket_map) # statistics - self.total_sessions = Counter() - self.closed_sessions = Counter() - self.total_files_out = Counter() - self.total_files_in = Counter() - self.total_bytes_out = Counter() - self.total_bytes_in = Counter() - self.total_exceptions = Counter() +## self.total_sessions = 0 +## self.closed_sessions = 0 +## self.total_files_out = 0 +## self.total_files_in = 0 +## self.total_bytes_out = 0 +## self.total_bytes_in = 0 +## self.total_exceptions = 0 if __name__ == '__main__': From shane@cvs.zope.org Fri Apr 5 23:07:17 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 5 Apr 2002 18:07:17 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - FTPStatusMessages.py:1.1.2.7 Message-ID: <200204052307.g35N7H028425@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv28407 Modified Files: Tag: Zope3-Server-Branch FTPStatusMessages.py Log Message: Minor cleanup of status messages. === Zope3/lib/python/Zope/Server/FTP/FTPStatusMessages.py 1.1.2.6 => 1.1.2.7 === 'STRU_OK' : '200 STRU F Ok.', 'MODE_OK' : '200 MODE S Ok.', - 'FILE_DATE' : '213 %4d%02d%02d%02d%02d%02d', + 'FILE_DATE' : '213 %4d%02d%02d%02d%02d%02d', 'FILE_SIZE' : '213 %d Bytes', 'HELP_START' : '214-The following commands are recognized', 'HELP_END' : '214 Help done.', @@ -37,7 +37,7 @@ 'LOGIN_SUCCESS' : '230 Login Successful.', 'SUCCESS_250' : '250 %s command successful.', 'SUCCESS_257' : '257 %s command successful.', - 'ALREADY_CURRENT' : "257 '%s' is the current directory.", + 'ALREADY_CURRENT' : '257 "%s" is the current directory.', 'PASS_REQUIRED' : '331 Password required', 'RESTART_TRANSFER' : '350 Restarting at %d. Send STORE or ' 'RETRIEVE to initiate transfer.', @@ -53,9 +53,9 @@ 'LOGIN_REQUIRED' : '530 Please log in with USER and PASS', 'LOGIN_MISMATCH' : '530 The username and password do not match.', 'ERR_NO_LIST' : '550 Could not list directory: %s', - 'ERR_NO_DIR' : '550 %s: No such directory.', - 'ERR_NO_FILE' : '550 %s: No such file.', - 'ERR_IS_NOT_FILE' : '550 %s: Is not a file', + 'ERR_NO_DIR' : '550 "%s": No such directory.', + 'ERR_NO_FILE' : '550 "%s": No such file.', + 'ERR_IS_NOT_FILE' : '550 "%s": Is not a file', 'ERR_CREATE_FILE' : '550 Error creating file.', 'ERR_CREATE_DIR' : '550 Error creating directory.', 'ERR_DELETE_FILE' : '550 Error deleting file.', @@ -63,7 +63,7 @@ 'ERR_OPEN_READ' : '553 Could not open file for reading: %s', 'ERR_OPEN_WRITE' : '553 Could not open file for writing: %s', 'ERR_RESTART_STOR' : '553 Restart on STOR not yet supported', - 'ERR_RENAME' : '560 Could not rename %s to %s.', + 'ERR_RENAME' : '560 Could not rename "%s" to "%s".', 'ERR_RNFR_SOURCE' : '560 No source filename specify. Call RNFR first.', } From shane@cvs.zope.org Fri Apr 5 23:09:14 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 5 Apr 2002 18:09:14 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - FTPServerChannel.py:1.1.2.14 RecvChannel.py:1.1.2.5 XmitChannel.py:1.1.2.4 Message-ID: <200204052309.g35N9ES29482@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv28562 Modified Files: Tag: Zope3-Server-Branch FTPServerChannel.py RecvChannel.py XmitChannel.py Log Message: Primarily made sure file transfers don't span threads, while avoiding blocking the application and flushing buffers as quickly as possible. Fixed bugs and refactored some. === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.13 => 1.1.2.14 === from Zope.Server.LineReceiver.LineServerChannel import LineServerChannel from FTPStatusMessages import status_msgs -from FileProducer import FileProducer from IFTPCommandHandler import IFTPCommandHandler from PassiveAcceptor import PassiveAcceptor @@ -74,13 +73,10 @@ self.client_addr = (addr[0], 21) - self.active_channels = {} # Class-specific channel tracker - self.next_channel_cleanup = [0] # Class-specific cleanup time - self.passive_acceptor = None self.client_dc = None - self.transfer_mode = 'i' # Use binary by default + self.transfer_mode = 'a' # Have to default to ASCII :-| self.passive_mode = 0 self.cwd = '/' self._rnfr = None @@ -104,7 +100,7 @@ def cmd_appe (self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' - return self.cmd_stor(args, 'ab') + return self.cmd_stor(args, 'a') def cmd_cdup(self, args): @@ -150,19 +146,21 @@ self.reply('HELP_END') - def cmd_list(self, args): + def cmd_list(self, args, long=1): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' args = args.split() try: - producer = self.getDirectoryList(args, 1) + s = self.getDirectoryList(args, long) except os.error, why: - self.reply('ERR_NO_LIST', repr(why)) + self.reply('ERR_NO_LIST', str(why)) return - - self.reply('OPEN_DATA_CONN', self.type_map[self.transfer_mode]) - self.createXmitChannel() - self.client_dc.push_with_producer(producer) - self.client_dc.close_when_done() + try: + self.reply('OPEN_DATA_CONN', self.type_map[self.transfer_mode]) + self.openDataChannel(XmitChannel, s) + finally: + if hasattr(s, 'close'): + # Close the stream. + s.close() def cmd_mdtm(self, args): @@ -202,21 +200,7 @@ def cmd_nlst(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' - # ncftp adds the -FC argument for the user-visible 'nlist' - # command. We could try to emulate ls flags, but not just yet. - args = args.split() - if '-FC' in args: - args.remove('-FC') - try: - producer = self.getDirectoryList(args, 0) - except os.error, why: - self.reply('ERR_NO_LIST', repr(why)) - return - - self.createXmitChannel() - self.client_dc.push_with_producer(producer) - self.client_dc.close_when_done() - self.reply('OPEN_DATA_CONN', (self.type_map[self.transfer_mode],)) + self.cmd_list(args, 0) def cmd_noop(self, args): @@ -267,7 +251,7 @@ def cmd_pwd(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' - self.reply('SUCCESS_257', self.cwd) + self.reply('ALREADY_CURRENT', self.cwd) def cmd_quit(self, args): @@ -284,34 +268,34 @@ path = self._generatePath(args) if not self.server.filesystem.isfile(path): - #self.log_info ('checking %s' % file) - self.reply(550, 2, path) + self.reply('ERR_IS_NOT_FILE', path) else: try: - # FIXME: for some reason, 'rt' isn't working on win95 - mode = 'r'+self.type_mode_map[self.transfer_mode] + mode = 'r' + self.type_mode_map[self.transfer_mode] fd = self.server.filesystem.open(path, mode) except IOError, why: - self.reply('ERR_OPEN_READ', repre(why)) + self.reply('ERR_OPEN_READ', str(why)) return - self.reply('OPEN_CONN', - (self.type_map[self.transfer_mode], path) ) - self.createXmitChannel() - - if self.restart_position: - # try to position the file as requested, but - # give up silently on failure (the 'file object' - # may not support seek()) - try: - fd.seek(self.restart_position) - except: - pass - self.restart_position = 0 - - self.client_dc.push_with_producer ( - FileProducer(self.server, self.client_dc, fd) - ) - self.client_dc.close_when_done() + try: + self.reply('OPEN_CONN', + (self.type_map[self.transfer_mode], path) ) + + if self.restart_position: + # try to position the file as requested, but + # give up silently on failure (the 'file object' + # may not support seek()) + try: + fd.seek(self.restart_position) + except: + pass + self.restart_position = 0 + + self.openDataChannel(XmitChannel, fd) + + finally: + if hasattr(fd, 'close'): + # Close the stream. + fd.close() def cmd_rest(self, args): @@ -370,7 +354,7 @@ self.server.filesystem.stat(path)[stat.ST_SIZE]) - def cmd_stor(self, args, mode='wb'): + def cmd_stor(self, args, write_mode='w'): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' if not args: self.reply('CMD_UNKNOWN', 'STOR') @@ -381,14 +365,44 @@ restart_position = 0 self.reply('ERR_RESTART_STOR') return - # todo: handle that type flag + mode = write_mode + self.type_mode_map[self.transfer_mode] + try: - fd = self.server.filesystem.open(args, mode) + # Optionally verify the file can be opened, + # but don't open it yet. The actually write + # should be transactional without holding up the + # application. + fs = self.server.filesystem + if hasattr(fs, 'check_open'): + fs.check_open(path, mode) except IOError, why: - self.reply('ERR_OPEN_WRITE', repr(why)) + self.reply('ERR_OPEN_WRITE', str(why)) return self.reply('OPEN_CONN', (self.type_map[self.transfer_mode], file) ) - self.createRecvChannel(fd) + self.openDataChannel(RecvChannel, (path, mode)) + + + def finishedRecv(self, buffer, path, mode): + """Called by RecvChannel when the transfer is finished.""" + # Always called in a task. + try: + outfile = self.server.filesystem.open(path, mode) + try: + copy_bytes = self.adj.copy_bytes + while 1: + data = buffer.get(copy_bytes) + if not data: + break + buffer.skip(len(data), 1) + outfile.write(data) + finally: + print 'cp4' + outfile.close() + print 'cp5' + except IOError, why: + self.reply('ERR_OPEN_WRITE', str(why)) + return + self.reply('TRANS_SUCCESS') def cmd_stru(self, args): @@ -418,8 +432,7 @@ self.reply('WRONG_BYTE_SIZE') else: - if t == 'a': - self.transfer_mode = t + self.transfer_mode = t self.reply('TYPE_SET_OK', self.type_map[t]) @@ -454,7 +467,7 @@ def listdir (self, path, long=0): - """returns a producer""" + """returns a string or stream""" return self.server.filesystem.listdir(path, long) @@ -476,66 +489,33 @@ return self.listdir(dir, long) - def createXmitChannel(self): - """In PASV mode, the connection may or may _not_ have been - made yet. [although in most cases it is... FTP Explorer - being the only exception I've yet seen]. This gets - somewhat confusing because things may happen in any - order... - """ + def openDataChannel(self, class_, *args): pa = self.passive_acceptor if pa: + # PASV mode. if pa.ready: # a connection has already been made. - conn, addr = self.passive_acceptor.ready - cdc = XmitChannel(self, addr) - cdc.set_socket(conn) + conn, addr = pa.ready + cdc = class_(self, addr, *args) + cdc.set_socket (conn) cdc.connected = 1 self.passive_acceptor.close() self.passive_acceptor = None else: # we're still waiting for a connect to the PASV port. - cdc = XmitChannel(self) - + # FTP Explorer is known to do this. + cdc = class_(self, None, *args) else: # not in PASV mode. ip, port = self.client_addr - cdc = XmitChannel(self, self.client_addr) + cdc = class_(self, self.client_addr, *args) cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) if self.bind_local_minus_one: cdc.bind(('', self.server.port - 1)) try: - cdc.connect ((ip, port)) + cdc.connect((ip, port)) except socket.error, why: self.reply(425) self.client_dc = cdc - - # pretty much the same as xmit, but only right on the verge of - # being worth a merge. - def createRecvChannel(self, fd): - pa = self.passive_acceptor - if pa: - if pa.ready: - # a connection has already been made. - conn, addr = pa.ready - cdc = RecvChannel(self, addr, fd) - cdc.set_socket (conn) - cdc.connected = 1 - self.passive_acceptor.close() - self.passive_acceptor = None - else: - # we're still waiting for a connect to the PASV port. - cdc = RecvChannel(self, None, fd) - else: - # not in PASV mode. - ip, port = self.client_addr - cdc = RecvChannel(self, self.client_addr, fd) - cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) - try: - cdc.connect ((ip, port)) - except socket.error, why: - self.reply(425) - - self.client_dc = cdc === Zope3/lib/python/Zope/Server/FTP/RecvChannel.py 1.1.2.4 => 1.1.2.5 === $Id$ """ -import asyncore -from Zope.Server.Counter import Counter +from Zope.Server.ServerChannelBase import ChannelBaseClass +from Zope.Server.Buffers import OverflowableBuffer +from Zope.Server.ITask import ITask -class RecvChannel(asyncore.dispatcher): + +class RecvChannel(ChannelBaseClass): """ """ - def __init__ (self, channel, client_addr, fd): - self.channel = channel + def __init__ (self, cmd_channel, client_addr, finish_args, + adj=None, socket_map=None): + self.cmd_channel = cmd_channel self.client_addr = client_addr - self.fd = fd - asyncore.dispatcher.__init__ (self) - self.bytes_in = Counter() - + self.finish_args = finish_args + ChannelBaseClass.__init__(self, None, None, adj, socket_map) + self.inbuf = OverflowableBuffer(self.adj.inbuf_overflow) - def log (self, *ignore): - pass +## def log (self, *ignore): +## pass + def writable (self): + return 0 def handle_connect (self): pass + def received (self, data): + self.inbuf.append(data) + + def handle_close (self): + c = self.cmd_channel + task = FinishedRecvTask(c, self.inbuf, self.finish_args) + self.close() + self.cmd_channel = None + c.start_task(task) - def writable (self): - return 0 - def recv (*args): - result = apply (asyncore.dispatcher.recv, args) - self = args[0] - self.bytes_in.increment(len(result)) - return result +class FinishedRecvTask: + __implements__ = ITask - buffer_size = 8192 + def __init__(self, cmd_channel, inbuf, args): + self.cmd_channel = cmd_channel + self.inbuf = inbuf + self.args = args - def handle_read (self): - block = self.recv (self.buffer_size) - if block: + ############################################################ + # Implementation methods for interface + # Zope.Server.ITask + + def service(self): + """Called to execute the task. + """ + close_on_finish = 0 + c = self.cmd_channel + try: try: - self.fd.write (block) - except IOError: - self.log_info ('got exception writing block...', 'error') + c.finishedRecv(self.inbuf, *self.args) + except socket.error: + close_on_finish = 1 + if c.adj.log_socket_errors: + raise + finally: + c.end_task(close_on_finish) + + + def cancel(self): + 'See Zope.Server.ITask.ITask' + self.cmd_channel.close_when_done() - def handle_close (self): - s = self.channel.server - s.total_files_in.increment() - s.total_bytes_in.increment(self.bytes_in.as_long()) - self.fd.close() - self.channel.reply('TRANS_SUCCESS') - self.close() + def defer(self): + 'See Zope.Server.ITask.ITask' + pass + + # + ############################################################ + === Zope3/lib/python/Zope/Server/FTP/XmitChannel.py 1.1.2.3 => 1.1.2.4 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -import asynchat - - -class XmitChannel(asynchat.async_chat, object): - - # for an ethernet, you want this to be fairly large, in fact, it - # _must_ be large for performance comparable to an ftpd. [64k] we - # ought to investigate automatically-sized buffers... - ac_out_buffer_size = 16384 - - bytes_out = 0 - - def __init__ (self, channel, client_addr=None): - self.channel = channel - self.client_addr = client_addr - super(XmitChannel, self).__init__() - - - def log (*args): - pass - - - def readable (self): - return not self.connected - - - def writable (self): - return 1 - - - def send (self, data): - result = super(XmitChannel, self).send(data) - self.bytes_out = self.bytes_out + result - return result - - - def handle_error (self): - # usually this is to catch an unexpected disconnect. - # XXX: Helpfule for debugging - import traceback - traceback.print_exc() - self.log_info ('unexpected disconnect on data xmit channel', 'error') - try: - self.close() - except: - pass - - # TODO: there's a better way to do this. we need to be able to - # put 'events' in the producer fifo. to do this cleanly we need - # to reposition the 'producer' fifo as an 'event' fifo. - - # dummy function to suppress warnings caused by some FTP clients - def handle_connect(self): - pass - - - def close (self): - c = self.channel - s = c.server - c.client_dc = None - s.total_files_out.increment() - s.total_bytes_out.increment (self.bytes_out) - if not len(self.producer_fifo): - c.reply('TRANS_SUCCESS') - elif not c.closed: - c.reply('TRANSFER_ABORTED') - del c - del s - del self.channel - asynchat.async_chat.close(self) +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +from Zope.Server.ServerChannelBase import ChannelBaseClass + + +class XmitChannel(ChannelBaseClass): + + def __init__ (self, cmd_channel, client_addr, s, + adj=None, socket_map=None): + self.cmd_channel = cmd_channel + self.client_addr = client_addr + ChannelBaseClass.__init__(self, None, None, adj, socket_map) + # Send the stream and close when finished. + self.writeAll(s) + self.close_when_done() + + def writeAll(self, s): + """Sends a stream or string. + + Returns the number of bytes sent. + """ + sent = 0 + if hasattr(s, 'read'): + # s is a stream. + copy_bytes = self.adj.copy_bytes + while 1: + data = s.read(copy_bytes) + if not data: + break + sent += len(data) + self.write(data) + else: + # s is a string. + sent = len(s) + self.write(s) + return sent + + def readable(self): + return not self.connected + + def handle_connect(self): + pass + + def handle_comm_error(self): + if self.adj.log_socket_errors: + self.handle_error() + else: + self.close() + + def close (self): + c = self.cmd_channel + s = c.server + c.client_dc = None + #s.total_files_out += 1 + #s.total_bytes_out += self.bytes_out + if not len(self.outbuf): + # All data transferred + c.reply('TRANS_SUCCESS') + else: + # Not all data transferred + c.reply('TRANSFER_ABORTED') + del c + del s + del self.cmd_channel + ChannelBaseClass.close(self) + From srichter@cbu.edu Sat Apr 6 19:53:43 2002 From: srichter@cbu.edu (Stephan Richter) Date: Sat, 6 Apr 2002 14:53:43 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP/tests Zope3/lib/python/Zope/Server/FTP/tests - New directory Message-ID: <200204061953.g36JrhZ01558@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP/tests In directory cvs.zope.org:/tmp/cvs-serv1552/tests Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/Server/FTP/tests added to the repository --> Using per-directory sticky tag `Zope3-Server-Branch' === Added directory Zope3/lib/python/Zope/Server/FTP/tests === From srichter@cbu.edu Sat Apr 6 19:57:10 2002 From: srichter@cbu.edu (Stephan Richter) Date: Sat, 6 Apr 2002 14:57:10 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP/tests - __init__.py:1.1.2.1 testFTPServer.py:1.1.2.1 testPublisherServer.py:1.1.2.1 Message-ID: <200204061957.g36JvAb02451@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP/tests In directory cvs.zope.org:/tmp/cvs-serv2221/tests Added Files: Tag: Zope3-Server-Branch __init__.py testFTPServer.py testPublisherServer.py Log Message: Started writing FTP Server tests. Some are fairly easy, but othere are hard, since FTP opens other connections as well. === Added File Zope3/lib/python/Zope/Server/FTP/tests/__init__.py === # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. """ Unit tests for Zope.Server """ === Added File Zope3/lib/python/Zope/Server/FTP/tests/testFTPServer.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: testFTPServer.py,v 1.1.2.1 2002/04/06 19:57:09 srichter Exp $ """ import unittest import tempfile import os from asyncore import socket_map, poll import socket from types import StringType from threading import Thread from Zope.Server.TaskThreads import ThreadedTaskDispatcher from Zope.Server.FTP.FTPServer import FTPServer from Zope.Server.FTP.FTPStatusMessages import status_msgs from Zope.Server.Adjustments import Adjustments from Zope.Server.ITask import ITask from Zope.Server.Authentication.DictionaryAuthentication import \ DictionaryAuthentication import ftplib from time import sleep, time td = ThreadedTaskDispatcher() LOCALHOST = '127.0.0.1' SERVER_PORT = 0 # Set these port numbers to 0 to auto-bind, or CONNECT_TO_PORT = 0 # use specific numbers to inspect using TCPWatch. my_adj = Adjustments() # Reduce overflows to make testing easier. my_adj.outbuf_overflow = 10000 my_adj.inbuf_overflow = 10000 class Tests(unittest.TestCase): def setUp(self): td.setThreadCount(1) self.orig_map_size = len(socket_map) self.root_dir = tempfile.mktemp() os.mkdir(self.root_dir) os.mkdir(os.path.join(self.root_dir, 'test')) self.server = FTPServer(LOCALHOST, SERVER_PORT, self.root_dir, DictionaryAuthentication({'foo': 'bar'}), task_dispatcher=td, adj=my_adj) if CONNECT_TO_PORT == 0: self.port = self.server.socket.getsockname()[1] else: self.port = CONNECT_TO_PORT self.run_loop = 1 self.counter = 0 self.thread = Thread(target=self.loop) self.thread.start() sleep(0.1) # Give the thread some time to start. def tearDown(self): self.run_loop = 0 self.thread.join() td.shutdown() self.server.close() # Make sure all sockets get closed by asyncore normally. timeout = time() + 5 #while 1: # if len(socket_map) == self.orig_map_size: # # Clean! # break # if time() >= timeout: # print 'Leaked a socket: %s' % `socket_map` # break # #self.fail('Leaked a socket: %s' % `socket_map`) # poll(0.1, socket_map) def loop(self): while self.run_loop: self.counter = self.counter + 1 # print 'loop', self.counter poll(0.1, socket_map) def getFTPConnection(self, login=1): ftp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ftp.connect((LOCALHOST, self.port)) result = ftp.recv(10000) self.assertEqual(result, status_msgs['SERVER_READY'] %( 'localhost.localdomain') + '\r\n') if login: ftp.send('USER foo\r\n') self.assertEqual(ftp.recv(1024), status_msgs['PASS_REQUIRED'] +'\r\n') ftp.send('PASS bar\r\n') self.assertEqual(ftp.recv(1024), status_msgs['LOGIN_SUCCESS'] +'\r\n') return ftp def execute(self, commands, login=1): ftp = self.getFTPConnection(login) if type(commands) is StringType: commands = (commands,) for command in commands: ftp.send('%s\r\n' %command) result = ftp.recv(10000) #print result[:-2] self.failUnless(result.endswith('\r\n')) ftp.close() return result[:-2] def testABOR(self): self.assertEqual(self.execute('ABOR', 1), status_msgs['TRANSFER_ABORTED']) #def testABOR(self): def testCDUP(self): self.assertEqual(self.execute(('CWD test', 'CDUP'), 1), status_msgs['SUCCESS_250'] %'CDUP') self.assertEqual(self.execute('CDUP', 1), status_msgs['SUCCESS_250'] %'CDUP') def testCWD(self): self.assertEqual(self.execute('CWD test', 1), status_msgs['SUCCESS_250'] %'CWD') self.assertEqual(self.execute('CWD foo', 1), status_msgs['ERR_NO_DIR'] %'/foo') def testDELE(self): open(os.path.join(self.root_dir, 'foo'), 'w').write('blah') self.assertEqual(self.execute('DELE foo', 1), status_msgs['SUCCESS_250'] %'DELE') self.assertEqual(self.execute('DELE bar', 1), status_msgs['ERR_DELETE_FILE']) self.assertEqual(self.execute('DELE', 1), status_msgs['CMD_UNKNOWN'] %'DELE') def testHELP(self): result = status_msgs['HELP_START'] #+ '\r\n' #result += 'Help goes here somewhen.\r\n' #result += status_msgs['HELP_END'] self.assertEqual(self.execute('HELP', 1), result) def testLIST(self): path = os.path.join(self.root_dir, 'foo') result = "[Errno 2] No such file or directory: '%s'" %path self.assertEqual(self.execute('LIST /foo', 1), status_msgs['ERR_NO_LIST'] %result) self.assertEqual(self.execute('LIST', 1), status_msgs['SUCCESS_200'] %'NOOP') def testNOOP(self): self.assertEqual(self.execute('NOOP', 0), status_msgs['SUCCESS_200'] %'NOOP') self.assertEqual(self.execute('NOOP', 1), status_msgs['SUCCESS_200'] %'NOOP') def testPASS(self): self.assertEqual(self.execute('PASS', 0), status_msgs['LOGIN_MISMATCH']) self.assertEqual(self.execute(('USER blah', 'PASS bar'), 0), status_msgs['LOGIN_MISMATCH']) def testQUIT(self): self.assertEqual(self.execute('QUIT', 0), status_msgs['GOODBYE']) self.assertEqual(self.execute('QUIT', 1), status_msgs['GOODBYE']) def testUSER(self): self.assertEqual(self.execute('USER foo', 0), status_msgs['PASS_REQUIRED']) self.assertEqual(self.execute('USER', 0), status_msgs['CMD_UNKNOWN'] %'USER') def test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(Tests) if __name__=='__main__': unittest.TextTestRunner().run( test_suite() ) === Added File Zope3/lib/python/Zope/Server/FTP/tests/testPublisherServer.py === ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. ############################################################################## """ $Id: testPublisherServer.py,v 1.1.2.1 2002/04/06 19:57:09 srichter Exp $ """ #import unittest #from asyncore import socket_map, poll #import sys # #from threading import Thread #from Zope.Server.TaskThreads import ThreadedTaskDispatcher #from Zope.Server.HTTP.PublisherHTTPServer import PublisherHTTPServer #from Zope.Publisher.Browser.BrowserRequest import BrowserRequest # #from Zope.Publisher.DefaultPublication import DefaultPublication #from Zope.Publisher.Exceptions import Redirect, Retry #from Zope.Publisher.HTTP import HTTPRequest # #from httplib import HTTPConnection # #from time import sleep, time # #td = ThreadedTaskDispatcher() # #LOCALHOST = '127.0.0.1' # #HTTPRequest.STAGGER_RETRIES = 0 # Don't pause. # # #class Conflict (Exception): # """ # Pseudo ZODB conflict error. # """ # # #class PublicationWithConflict(DefaultPublication): # # def handleException(self, request, exc_info, retry_allowed=1): # if exc_info[0] is Conflict and retry_allowed: # # This simulates a ZODB retry. # raise Retry(exc_info) # else: # DefaultPublication.handleException(self, request, exc_info, # retry_allowed) # # #class tested_object: # " " # tries = 0 # # def __call__(self, REQUEST): # return 'URL invoked: %s' % REQUEST.URL # # def redirect_method(self, REQUEST): # "Generates a redirect using the redirect() method." # REQUEST.getResponse().redirect("http://somewhere.com/redirect") # # def redirect_exception(self): # "Generates a redirect using an exception." # raise Redirect("http://somewhere.com/exception") # # def conflict(self, REQUEST, wait_tries): # """ # Returns 202 status only after (wait_tries) tries. # """ # if self.tries >= int(wait_tries): # raise "Accepted" # else: # self.tries += 1 # raise Conflict # # # #class Tests(unittest.TestCase): # # def setUp(self): # # obj = tested_object() # obj.folder = tested_object() # obj.folder.item = tested_object() # # obj._protected = tested_object() # # pub = PublicationWithConflict(obj) # # def request_factory(input_stream, output_steam, env): # request = BrowserRequest(input_stream, output_steam, env) # request.setPublication(pub) # return request # # td.setThreadCount(4) # # Bind to any port on localhost. # self.server = PublisherHTTPServer(request_factory, 'Browser', # LOCALHOST, 0, task_dispatcher=td) # self.port = self.server.socket.getsockname()[1] # self.run_loop = 1 # self.thread = Thread(target=self.loop) # self.thread.start() # sleep(0.1) # Give the thread some time to start. # # def tearDown(self): # self.run_loop = 0 # self.thread.join() # td.shutdown() # self.server.close() # # def loop(self): # while self.run_loop: # poll(0.1, socket_map) # # def testResponse(self, path='/', status_expected=200, # add_headers=None, request_body=''): # h = HTTPConnection(LOCALHOST, self.port) # h.putrequest('GET', path) # h.putheader('Accept', 'text/plain') # if add_headers: # for k, v in add_headers.items(): # h.putheader(k, v) # if request_body: # h.putheader('Content-Length', str(int(len(request_body)))) # h.endheaders() # if request_body: # h.send(request_body) # response = h.getresponse() # length = int(response.getheader('Content-Length', '0')) # if length: # response_body = response.read(length) # else: # response_body = '' # # XXX How to test this now that we don't set the response code? # ##self.failUnlessEqual(int(response.status), status_expected) # self.failUnlessEqual(length, len(response_body)) # # if (status_expected == 200): # if path == '/': path = '' # expect_response = 'URL invoked: http://%s:%d%s' % (LOCALHOST, # self.port, path) # self.failUnlessEqual(response_body, expect_response) # # def testDeeperPath(self): # self.testResponse(path='/folder/item') # # def testNotFound(self): # self.testResponse(path='/foo/bar', status_expected=404) # # def testUnauthorized(self): # self.testResponse(path='/_protected', status_expected=401) # # def testRedirectMethod(self): # self.testResponse(path='/redirect_method', status_expected=302) # # def testRedirectException(self): # self.testResponse(path='/redirect_exception', status_expected=302) # self.testResponse(path='/folder/redirect_exception', # status_expected=302) # # def testConflictRetry(self): # # Expect the "Accepted" response since the retries will succeed. # self.testResponse(path='/conflict?wait_tries=2', status_expected=202) # # def testFailedConflictRetry(self): # # Expect a "Conflict" response since there will be too many # # conflicts. # self.testResponse(path='/conflict?wait_tries=10', status_expected=409) # # # #def test_suite(): # loader = unittest.TestLoader() # return loader.loadTestsFromTestCase(Tests) # #if __name__=='__main__': # unittest.TextTestRunner().run( test_suite() ) From srichter@cbu.edu Sat Apr 6 19:57:40 2002 From: srichter@cbu.edu (Stephan Richter) Date: Sat, 6 Apr 2002 14:57:40 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - FTPServer.py:1.1.2.9 FTPServerChannel.py:1.1.2.15 Message-ID: <200204061957.g36Jve202469@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv2221 Modified Files: Tag: Zope3-Server-Branch FTPServer.py FTPServerChannel.py Log Message: Started writing FTP Server tests. Some are fairly easy, but othere are hard, since FTP opens other connections as well. === Zope3/lib/python/Zope/Server/FTP/FTPServer.py 1.1.2.8 => 1.1.2.9 === """Generic FTP Server""" - filesystem = UnixFileSystem('/') - auth_source = DictionaryAuthentication({'foo': 'bar'}) - channel_class = FTPServerChannel SERVER_IDENT = 'Zope.Server.FTPServer' - def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1, - hit_log=None, verbose=0, socket_map=None): + def __init__(self, ip, port, dir='/', auth_source=None, + task_dispatcher=None, adj=None, start=1, hit_log=None, + verbose=0, socket_map=None): + + self.filesystem = UnixFileSystem(dir) + self.auth_source = auth_source + super(FTPServer, self).__init__(ip, port, task_dispatcher, adj, start, hit_log, verbose, socket_map) @@ -54,7 +56,8 @@ from Zope.Server.TaskThreads import ThreadedTaskDispatcher td = ThreadedTaskDispatcher() td.setThreadCount(4) - FTPServer('', 8021, task_dispatcher=td) + auth_source = DictionaryAuthentication({'foo': 'bar'}) + FTPServer('', 8021, '/', auth_source, task_dispatcher=td) try: while 1: asyncore.poll(5) === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.14 => 1.1.2.15 === # List of commands that are always available - special_commands = ('cmd_quit', 'cmd_user', 'cmd_pass') + special_commands = ('cmd_quit', 'cmd_type', 'cmd_noop', 'cmd_user', + 'cmd_pass') # These are the commands that are accessing the filesystem. # Since this could be also potentially a longer process, these commands @@ -95,7 +96,7 @@ 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' if self.client_dc: self.client_dc.close() - self.reply('TRANS_SUCCESS', 'ABOR') + self.reply('TRANSFER_ABORTED') def cmd_appe (self, args): @@ -396,9 +397,7 @@ buffer.skip(len(data), 1) outfile.write(data) finally: - print 'cp4' outfile.close() - print 'cp5' except IOError, why: self.reply('ERR_OPEN_WRITE', str(why)) return From bitz@bitdance.com Sun Apr 7 18:44:34 2002 From: bitz@bitdance.com (R. David Murray) Date: Sun, 7 Apr 2002 13:44:34 -0400 (EDT) Subject: [zope-checkins] Re: fixing line endings. In-Reply-To: Message-ID: <20020407134209.C74342-100000@twirl.bitdance.com> > Date: Fri, 5 Apr 2002 10:01:05 -0500 > To: zope-checkins@zope.org > From: Shane Hathaway > Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/LineReceiver - LineCommandParser.py:1.1.2.2 LineServerChannel.py:1.1.2.2 LineTask.py:1.1.2.2 __init__.py:1.1.2.2 > Fixed line endings again (I hope no one minds me doing this. I have a tool > that does it automatically :-) Please, by all means keep doing it. I hate getting files that have ^Ms at the ends of all the lines . --RDM From steve@cat-box.net Sun Apr 7 19:36:55 2002 From: steve@cat-box.net (Steve Alexander) Date: Sun, 7 Apr 2002 14:36:55 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/Browser - IBrowserRequest.py:1.1.4.4 Message-ID: <200204071836.g37Iat612641@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/Browser In directory cvs.zope.org:/tmp/cvs-serv12589/Zope/Publisher/Browser Modified Files: Tag: Zope-3x-branch IBrowserRequest.py Log Message: fixed tiny docstring typo === Zope3/lib/python/Zope/Publisher/Browser/IBrowserRequest.py 1.1.4.3 => 1.1.4.4 === class IBrowserRequest(IHTTPRequest, IVirtualHostRequest): - """Browser-specific Rquest functionality. + """Browser-specific Request functionality. Note that the browser is special in many ways, since it exposes the Request object to the end-developer. From steve@cat-box.net Sun Apr 7 19:38:19 2002 From: steve@cat-box.net (Steve Alexander) Date: Sun, 7 Apr 2002 14:38:19 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/HTTP - IHTTPRequest.py:1.1.2.6 Message-ID: <200204071838.g37IcJM13034@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/HTTP In directory cvs.zope.org:/tmp/cvs-serv12967/Zope/Publisher/HTTP Modified Files: Tag: Zope-3x-branch IHTTPRequest.py Log Message: fixed tiny docstring typo === Zope3/lib/python/Zope/Publisher/HTTP/IHTTPRequest.py 1.1.2.5 => 1.1.2.6 === def setPathSuffix(steps): - """Add additional trversal steps to be taken after all other traversal + """Add additional traversal steps to be taken after all other traversal This is used to handle HTTP request methods (except for GET and POST in the case of browser requests) and XML-RPC methods. From steve@cat-box.net Sun Apr 7 19:41:47 2002 From: steve@cat-box.net (Steve Alexander) Date: Sun, 7 Apr 2002 14:41:47 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher - IPublisherRequest.py:1.1.2.6 Message-ID: <200204071841.g37IflG14817@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher In directory cvs.zope.org:/tmp/cvs-serv14747/Zope/Publisher Modified Files: Tag: Zope-3x-branch IPublisherRequest.py Log Message: fixed small typos in docstrings. === Zope3/lib/python/Zope/Publisher/IPublisherRequest.py 1.1.2.5 => 1.1.2.6 === """Request interface use by the publisher - The responsability of requests is to encapsulate protocol + The responsibility of requests is to encapsulate protocol specific details, especially wrt request inputs. - Request objects also serve as "context" objects. providing + Request objects also serve as "context" objectsm providing construction of and access to responses and storage of publication objects. @@ -44,14 +44,14 @@ """ def getPublication(): - """Return the requets's publication object + """Return the request's publication object The publication object, an IRequestPublication provides application-specific functionality hooks. """ def setPublication(publication): - """Set the requets's publication object + """Set the request's publication object """ def traverse(object): From srichter@cbu.edu Sun Apr 7 22:39:17 2002 From: srichter@cbu.edu (Stephan Richter) Date: Sun, 7 Apr 2002 17:39:17 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/POP3/tests - foo_mb.py:1.1.2.1 testPOP3Message.py:1.1.2.1 testPOP3MessageList.py:1.1.2.1 testPOP3Server.py:1.1.2.1 Message-ID: <200204072139.g37LdHT28717@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/POP3/tests In directory cvs.zope.org:/tmp/cvs-serv25992/POP3/tests Added Files: Tag: Zope3-Server-Branch foo_mb.py testPOP3Message.py testPOP3MessageList.py testPOP3Server.py Log Message: I just finished the POP3 server implmentation. Right now it does only work with Unix-like mailboxes, but is not limited to run on Unix I believe. It will not make much sense to write the Zope connection until we have the SMTP implemented and a MailMessageService has been written. Please try the code and let me know what could be improved. BTW, I tested the server with Eudora and it worked great, which included teh APOP authen- tication mechanism! === Added File Zope3/lib/python/Zope/Server/POP3/tests/foo_mb.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: foo_mb.py,v 1.1.2.1 2002/04/07 21:39:17 srichter Exp $ """ mailbox = """ >From srichter@iuveno-net.de Sun Apr 7 11:14:50 2002 Received: from Stephan.iuveno-net.de (bohr.cbu.edu [192.168.160.8]) by cbu.edu (8.11.6+Sun/8.11.6) with ESMTP id g37GEnM20286 for ; Sun, 7 Apr 2002 11:14:50 -0500 (CDT) Message-Id: <5.1.0.14.2.20020407111422.00bc5fd0@imail.iuveno-net.de> X-Sender: srichter@imail.iuveno-net.de X-Mailer: QUALCOMM Windows Eudora Version 5.1 Date: Sun, 07 Apr 2002 11:14:41 -0500 To: srichter@cbu.edu From: Stephan Richter Subject: Test Message 1 Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii"; format=flowed Content-Length: 114 Message 1 Body -- Stephan Richter >From srichter@iuveno-net.de Sun Apr 7 11:15:29 2002 Received: from Stephan.iuveno-net.de (bohr.cbu.edu [192.168.160.8]) by cbu.edu (8.11.6+Sun/8.11.6) with ESMTP id g37GFSM20303; Sun, 7 Apr 2002 11:15:28 -0500 (CDT) Message-Id: <5.1.0.14.2.20020407111444.00bc5b20@imail.iuveno-net.de> X-Sender: srichter@imail.iuveno-net.de X-Mailer: QUALCOMM Windows Eudora Version 5.1 Date: Sun, 07 Apr 2002 11:15:20 -0500 To: Stephan Richter From: Stephan Richter Subject: Test Message 2 Cc: Stephan Richter Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii"; format=flowed Content-Length: 121 One more test message -- Stephan Richter >From srichter@iuveno-net.de Sun Apr 7 11:16:00 2002 Received: from Stephan.iuveno-net.de (bohr.cbu.edu [192.168.160.8]) by cbu.edu (8.11.6+Sun/8.11.6) with ESMTP id g37GFxM20326; Sun, 7 Apr 2002 11:16:00 -0500 (CDT) Message-Id: <5.1.0.14.2.20020407111522.02331ac0@imail.iuveno-net.de> X-Sender: srichter@imail.iuveno-net.de X-Mailer: QUALCOMM Windows Eudora Version 5.1 Date: Sun, 07 Apr 2002 11:15:52 -0500 To: Stephan Richter , Stephan Richter From: Stephan Richter Subject: Test Message 3 Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii"; format=flowed Content-Length: 119 The last one, okay? -- Stephan Richter """ === Added File Zope3/lib/python/Zope/Server/POP3/tests/testPOP3Message.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: testPOP3Message.py,v 1.1.2.1 2002/04/07 21:39:17 srichter Exp $ """ import unittest import rfc822 import md5 import tempfile from Interface.Verify import verifyClass from Zope.Server.POP3.IPOP3Message import IPOP3Message from Zope.Server.POP3.POP3Message import POP3Message import foo_mb class Tests(unittest.TestCase): def setUp(self): fn = tempfile.mktemp() open(fn, 'w').write(foo_mb.mailbox[1:663]) msg = rfc822.Message(open(fn, 'r')) self.msg = POP3Message(msg) def testIsDeleted(self): self.assertEqual(self.msg.isDeleted(), 0) def testSetDeleted(self): self.assertEqual(self.msg.isDeleted(), 0) self.msg.setDeleted(1) self.assertEqual(self.msg.isDeleted(), 1) def testGetEntireMessage(self): self.assertEqual(self.msg.getEntireMessage(), foo_mb.mailbox[1:663]) def testGetBody(self): self.assertEqual(self.msg.getBody(), foo_mb.mailbox[626:663]) def testGetSize(self): self.assertEqual(self.msg.getSize(), 662) def testGetUID(self): hash = md5.md5(foo_mb.mailbox[626:663]).hexdigest() self.assertEqual(self.msg.getUID(), hash) def testInterface(self): self.failUnless(IPOP3Message.isImplementedByInstancesOf(POP3Message)) self.failUnless(verifyClass(IPOP3Message, POP3Message)) def test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(Tests) if __name__=='__main__': unittest.TextTestRunner().run( test_suite() ) === Added File Zope3/lib/python/Zope/Server/POP3/tests/testPOP3MessageList.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: testPOP3MessageList.py,v 1.1.2.1 2002/04/07 21:39:17 srichter Exp $ """ import unittest import mailbox import tempfile import os from Interface.Verify import verifyClass from Zope.Server.POP3.IPOP3MessageList import IPOP3MessageList from Zope.Server.POP3.POP3MessageList import POP3MessageList from Zope.Server.VFS.UnixFileSystem import UnixFileSystem import foo_mb class Tests(unittest.TestCase): def setUp(self): dir = tempfile.gettempdir() open(os.path.join(dir, 'foo'), 'w').write(foo_mb.mailbox) self.msg_list = POP3MessageList(UnixFileSystem(dir), 'foo') self.msg_list.open() def testOpen(self): self._messagelist = [] self.msg_list.open() self.assertEqual(len(self.msg_list._messagelist), 3) def testExists(self): self.assertEqual(self.msg_list.exists(1), 1) self.assertEqual(self.msg_list.exists(4), 0) def testGetMessages(self): self.assertEqual(len(self.msg_list.getMessages()), 3) def testGetMessage(self): msg = self.msg_list._messagelist[0] self.assertEqual(self.msg_list.getMessage(1), msg) def testGetTotal(self): self.assertEqual(self.msg_list.getTotalSize(), 2062) def testGetIndex(self): msg = self.msg_list._messagelist[0] self.assertEqual(self.msg_list.getIndex(msg), 1) def testInterface(self): self.failUnless(IPOP3MessageList.isImplementedByInstancesOf( POP3MessageList)) self.failUnless(verifyClass(IPOP3MessageList, POP3MessageList)) def test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(Tests) if __name__=='__main__': unittest.TextTestRunner().run( test_suite() ) === Added File Zope3/lib/python/Zope/Server/POP3/tests/testPOP3Server.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: testPOP3Server.py,v 1.1.2.1 2002/04/07 21:39:17 srichter Exp $ """ import unittest import tempfile import os from asyncore import socket_map, poll from threading import Thread from Zope.Server.TaskThreads import ThreadedTaskDispatcher from Zope.Server.POP3.POP3Server import POP3Server from Zope.Server.POP3.POP3ServerChannel import POP3ServerChannel from Zope.Server.POP3.POP3StatusMessages import status_msgs from Zope.Server.Adjustments import Adjustments from Zope.Server.ITask import ITask from Zope.Server.VFS.UnixFileSystem import UnixFileSystem from Zope.Server.Authentication.DictionaryAuthentication import \ DictionaryAuthentication import poplib import foo_mb from time import sleep, time td = ThreadedTaskDispatcher() LOCALHOST = '127.0.0.1' SERVER_PORT = 0 # Set these port numbers to 0 to auto-bind, or CONNECT_TO_PORT = 0 # use specific numbers to inspect using TCPWatch. my_adj = Adjustments() # Reduce overflows to make testing easier. my_adj.outbuf_overflow = 10000 my_adj.inbuf_overflow = 10000 class Tests(unittest.TestCase): def setUp(self): td.setThreadCount(1) self.orig_map_size = len(socket_map) root_dir = tempfile.mktemp() os.mkdir(root_dir) self.root_dir = UnixFileSystem(root_dir) file = open(os.path.join(root_dir, 'foo'), 'w') file.write(foo_mb.mailbox) file.close() self.server = POP3Server(LOCALHOST, SERVER_PORT, root_dir, DictionaryAuthentication({'foo': 'bar'}), task_dispatcher=td, adj=my_adj) if CONNECT_TO_PORT == 0: self.port = self.server.socket.getsockname()[1] else: self.port = CONNECT_TO_PORT self.run_loop = 1 self.counter = 0 self.thread = Thread(target=self.loop) self.thread.start() sleep(0.1) # Give the thread some time to start. def tearDown(self): self.run_loop = 0 self.thread.join() td.shutdown() self.server.close() # Make sure all sockets get closed by asyncore normally. # timeout = time() + 5 # while 1: # if len(socket_map) == self.orig_map_size: # # Clean! # break # if time() >= timeout: # print 'Leaked a socket: %s' % `socket_map` # break # #self.fail('Leaked a socket: %s' % `socket_map`) # poll(0.1, socket_map) def loop(self): while self.run_loop: self.counter = self.counter + 1 # print 'loop', self.counter poll(0.1, socket_map) def getPOP3Connection(self, login=1): # Refresh the file every single time, since some operations might # modify it. file = self.root_dir.open('foo', 'w') file.write(foo_mb.mailbox) file.close() pop = poplib.POP3(LOCALHOST, self.port) if login: self.assertEqual(pop.user('foo'), status_msgs['OK_USER'] %'foo') self.assertEqual(pop.pass_('bar'), status_msgs['OK_LOGIN']) return pop def testAPOP(self): pop = self.getPOP3Connection(0) self.assertEqual(pop.apop('foo', 'bar'), status_msgs['OK_LOGIN']) pop.quit() def testDELE(self): pop = self.getPOP3Connection(1) self.assertEqual(pop.dele(1), status_msgs['OK_DELETE']) pop.quit() def testLIST(self): pop = self.getPOP3Connection(1) self.assertEqual(pop.list(), (status_msgs['OK_MSG_LIST'] %(3, 2062), ['1 662', '2 703', '3 697'], 21) ) pop.quit() def testNOOP(self): pop = self.getPOP3Connection(1) self.assertEqual(pop.noop(), status_msgs['OK_GENERAL']) pop.quit() def testPASS(self): pop = self.getPOP3Connection(0) pop.user('foo') self.assertEqual(pop.pass_('bar'), status_msgs['OK_LOGIN']) pop.quit() pop = self.getPOP3Connection(0) pop.user('foo') try: pop.pass_('blah') except poplib.error_proto, error: self.assertEqual(str(error), status_msgs['ERR_LOGIN_MISMATCH']) def testQUIT(self): pop = self.getPOP3Connection(1) self.assertEqual(pop.quit(), status_msgs['OK_QUIT']) def testRETR(self): pop = self.getPOP3Connection(1) self.assertEqual(pop.retr(1), (status_msgs['OK_RETR'] %662, [ 'From srichter@iuveno-net.de Sun Apr 7 11:14:50 2002', 'Received: from Stephan.iuveno-net.de (bohr.cbu.edu [192.168.160.8])', '\tby cbu.edu (8.11.6+Sun/8.11.6) with ESMTP id g37GEnM20286', '\tfor ; Sun, 7 Apr 2002 11:14:50 -0500 (CDT)', 'Message-Id: <5.1.0.14.2.20020407111422.00bc5fd0@imail.iuveno-net.de>', 'X-Sender: srichter@imail.iuveno-net.de', 'X-Mailer: QUALCOMM Windows Eudora Version 5.1', 'Date: Sun, 07 Apr 2002 11:14:41 -0500', 'To: srichter@cbu.edu', 'From: Stephan Richter ', 'Subject: Test Message 1', 'Mime-Version: 1.0', 'Content-Type: text/plain; charset="us-ascii"; format=flowed', 'Content-Length: 114', '', 'Message 1 Body', '', '--', 'Stephan Richter', '', '', ''], 664)) try: pop.retr(4) except poplib.error_proto, error: self.assertEqual(str(error), status_msgs['ERR_MSG_UNKNOWN']) pop.quit() def testRSET(self): pop = self.getPOP3Connection(1) pop.dele(1) self.assertEqual(len(pop.list()[1]), 2) pop.rset() self.assertEqual(len(pop.list()[1]), 3) pop.quit() def testSTAT(self): pop = self.getPOP3Connection(1) self.assertEqual(pop.stat(), (2062, 3)) pop.quit() def testTOP(self): pop = self.getPOP3Connection(1) self.assertEqual(pop.top(1, 2), (status_msgs['OK_TOP'] % 2, ['Message 1 Body', ''], 18)) try: pop.top(4, 1) except poplib.error_proto, error: self.assertEqual(str(error), status_msgs['ERR_MSG_UNKNOWN']) pop.quit() def testUIDL(self): pop = self.getPOP3Connection(1) self.assertEqual(pop.uidl(), (status_msgs['OK_MSG_UIDL'], ['1 f10230af2271c19b56442b4422d30244', '2 f35cffda322101a0aaf354c1ca4a7840', '3 059fa436bc14db93c2094c11ba224227'], 108)) self.assertEqual(pop.uidl(1), status_msgs['OK_SINGLE_UIDL'] %( 1, 'd41d8cd98f00b204e9800998ecf8427e')) try: pop.uidl(4) except poplib.error_proto, error: self.assertEqual(str(error), status_msgs['ERR_MSG_UNKNOWN']) pop.quit() def testUSER(self): pop = self.getPOP3Connection(0) self.assertEqual(pop.user('foo'), status_msgs['OK_USER'] %'foo') try: pop.user('blah') except poplib.error_proto, error: self.assertEqual(str(error), status_msgs['ERR_NOT_USER']) pop.quit() def test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(Tests) if __name__=='__main__': unittest.TextTestRunner().run( test_suite() ) From srichter@cbu.edu Sun Apr 7 22:39:18 2002 From: srichter@cbu.edu (Stephan Richter) Date: Sun, 7 Apr 2002 17:39:18 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/POP3 - IPOP3Message.py:1.1.2.1 IPOP3MessageList.py:1.1.2.1 POP3Message.py:1.1.2.1 POP3MessageList.py:1.1.2.1 IPOP3CommandHandler.py:1.1.2.2 POP3Server.py:1.1.2.2 POP3ServerChannel.py:1.1.2.2 POP3StatusMessages.py:1.1.2.2 Message-ID: <200204072139.g37LdIX28718@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/POP3 In directory cvs.zope.org:/tmp/cvs-serv25992/POP3 Modified Files: Tag: Zope3-Server-Branch IPOP3CommandHandler.py POP3Server.py POP3ServerChannel.py POP3StatusMessages.py Added Files: Tag: Zope3-Server-Branch IPOP3Message.py IPOP3MessageList.py POP3Message.py POP3MessageList.py Log Message: I just finished the POP3 server implmentation. Right now it does only work with Unix-like mailboxes, but is not limited to run on Unix I believe. It will not make much sense to write the Zope connection until we have the SMTP implemented and a MailMessageService has been written. Please try the code and let me know what could be improved. BTW, I tested the server with Eudora and it worked great, which included teh APOP authen- tication mechanism! === Added File Zope3/lib/python/Zope/Server/POP3/IPOP3Message.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IPOP3Message.py,v 1.1.2.1 2002/04/07 21:39:16 srichter Exp $ """ from Interface import Interface class IPOP3Message(Interface): """THis interface describes the methods that are expected of a message by the POP3 server. """ def isDeleted(): """Return the 'deleted' status of the message. """ def setDeleted(deleted=1): """Set the message as delted or not-deleted. """ def getEntireMessage(): """Return the entire message, including headers. """ def getBody(): """Return only the body of the message. """ def getSize(): """Return the size of the message in octets. """ def getUID(): """Get a unique id, following th eguidelines given in the POP3 RFC in the UIDL section. """ === Added File Zope3/lib/python/Zope/Server/POP3/IPOP3MessageList.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IPOP3MessageList.py,v 1.1.2.1 2002/04/07 21:39:16 srichter Exp $ """ from Interface import Interface class IPOP3MessageList(Interface): """ """ def open(): """Open the mailbox and create the message list. """ def close(): """Close the mailbox. Here the messages that are marked as 'deleted' should be removed before saving the list. """ def exists(index): """Check whether this index exists in this Message List. """ def getMessages(): """Return a list of non-deleted messages. """ def getMessage(index): """Return the message of the given index. """ def getTotalSize(): """Get the total size of all non-deleted messages. """ def getIndex(message): """Get the index of a particular method.""" def __getitem__(index): """Get the message wuth the specified 'index'. """ === Added File Zope3/lib/python/Zope/Server/POP3/POP3Message.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: POP3Message.py,v 1.1.2.1 2002/04/07 21:39:16 srichter Exp $ """ from Zope.Server.POP3.IPOP3Message import IPOP3Message import md5 class POP3Message: __implements__ = IPOP3Message def __init__(self, rfc822_msg): """ """ self.rfc822_msg = rfc822_msg self._deleted = 0 ############################################################ # Implementation methods for interface # Zope.Server.POP3.IPOP3Message. def isDeleted(self): 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' return self._deleted def setDeleted(self, deleted=1): 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' self._deleted = deleted def getEntireMessage(self): 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' self.rfc822_msg.fp.seek(0) return self.rfc822_msg.fp.read() def getBody(self): 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' return self.rfc822_msg.fp.read() def getSize(self): 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' return len(self.getEntireMessage()) def getUID(self): 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' hash = md5.md5(self.getBody()) return hash.hexdigest() # ############################################################ === Added File Zope3/lib/python/Zope/Server/POP3/POP3MessageList.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: POP3MessageList.py,v 1.1.2.1 2002/04/07 21:39:16 srichter Exp $ """ import mailbox import os from IPOP3MessageList import IPOP3MessageList from POP3Message import POP3Message class POP3MessageList: __implements__ = IPOP3MessageList def __init__(self, maildir, maildrop=None): """ """ self.maildir = maildir self.maildrop = maildrop self._messagelist = [] self._mb = None ############################################################ # Implementation methods for interface # Zope.Server.POP3.IPOP3MessageList. def open(self, maildrop=None): 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' if maildrop is None: maildrop = self.maildrop else: self.maildrop = maildrop md_file = self.maildir.open(maildrop, 'r') self._mb = mailbox.UnixMailbox(md_file) msg = self._mb.next() self._messagelist = [] while msg is not None: self._messagelist.append(POP3Message(msg)) msg = self._mb.next() def close(self): 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' mb_str = '' for msg in self.getMessages(): mb_str += msg.getEntireMessage() self._mb.fp.close() file = self.maildir.open(self.maildrop, 'w') file.write(mb_str) file.close() def exists(self, index): 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' if index > 0 and index <= len(self._messagelist): return 1 return 0 def getMessages(self): 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' return filter(lambda msg: not msg.isDeleted(), self._messagelist) def getMessage(self, index): 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' return self._messagelist[index-1] def getTotalSize(self): 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' sizes = map(lambda msg: msg.getSize(), self.getMessages()) if sizes: return reduce(lambda x, y: x+y, sizes) else: return 0 def getIndex(self, message): 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' return self._messagelist.index(message) + 1 def __getitem__(self, index): 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' return self.getMessage(index) # ############################################################ === Zope3/lib/python/Zope/Server/POP3/IPOP3CommandHandler.py 1.1.2.1 => 1.1.2.2 === class IPOP3CommandHandler(Interface): - """ + """This interface lists the implemented POP3 commands following + RFC 1939. Some advanced commands specified in RFC 2449 are also + listed. """ def cmd_apop(args): @@ -111,6 +113,46 @@ """ + def cmd_capa(args): + """CAPA + + Arguments: none + + Restrictions: none + + Discussion: + An -ERR response indicates the capability command + is not implemented and the client will have to + probe for capabilities as before. + + An +OK response is followed by a list of + capabilities, one per line. Each capability name + MAY be followed by a single space and a + space-separated list of parameters. Each + capability line is limited to 512 octets + (including the CRLF). The capability list is + terminated by a line containing a termination + octet (".") and a CRLF pair. + + Possible Responses: + +OK -ERR + + Examples: + C: CAPA + S: +OK Capability list follows + S: TOP + S: USER + S: SASL CRAM-MD5 KERBEROS_V4 + S: RESP-CODES + S: LOGIN-DELAY 900 + S: PIPELINING + S: EXPIRE 60 + S: UIDL + S: IMPLEMENTATION Shlemazle-Plotz-v302 + S: . + + """ + def cmd_dele(args): """DELE msg @@ -191,6 +233,28 @@ C: LIST 3 S: -ERR no such message, only 2 messages in maildrop """ + + + def cmd_noop(args): + """NOOP + + Arguments: none + + Restrictions: + may only be given in the TRANSACTION state + + Discussion: + The POP3 server does nothing, it merely replies with a + positive response. + + Possible Responses: + +OK + + Examples: + C: NOOP + S: +OK + """ + def cmd_pass(args): """PASS string === Zope3/lib/python/Zope/Server/POP3/POP3Server.py 1.1.2.1 => 1.1.2.2 === from Zope.Server.ServerBase import ServerBase +from Zope.Server.VFS.UnixFileSystem import UnixFileSystem +from Zope.Server.Authentication.DictionaryAuthentication import \ + DictionaryAuthentication + + class POP3Server(ServerBase): """Generic FTP Server""" @@ -25,11 +30,16 @@ SERVER_IDENT = 'Zope.Server.POP3Server' - def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1, - hit_log=None, verbose=0, socket_map=None): - super(FTPServer, self).__init__(ip, port, task_dispatcher, - adj, start, hit_log, - verbose, socket_map) + def __init__(self, ip, port, maildir, auth, task_dispatcher=None, + adj=None, start=1, hit_log=None, verbose=0, + socket_map=None): + + self.auth_source = auth + self.maildir = UnixFileSystem(maildir) + + super(POP3Server, self).__init__(ip, port, task_dispatcher, + adj, start, hit_log, + verbose, socket_map) if __name__ == '__main__': @@ -39,11 +49,12 @@ td = ThreadedTaskDispatcher() td.setThreadCount(4) - POP3Server('', 8110, task_dispatcher=td) + auth_source = DictionaryAuthentication({'foo': 'bar'}) + POP3Server('', 110, '/var/mail', auth_source, task_dispatcher=td) try: while 1: asyncore.poll(5) - print 'active channels:', POP3ServerChannel.active_channels + # print 'active channels:', POP3ServerChannel.active_channels except KeyboardInterrupt: print 'shutting down...' td.shutdown() === Zope3/lib/python/Zope/Server/POP3/POP3ServerChannel.py 1.1.2.1 => 1.1.2.2 === import stat import socket +import thread import time +import md5 from Zope.Server.LineReceiver.LineServerChannel import LineServerChannel from POP3StatusMessages import status_msgs -from FileProducer import FileProducer +from POP3MessageList import POP3MessageList from IPOP3CommandHandler import IPOP3CommandHandler -from PassiveAcceptor import PassiveAcceptor -from RecvChannel import RecvChannel -from XmitChannel import XmitChannel class POP3ServerChannel(LineServerChannel): @@ -37,28 +36,46 @@ __implements__ = LineServerChannel.__implements__, IPOP3CommandHandler - # These are the commands that are allowed without the channel being in # "Transaction State", as the POP3 RFC calls it. - special_commands = ('cmd_quit', 'cmd_user', 'cmd_pass') + special_commands = ('cmd_quit', 'cmd_apop', 'cmd_capa', + 'cmd_user', 'cmd_pass') # These are the commands that are accessing the filesystem. # Since this could be also potentially a longer process, these commands # are also the ones that are executed in a different thread. - thread_commands = ('cmd_apop', 'cmd_dele', 'cmd_list', 'cmd_pass', - 'cmd_retr', 'cmd_rset', 'cmd_stat', 'cmd_top', - 'cmd_uidl') + # thread_commands = ('cmd_apop', 'cmd_dele', 'cmd_list', 'cmd_pass', + # 'cmd_retr', 'cmd_rset', 'cmd_stat', 'cmd_top', + # 'cmd_uidl') # Define the status messages status_messages = status_msgs + # Deifne the factory that will create a message list object + message_list_factory = POP3MessageList + + # Define the error message that occurs, when the reply code was not found. + reply_error = '-ERR Reply Code unknown: %s' + + # A list of this servers capabilities + capa_list = ('APOP MAILBOX MD5-DISGEST', 'CAPA', 'DELE MSG-INDEX', + 'LIST [MSG-INDEX]', 'NOOP', 'PASS PASSWORD', 'QUIT', + 'RETR MSG-INDEX', 'RSET', 'STAT', 'TOP MSG-INDEX NROFLINES', + 'UIDL [MESG-INDEX', 'USER MAILBOX') + def __init__(self, server, conn, addr, adj=None, socket_map=None): super(POP3ServerChannel, self).__init__(server, conn, addr, adj, socket_map) self.username = '' self.password = '' - self.messagelist = [] + self.messagelist = None + + self.secret = "<%d.%d.%s@%s.%s>" %( os.getpid(), thread.get_ident(), + str(time.clock()), + socket.gethostname(), + str(id(self)) ) + self.reply('OK_GREETING', self.secret) ############################################################ @@ -67,21 +84,48 @@ def cmd_apop(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' - pass + if self.authenticated: + return self.reply('ERR_INV_STATE') + + # We require the username and the MD5 hash + if len(args.split()) != 2: + return self.reply('ERR_CMD_UNKNOWN') + + # Get the username and check whether the user exists + auth = self.server.auth_source + self.username, hash = args.split() + if not auth.hasUser(self.username): + return self.reply('ERR_LOGIN_MISMATCH') + + # See whether we got the right MD5 hash + self.password = auth.getPassword(self.username) + expected = md5.new(self.secret + self.password).hexdigest() + if expected != hash: + return self.reply('ERR_LOGIN_MISMATCH') + + self.openMessageList() + self.reply('OK_LOGIN') + self.authenticated = 1 + + + def cmd_capa(self, args): + 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' + self.reply('OK_CAPA') + self.write('\r\n'.join(self.capa_list)) + self.write('\r\n.\r\n') + self.flush() def cmd_dele(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' try: - msg_index = int(args)-1 + msg_index = int(args) except: return self.reply('ERR_MSG_UNKNOWN') - msg_list = self.messagelist - - if msg_index >= 0 and msg_index < len(msg_list): + if self.messagelist.exists(msg_index): # mark message as deleted - self.msg_list[msg_index].deleted = 1 + self.messagelist[msg_index].setDeleted() return self.reply('OK_DELETE') return self.reply('ERR_MSG_UNKNOWN') @@ -89,43 +133,44 @@ def cmd_list(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' - - msg_list = self.messagelist - if args: # A message id was passed, so let's work with it. try: - msg_index = int(args)-1 + msg_index = int(args) except: return self.reply('ERR_MSG_UNKNOWN') - if msg_index >= 0 and msg_index < len(msg_list): + if not self.messagelist.exists(msg_index): return self.reply('ERR_MSG_UNKNOWN') - message = msg_list[msg_index] - self.reply('OK_SINGLE_LIST', (msg_index+1, message.size) + message = self.messagelist[msg_index] + self.reply('OK_SINGLE_LIST', (msg_index, message.getSize())) else: - usedbytes = self.getTotalSize(msg_list) - total_msgs = len(map(lambda msg: not msg.deleted, msg_list)) - self.reply('OK_MSG_LIST', (len(msg_list), usedbytes)) - - for msg in msg_list: - if msg.deleted: continue - self.write("%d %d\r\n" % (msg_list.index(msg)+1, msg.size)) + self.reply('OK_MSG_LIST', (len(self.messagelist.getMessages()), + self.messagelist.getTotalSize())) + + for msg in self.messagelist.getMessages(): + self.write("%d %d\r\n" % (self.messagelist.getIndex(msg), + msg.getSize())) self.write('.\r\n') self.flush() - def cmd_pass(self, args): + def cmd_noop(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' + self.reply('OK_GENERAL') + + def cmd_pass(self, args): + 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' self.password = args if self.authenticated: return self.reply('ERR_INV_STATE') + # No username was specified. Use USER first if not self.username: return self.reply('ERR_NO_USER') @@ -133,53 +178,50 @@ self.authenticated, message = auth.authenticate(self.username, self.password) if self.authenticated: + self.openMessageList() self.reply('OK_LOGIN') else: self.reply('ERR_LOGIN_MISMATCH') - self.close_when_done() + self.close() def cmd_quit(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' self.reply('OK_QUIT') - # XXX Should de;ete messages - self.close_when_done() + self.closeMessageList() + self.close() def cmd_retr(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' - try: - msg_index = int(args)-1 + msg_index = int(args) except: return self.reply('ERR_MSG_UNKNOWN') - msg_list = self.messagelist - - if msg_index >= 0 and msg_index < len(msg_list): - # mark message as deleted - self.write(msg.body) - return self.reply('OK_RETR') - - return self.reply('ERR_MSG_UNKNOWN') + # Output the message quickly, so we get done. + if self.messagelist.exists(msg_index): + msg = self.messagelist.getMessage(msg_index) + self.reply('OK_RETR', msg.getSize()) + self.write(msg.getEntireMessage()) + self.write('\r\n.\r\n') + else: + return self.reply('ERR_MSG_UNKNOWN') def cmd_rset(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' - - for msg in self.messagelist): + for msg in self.messagelist: # mark all messages as not-deleted - msg.deleted = 0 + msg.setDeleted(0) self.reply('OK_RSET') def cmd_stat(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' - usedbytes = self.getTotalSize(msg_list) - total_msgs = len(map(lambda msg: not msg.deleted, msg_list)) - - self.reply('OK_STAT', (total_msgs, usedbytes)) + self.reply('OK_STAT', (self.messagelist.getTotalSize(), + len(self.messagelist.getMessages())) ) def cmd_top(self, args): @@ -187,35 +229,22 @@ try: msg_index, nroflines = args.split() - msg_index = int(args)-1 + msg_index = int(msg_index) nroflines = int(nroflines) except: return self.reply('ERR_MSG_UNKNOWN') - msg_list = self.messagelist - - if msg_index >= 0 and msg_index < len(msg_list): - # Split message body into lines/ - lines = self.messagelist[msg_index].body.split("\r\n") - - found, isHeader, line = -1, 1, 0 - - # XXX: This is too complicated. It can be done easier. - - while line < len(nroflines): - if isHeader: - # skip header lines. Header lines have a : - if lines[line].find(':') == 0: - isHeader = 0 - else: - found += 1 - if found == nroflines: - break + if self.messagelist.exists(msg_index): + # Split message body into lines + lines = self.messagelist[msg_index].getBody().split('\n') + + # Determine the true number of lines that will be returned + if nroflines <= len(lines): + lines = lines[:nroflines] - self.reply('OK_TOP', line) - lines = lines[:line] + self.reply('OK_TOP', len(lines)) self.write("\r\n".join(lines)) - self.write('.\r\n') + self.write('\r\n.\r\n') self.flush() else: return self.reply('ERR_MSG_UNKNOWN') @@ -223,7 +252,28 @@ def cmd_uidl(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' - pass + if args: + # A message id was passed, so let's work with it. + try: + msg_index = int(args) + except: + return self.reply('ERR_MSG_UNKNOWN') + + if not self.messagelist.exists(msg_index): + return self.reply('ERR_MSG_UNKNOWN') + + message = self.messagelist[msg_index] + self.reply('OK_SINGLE_UIDL', (msg_index, message.getUID())) + + else: + self.reply('OK_MSG_UIDL') + + for msg in self.messagelist.getMessages(): + self.write("%i %s\r\n" % (self.messagelist.getIndex(msg), + msg.getUID())) + + self.write('.\r\n') + self.flush() def cmd_user(self, args): @@ -232,10 +282,21 @@ if self.authenticated: return self.reply('ERR_INV_STATE') - if self.auth.hasUser(args): + if self.server.auth_source.hasUser(args): + self.username = args self.reply('OK_USER', args) else: self.reply('ERR_NOT_USER') # ############################################################ + + + def openMessageList(self): + self.messagelist = self.message_list_factory(self.server.maildir) + self.messagelist.open(self.username) + + + def closeMessageList(self): + if self.messagelist is not None: + self.messagelist.close() === Zope3/lib/python/Zope/Server/POP3/POP3StatusMessages.py 1.1.2.1 => 1.1.2.2 === status_msgs = { - 'OK_GENERAL' : '+OK', - 'OK_LOGIN' : '+OK login successful', - 'OK_USER' : '+OK %s is a valid name box', - 'OK_QUIT' : '+OK', - 'OK_SINGLE_LIST' : '+OK %i %i', - 'OK_MSG_LIST' : '+OK %i message (%i octets)', - 'OK_DELETE' : '+OK The message was successfully deleted' - 'OK_RETR' : '+OK message follows', - 'OK_RSET' : '+OK Resetting all messages done', - 'OKTOP' : '+OK top %i lines of message follows', - 'OK_APOP' : '+OK maildrop locked and ready', - 'OK_UIDL' : '+OK unique-id listing follows', + 'OK_GENERAL' : '+OK', + 'OK_GREETING' : '+OK Zope 3 POP3 server ready %s', + 'OK_LOGIN' : '+OK login successful', + 'OK_USER' : '+OK %s is a valid mailbox', + 'OK_QUIT' : '+OK Connection is closing.', + 'OK_SINGLE_LIST' : '+OK %i %i', + 'OK_MSG_LIST' : '+OK %i message (%i octets)', + 'OK_DELETE' : '+OK The message was successfully deleted', + 'OK_RETR' : '+OK message follows (%i octets)', + 'OK_RSET' : '+OK Resetting all messages done', + 'OK_STAT' : '+OK %i %i', + 'OK_TOP' : '+OK top %i lines of message follows', + 'OK_APOP' : '+OK maildrop locked and ready', + 'OK_SINGLE_UIDL' : '+OK %i %s', + 'OK_MSG_UIDL' : '+OK Unique message id list follows', + 'OK_CAPA' : '+OK Capability list follows', - 'ERR_CMD_UNKNOWN' : '-ERR unknown command', - 'ERR_MSG_UNKNOWN' : '-ERR unknown or invalid message id', - 'ERR_INV_STATE' : '-ERR Invalid State', - 'ERR_NO_USER' : '-ERR No user was yet specified' - 'ERR_NOT_USER' : '-ERR never heard of mailbox name', - 'ERR_LOGIN_MISMATH' : '-ERR username and password did not match', + 'ERR_CMD_UNKNOWN' : '-ERR unknown command', + 'ERR_MSG_UNKNOWN' : '-ERR unknown or invalid message id', + 'ERR_INV_STATE' : '-ERR Invalid State', + 'ERR_NO_USER' : '-ERR No user was yet specified', + 'ERR_NOT_USER' : '-ERR never heard of mailbox name', + 'ERR_LOGIN_MISMATCH' : '-ERR username and password did not match', + + 'CMD_UNKNOWN' : '-ERR %s command unknown', + 'LOGIN_REQUIRED' : '-ERR Not yet logged in.', } From srichter@cbu.edu Mon Apr 8 07:50:30 2002 From: srichter@cbu.edu (Stephan Richter) Date: Mon, 8 Apr 2002 02:50:30 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - IReadFileSystem.py:1.1.2.3 Message-ID: <200204080650.g386oUB01919@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv31265/VFS Modified Files: Tag: Zope3-Server-Branch IReadFileSystem.py Log Message: This is the first working version of the SMTP server. There is still a lot of work to be done, but it is a start. Now I need to stabalize the code and write some tests. Also, Gerson Kunze (author of Shicks!), whose code I used as a template, told me that he would be working on implementing ESMTP and a better SPAM filter, whcih should make the server even cooler. I guess we should start discussing how a possible MailService could look like. === Zope3/lib/python/Zope/Server/VFS/IReadFileSystem.py 1.1.2.2 => 1.1.2.3 === return list(tuple(str, str)) - def longify(path): + def longify(path, stat): """Return a 'long' representation of the filename [for the output of the LIST command] """ From srichter@cbu.edu Mon Apr 8 07:50:30 2002 From: srichter@cbu.edu (Stephan Richter) Date: Mon, 8 Apr 2002 02:50:30 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS/tests - testOSFileSystem.py:1.1.2.6 Message-ID: <200204080650.g386oUx01920@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS/tests In directory cvs.zope.org:/tmp/cvs-serv31265/VFS/tests Modified Files: Tag: Zope3-Server-Branch testOSFileSystem.py Log Message: This is the first working version of the SMTP server. There is still a lot of work to be done, but it is a start. Now I need to stabalize the code and write some tests. Also, Gerson Kunze (author of Shicks!), whose code I used as a template, told me that he would be working on implementing ESMTP and a better SPAM filter, whcih should make the server even cooler. I guess we should start discussing how a possible MailService could look like. === Zope3/lib/python/Zope/Server/VFS/tests/testOSFileSystem.py 1.1.2.5 => 1.1.2.6 === open(path, 'w').write('test') stat_info = os.stat(path) - result = self.filesystem.longify(('foo', stat_info)) + result = self.filesystem.longify('foo', stat_info) self.failUnless(result.endswith('foo')) os.remove(path) From srichter@cbu.edu Mon Apr 8 07:50:58 2002 From: srichter@cbu.edu (Stephan Richter) Date: Mon, 8 Apr 2002 02:50:58 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/Authentication - DictionaryAuthentication.py:1.1.2.4 IAuthentication.py:1.1.2.5 Message-ID: <200204080650.g386ow002110@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/Authentication In directory cvs.zope.org:/tmp/cvs-serv31265/Authentication Modified Files: Tag: Zope3-Server-Branch DictionaryAuthentication.py IAuthentication.py Log Message: This is the first working version of the SMTP server. There is still a lot of work to be done, but it is a start. Now I need to stabalize the code and write some tests. Also, Gerson Kunze (author of Shicks!), whose code I used as a template, told me that he would be working on implementing ESMTP and a better SPAM filter, whcih should make the server even cooler. I guess we should start discussing how a possible MailService could look like. === Zope3/lib/python/Zope/Server/Authentication/DictionaryAuthentication.py 1.1.2.3 => 1.1.2.4 === ############################################################ # Implementation methods for interface - # Zope.Server.Authentication.IAuthentication. + # Zope.Server.Authentication.IAuthentication.IAuthentication def authenticate(self, username, password): 'See Zope.Server.Authentication.IAuthentication.IAuthentication' @@ -42,6 +42,14 @@ else: return 0, 'Password invalid.' + def hasUser(self, username): + 'See Zope.Server.Authentication.IAuthentication.IAuthentication' + return self.user_dict.has_key(username) + + def getPassword(self, username): + 'See Zope.Server.Authentication.IAuthentication.IAuthentication' + return self.user_dict[username] + # ############################################################ === Zope3/lib/python/Zope/Server/Authentication/IAuthentication.py 1.1.2.4 => 1.1.2.5 === def authenticate(username, password): + """Authenticate a user using the passed username and password pair. """ + return Boolean, str("Message") + + + def hasUser(username): + """Check whether a user is defined. """ + return Boolean - return Boolean, str("Message") + + def getPassword(username): + """Get the password for this username, sinc esome applicaitons want to + do some extraordinary encoding and other things themselves. + """ From srichter@cbu.edu Mon Apr 8 07:50:58 2002 From: srichter@cbu.edu (Stephan Richter) Date: Mon, 8 Apr 2002 02:50:58 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP/tests - testFTPServer.py:1.1.2.2 Message-ID: <200204080650.g386owp02112@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP/tests In directory cvs.zope.org:/tmp/cvs-serv31265/FTP/tests Modified Files: Tag: Zope3-Server-Branch testFTPServer.py Log Message: This is the first working version of the SMTP server. There is still a lot of work to be done, but it is a start. Now I need to stabalize the code and write some tests. Also, Gerson Kunze (author of Shicks!), whose code I used as a template, told me that he would be working on implementing ESMTP and a better SPAM filter, whcih should make the server even cooler. I guess we should start discussing how a possible MailService could look like. === Zope3/lib/python/Zope/Server/FTP/tests/testFTPServer.py 1.1.2.1 => 1.1.2.2 === status_msgs['TRANSFER_ABORTED']) - #def testABOR(self): - def testCDUP(self): self.assertEqual(self.execute(('CWD test', 'CDUP'), 1), @@ -171,14 +169,14 @@ self.assertEqual(self.execute('HELP', 1), result) - def testLIST(self): - path = os.path.join(self.root_dir, 'foo') - result = "[Errno 2] No such file or directory: '%s'" %path - - self.assertEqual(self.execute('LIST /foo', 1), - status_msgs['ERR_NO_LIST'] %result) - self.assertEqual(self.execute('LIST', 1), - status_msgs['SUCCESS_200'] %'NOOP') + # def testLIST(self): + # path = os.path.join(self.root_dir, 'foo') + # result = "[Errno 2] No such file or directory: '%s'" %path + # + # self.assertEqual(self.execute('LIST /foo', 1), + # status_msgs['ERR_NO_LIST'] %result) + # self.assertEqual(self.execute('LIST', 1), + # status_msgs['SUCCESS_200'] %'NOOP') def testNOOP(self): From srichter@cbu.edu Mon Apr 8 07:50:59 2002 From: srichter@cbu.edu (Stephan Richter) Date: Mon, 8 Apr 2002 02:50:59 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/LineReceiver - LineCommandParser.py:1.1.2.3 LineServerChannel.py:1.1.2.5 Message-ID: <200204080650.g386oxk02118@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/LineReceiver In directory cvs.zope.org:/tmp/cvs-serv31265/LineReceiver Modified Files: Tag: Zope3-Server-Branch LineCommandParser.py LineServerChannel.py Log Message: This is the first working version of the SMTP server. There is still a lot of work to be done, but it is a start. Now I need to stabalize the code and write some tests. Also, Gerson Kunze (author of Shicks!), whose code I used as a template, told me that he would be working on implementing ESMTP and a better SPAM filter, whcih should make the server even cooler. I guess we should start discussing how a possible MailService could look like. === Zope3/lib/python/Zope/Server/LineReceiver/LineCommandParser.py 1.1.2.2 => 1.1.2.3 === def parseLine(self, line): + print line parts = line.split(' ', 1) if len(parts) == 2: self.cmd, self.args = parts === Zope3/lib/python/Zope/Server/LineReceiver/LineServerChannel.py 1.1.2.4 => 1.1.2.5 === unknown_reply = 'CMD_UNKNOWN' + # Define the error message that occurs, when the reply code was not found. + reply_error = '500 Unknown Reply Code: %s.' + # Define the status messages status_messages = { 'CMD_UNKNOWN' : "500 '%s': command not understood.", @@ -78,8 +81,11 @@ return self.task_class(self, command, method) elif hasattr(self, method): - getattr(self, method)(command.args) - + try: + getattr(self, method)(command.args) + except: + import traceback + traceback.print_exc() else: self.reply(self.unknown_reply, cmd.upper()) return None @@ -88,9 +94,9 @@ def reply(self, code, args=(), flush=1): """ """ try: - msg = self.status_messages[code] % args + msg = self.status_messages[code] %args except: - msg = '500 Unknown Response: %s.' % repr(code) + msg = self.reply_error %code self.write('%s\r\n' %msg) From srichter@cbu.edu Mon Apr 8 07:51:00 2002 From: srichter@cbu.edu (Stephan Richter) Date: Mon, 8 Apr 2002 02:51:00 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/SMTP - SMTPConfigurations.py:1.1.2.1 SMTPServer.py:1.1.2.2 SMTPServerChannel.py:1.1.2.2 SMTPStatusMessages.py:1.1.2.2 Message-ID: <200204080651.g386p0n02123@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/SMTP In directory cvs.zope.org:/tmp/cvs-serv31265/SMTP Modified Files: Tag: Zope3-Server-Branch SMTPServer.py SMTPServerChannel.py SMTPStatusMessages.py Added Files: Tag: Zope3-Server-Branch SMTPConfigurations.py Log Message: This is the first working version of the SMTP server. There is still a lot of work to be done, but it is a start. Now I need to stabalize the code and write some tests. Also, Gerson Kunze (author of Shicks!), whose code I used as a template, told me that he would be working on implementing ESMTP and a better SPAM filter, whcih should make the server even cooler. I guess we should start discussing how a possible MailService could look like. === Added File Zope3/lib/python/Zope/Server/SMTP/SMTPConfigurations.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: SMTPConfigurations.py,v 1.1.2.1 2002/04/08 06:50:27 srichter Exp $ """ # ** Relay rules ** # Specify relay level. # true: Allow relaying except from domains specified in DENY_RELAY_FROM # and to domains in DENY_RELAY_TO # false: Deny relaying except from domains specified in ALLOW_RELAY_FROM # and to domains in ALLOW_RELAY_TO RELAY_FROM = 1 ACCEPT_RELAY_FROM = ('*cbu.edu', '*zope.org') DENY_RELAY_FROM = () RELAY_TO = 1 ACCEPT_RELAY_TO = ('*.cbu.edu') DENY_RELAY_TO = () # If specified all mail is forwarded to this server. USE_RELAY_SERVER = '' # When set to true, a local sender is only allowed to send, if the connection # is coming from a local IP. STRICT_RELAY_TEST = 0 # Define some standard mail accounts ADMIN_ACCOUNT = 'foo' UNKNOWN_ACCOUNT = 'unknown' LOCAL_DOMAIN_NAME = '*cbu.edu' === Zope3/lib/python/Zope/Server/SMTP/SMTPServer.py 1.1.2.1 => 1.1.2.2 === """ import asyncore -from FTPServerChannel import FTPServerChannel +from SMTPServerChannel import SMTPServerChannel +import SMTPConfigurations from Zope.Server.ServerBase import ServerBase -from Zope.Server.Counter import Counter from Zope.Server.VFS.UnixFileSystem import UnixFileSystem from Zope.Server.Authentication.DictionaryAuthentication import \ @@ -31,34 +31,26 @@ channel_class = SMTPServerChannel SERVER_IDENT = 'Zope.Server.SMTPServer' - - relay_smtp_server_name = 'mail.cbu.edu' storage = UnixFileSystem('/opt/ZopeMail') auth_source = DictionaryAuthentication({'foo': 'bar'}) - refresh_relay_rules = 1 - relay_rules = [] - allow_unknown_receiver_default = 1 - allow_unknown_sender_default = 1 - admin_account = "" - default_local_domain = "" - unknown_account = "" - ip_address_range = None - + config = SMTPConfigurations - def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1, - hit_log=None, verbose=0, socket_map=None): + def __init__(self, ip, port, maildir, auth, task_dispatcher=None, + adj=None, start=1, hit_log=None, verbose=0, socket_map=None): super(SMTPServer, self).__init__(ip, port, task_dispatcher, adj, start, hit_log, verbose, socket_map) - self.counter = Counter() + self.auth_source = auth + self.maildir = UnixFileSystem(maildir) if __name__ == '__main__': from Zope.Server.TaskThreads import ThreadedTaskDispatcher td = ThreadedTaskDispatcher() td.setThreadCount(4) - SMTPServer('', 8025, task_dispatcher=td) + auth_source = DictionaryAuthentication({'foo': 'bar'}) + SMTPServer('', 25, '/var/mail', auth_source, task_dispatcher=td) try: while 1: asyncore.poll(5) === Zope3/lib/python/Zope/Server/SMTP/SMTPServerChannel.py 1.1.2.1 => 1.1.2.2 === (494/594 lines abridged) """ -from Zope.Server.ServerChannelBase import ServerChannelBase -from SMTPimport status_msgs -from SMTPTask import SMTPTask +import time +import fnmatch +import socket + +from Zope.Server.LineReceiver.LineServerChannel import LineServerChannel +from SMTPStatusMessages import status_msgs from ISMTPCommandHandler import ISMTPCommandHandler @@ -30,29 +33,73 @@ __implements__ = ISMTPCommandHandler # Commands that are run in a separate thread - thread_commands = ('cmd_mail', 'cmd_vrfy', 'cmd_data') + # thread_commands = ('cmd_mail', 'cmd_vrfy', 'cmd_data') # Define the authentication status of the channel. Note that only the # "special commands" can be executed without having authenticated. authenticated = 1 # Define the reply code for an unrecognized command - unknown_reply = (500, 0) + unknown_reply = 'ERR_CMD_UNKNOWN' # Define the status messages status_messages = status_msgs + # Defines the message terminator (a string sequence that signalizes the + # end of a message) + message_terminator = '.\r\n' + + # Define the Date/Time format. The Python Mail parser is very strict + # about the format of this date. + datetime_format = '%a %b %d %H:%M:%S %Y' + def __init__(self, server, conn, addr, adj=None, socket_map=None): super(SMTPServerChannel, self).__init__(server, conn, addr, adj, socket_map) + + self._from = '' + self._to = [] + self._message = '' self._sender_host = None [-=- -=- -=- 494 lines omitted -=- -=- -=-] + name = name[1:-1] + + try: + username, domain = address.split('@') + except: + username, domain = address, '' + + return '"%s" <%s@%s>' %(username, username, domain) + + + def isLocalConnection(self): + name = ip2hostname(self.addr[0]) + match = fnmatch.fnmatch(name, self.server.config.LOCAL_DOMAIN_NAME) + return match or name == 'localhost.localdomain' + + + def isLocalAddress(self, address): + # clean up the address + if address[0] == '<' or address[-1] == '>': + address = address[1:-1] + + # Split the address into it user and domain component + try: + username, domain = address.split('@') + except: + username, domain = address, '' + + if ( self.server.auth_source.hasUser(username) and + (domain.lower() == self.server.server_name or domain == '') ): + return 1 + + return 0 + + + +def ip2hostname(ip, default=None): + """Resolves an IP into a hostname""" + try: + return socket.gethostbyaddr(ip)[0] + except socket.herror: + return default + + + +def hostname2ip(hostname, default=None): + try: + return socket.gethostbyname(hostname) + except socket.gaierror: + return default + === Zope3/lib/python/Zope/Server/SMTP/SMTPStatusMessages.py 1.1.2.1 => 1.1.2.2 === status_msgs = { - 214: ("Help not available. RTFM!",), - 220: ("Zope Service ready",), - 221: ("SHICKS! Service closing transmission channel",), - 250: ('OK', - '%s', # Username and location - 'Zope 3.0 ready.', # = - 'SIZE', # | - 'VRFY', # | - 'HELP',), # +--> These are all for HELO - 251: ("User not local; will forward to ",), - 354: ("Start mail input; end with .",), - 421: ("Zope Service not available",), - 450: ("Requested mail action not taken: mailbox unavailable",), - 500: ('Syntax error, command unrecognized"',), - 501: ("Syntax error in parameters or arguments",), - 502: ("Command not implemented",), - 503: (" Bad sequence of commands",), - 504: ("Command parameter not implemented",), - 550: (" Requested action not taken: mailbox unknown", - 'String does not match anything.'), - 551: ("ACCESS DENIED.",), - 554: ("Transaction failed",), + 'OK_HELP' : '214 Help not available. RTFM!', + 'OK_WELCOME' : '220 %s Zope 3 SMTP Service ready; %s', + 'OK_QUIT' : '221 Closing transmission channel', + 'OK_NOOP' : '250 OK', + 'OK_GREETING' : '250 %s Hello %s [%s], pleased to meet you', + 'OK_FROM_ACCPT' : '250 Sender has been accepted', + 'OK_TO_ACCPT' : '250 Receiver has been accepted', + 'OK_RESET' : '250 Session reset', + 'OK_VERIFY' : '250 %s', + 'OK_DATA_RECV' : '250 Data received', + 'OK_TSFR_START' : '354 Start mail input; end with .', + + 'ERR_CMD_UNKNOWN' : '500 "%s" Syntax error, command unrecognized', + 'ERR_DOMAIN_REQ' : '501 HELO requires domain address', + 'ERR_MISS_FROM' : '501 MAIL command without "FROM:"', + 'ERR_MISS_TO' : '501 RCPT command without "TO:"', + 'ERR_USR_UNKNOWN' : '550 No user called "%s" known', + 'ERR_FROM_DENIED' : '551 Access for sender %s denied', + 'ERR_TO_DENIED' : '551 Access for sender %s denied', + 'ERR_ACC_DENIED' : '551 Data transfer access denied', } - From tdickenson@geminidataloggers.com Mon Apr 8 13:41:53 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Mon, 8 Apr 2002 08:41:53 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/zExceptions - ExceptionFormatter.py:1.3 Message-ID: <200204081241.g38CfrL19748@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/zExceptions In directory cvs.zope.org:/tmp/cvs-serv19739 Modified Files: ExceptionFormatter.py Log Message: fix string formatting for the case where __traceback_info__ is a tuple === Zope/lib/python/zExceptions/ExceptionFormatter.py 1.2 => 1.3 === def formatTracebackInfo(self, tbi): - return self.formatSupplementLine('__traceback_info__: %s' % tbi) + return self.formatSupplementLine('__traceback_info__: %s' % (tbi,)) def formatLine(self, tb): f = tb.tb_frame From shane@cvs.zope.org Mon Apr 8 18:03:58 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Mon, 8 Apr 2002 13:03:58 -0400 Subject: [Zope-Checkins] CVS: Zope/ZServer/medusa - ftp_server.py:1.20 Message-ID: <200204081703.g38H3wj08769@cvs.baymountain.com> Update of /cvs-repository/Zope/ZServer/medusa In directory cvs.zope.org:/tmp/cvs-serv8760 Modified Files: ftp_server.py Log Message: Until now, Medusa FTP passive mode sockets were blocking. Fixed. === Zope/ZServer/medusa/ftp_server.py 1.19 => 1.20 === def handle_accept (self): conn, addr = self.accept() + conn.setblocking(0) dc = self.control_channel.client_dc if dc is not None: dc.set_socket (conn) From andreas@digicool.com Mon Apr 8 19:00:25 2002 From: andreas@digicool.com (Andreas Jung) Date: Mon, 8 Apr 2002 14:00:25 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/PluginIndexes/TextIndex/Splitter/UnicodeSplitter/src - UnicodeSplitter.c:1.13.4.4 Message-ID: <200204081800.g38I0Pc26582@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/PluginIndexes/TextIndex/Splitter/UnicodeSplitter/src In directory cvs.zope.org:/tmp/cvs-serv25599/UnicodeSplitter/src Modified Files: Tag: Zope-2_5-branch UnicodeSplitter.c Log Message: Splitter were broken when the casefolding default parameter has been overwritten. === Zope/lib/python/Products/PluginIndexes/TextIndex/Splitter/UnicodeSplitter/src/UnicodeSplitter.c 1.13.4.3 => 1.13.4.4 === int allow_single_chars; int index_numbers; + int casefolding; } Splitter; static -PyUnicodeObject *prepareString(PyUnicodeObject *o); +PyUnicodeObject *prepareString(Splitter *self, PyUnicodeObject *o); static PyObject *checkSynword(Splitter *self, PyObject *word) { @@ -203,7 +204,7 @@ int i=0; int start=0; - doc1 = prepareString(doc); + doc1 = prepareString(self,doc); if (doc1 == NULL) return -1; @@ -299,18 +300,20 @@ static -PyUnicodeObject *prepareString(PyUnicodeObject *o) +PyUnicodeObject *prepareString(Splitter *self,PyUnicodeObject *o) { PyUnicodeObject *u; u = (PyUnicodeObject*) PyUnicode_FromUnicode(o->str, o->length); - if (u != NULL) - fixlower(u); + if (u != NULL){ + if (self->casefolding) + fixlower(u); + } return u; } -static char *splitter_args[]={"doc","synstop","encoding","indexnumbers","singlechar","maxlen",NULL}; +static char *splitter_args[]={"doc","synstop","encoding","indexnumbers","singlechar","maxlen","casefolding",NULL}; static PyObject * @@ -322,8 +325,9 @@ int index_numbers = 0; int max_len=64; int single_char = 0; + int casefolding=1; - if (! (PyArg_ParseTupleAndKeywords(args,keywds,"O|Osiii",splitter_args,&doc,&synstop,&encoding,&index_numbers,&single_char,&max_len))) return NULL; + if (! (PyArg_ParseTupleAndKeywords(args,keywds,"O|Osiiii",splitter_args,&doc,&synstop,&encoding,&index_numbers,&single_char,&max_len,&casefolding))) return NULL; #ifdef DEBUG puts("got text"); @@ -336,6 +340,11 @@ return NULL; } + if (casefolding<0 || casefolding>1) { + PyErr_SetString(PyExc_ValueError,"casefolding must be 0 or 1"); + return NULL; + } + if (single_char<0 || single_char>1) { PyErr_SetString(PyExc_ValueError,"singlechar must be 0 or 1"); return NULL; @@ -373,6 +382,7 @@ self->index_numbers = index_numbers; self->max_len = max_len; self->allow_single_chars = single_char; + self->casefolding = casefolding; if ((splitUnicodeString(self,(PyUnicodeObject *)unicodedoc)) < 0) goto err; @@ -391,7 +401,7 @@ { { "UnicodeSplitter", (PyCFunction)newSplitter, METH_VARARGS|METH_KEYWORDS, - "UnicodeSplitter(doc[,synstop][,encoding='latin1']) " + "UnicodeSplitter(doc[,synstop][,encoding='latin1'][,indexnumbers][,maxlen][,singlechar][,casefolding]) " "-- Return a word splitter" }, { NULL, NULL } From andreas@digicool.com Mon Apr 8 19:00:25 2002 From: andreas@digicool.com (Andreas Jung) Date: Mon, 8 Apr 2002 14:00:25 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/PluginIndexes/TextIndex/Splitter/ZopeSplitter/src - ZopeSplitter.c:1.6.4.1 Message-ID: <200204081800.g38I0P126584@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/PluginIndexes/TextIndex/Splitter/ZopeSplitter/src In directory cvs.zope.org:/tmp/cvs-serv25599/ZopeSplitter/src Modified Files: Tag: Zope-2_5-branch ZopeSplitter.c Log Message: Splitter were broken when the casefolding default parameter has been overwritten. === Zope/lib/python/Products/PluginIndexes/TextIndex/Splitter/ZopeSplitter/src/ZopeSplitter.c 1.6 => 1.6.4.1 === int index_numbers; int max_len; + int casefolding; } Splitter; @@ -170,7 +171,10 @@ continue; } - c=tolower((unsigned char) *here); + if (self->casefolding) + c = tolower((unsigned char) *here); + else + c = (unsigned char) *here; /* Check to see if this character is part of a word */ @@ -435,7 +439,7 @@ SplitterType__doc__ /* Documentation string */ }; -static char *splitter_args[]={"doc","synstop","encoding","singlechar","indexnumbers","maxlen",NULL}; +static char *splitter_args[]={"doc","synstop","encoding","singlechar","indexnumbers","maxlen","casefolding",NULL}; static PyObject * @@ -447,9 +451,17 @@ int single_char = 0; int index_numbers = 0; int max_len= 64; + int casefolding = 1; - UNLESS(PyArg_ParseTupleAndKeywords(args,keywds,"O|Osiii",splitter_args, \ - &doc,&synstop,&encoding,&single_char,&index_numbers,&max_len)) return NULL; + UNLESS(PyArg_ParseTupleAndKeywords(args,keywds,"O|Osiiii",splitter_args, \ + &doc, + &synstop, + &encoding, + &single_char, + &index_numbers, + &max_len, + &casefolding + )) return NULL; if (index_numbers<0 || index_numbers>1) { @@ -457,6 +469,11 @@ return NULL; } + if (casefolding<0 || casefolding>1) { + PyErr_SetString(PyExc_ValueError,"casefolding must be 0 or 1"); + return NULL; + } + if (single_char<0 || single_char>1) { PyErr_SetString(PyExc_ValueError,"singlechar must be 0 or 1"); return NULL; @@ -486,6 +503,7 @@ self->allow_single_chars = single_char; self->index_numbers = index_numbers; self->max_len = max_len; + self->casefolding = casefolding; return (PyObject*)self; @@ -498,7 +516,7 @@ static struct PyMethodDef Splitter_module_methods[] = { { "ZopeSplitter", (PyCFunction)get_Splitter, METH_VARARGS|METH_KEYWORDS, - "ZopeSplitter(doc[,synstop][,encoding][,singlechar][,indexnumbers][,maxlen]) -- Return a word splitter" + "ZopeSplitter(doc[,synstop][,encoding][,singlechar][,indexnumbers][,maxlen][,casefolding]) -- Return a word splitter" }, { NULL, NULL } @@ -517,7 +535,6 @@ initZopeSplitter(void) { PyObject *m, *d; - char *rev="$Revision$"; /* Create the module and add the functions */ m = Py_InitModule4("ZopeSplitter", Splitter_module_methods, @@ -526,8 +543,6 @@ /* Add some symbolic constants to the module */ d = PyModule_GetDict(m); - PyDict_SetItemString(d, "__version__", - PyString_FromStringAndSize(rev+11,strlen(rev+11)-2)); if (PyErr_Occurred()) Py_FatalError("can't initialize module Splitter"); From andreas@digicool.com Mon Apr 8 19:00:55 2002 From: andreas@digicool.com (Andreas Jung) Date: Mon, 8 Apr 2002 14:00:55 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/PluginIndexes/TextIndex/Splitter/ISO_8859_1_Splitter/src - ISO_8859_1_Splitter.c:1.6.4.4 Message-ID: <200204081800.g38I0t426624@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/PluginIndexes/TextIndex/Splitter/ISO_8859_1_Splitter/src In directory cvs.zope.org:/tmp/cvs-serv25599/ISO_8859_1_Splitter/src Modified Files: Tag: Zope-2_5-branch ISO_8859_1_Splitter.c Log Message: Splitter were broken when the casefolding default parameter has been overwritten. === Zope/lib/python/Products/PluginIndexes/TextIndex/Splitter/ISO_8859_1_Splitter/src/ISO_8859_1_Splitter.c 1.6.4.3 => 1.6.4.4 === int index_numbers; int max_len; + int casefolding; } Splitter; @@ -251,7 +252,10 @@ continue; } - c=mytolower(*here); + if (self->casefolding) + c=mytolower(*here); + else + c = (*here); /* Check to see if this character is part of a word */ @@ -490,7 +494,7 @@ SplitterType__doc__ /* Documentation string */ }; -static char *splitter_args[]={"doc","synstop","encoding","singlechar","indexnumbers","maxlen",NULL}; +static char *splitter_args[]={"doc","synstop","encoding","singlechar","indexnumbers","maxlen","casefolding",NULL}; static PyObject * get_Splitter(PyObject *modinfo, PyObject *args,PyObject *keywds) @@ -501,8 +505,9 @@ int single_char = 0; int index_numbers = 0; int max_len=64; + int casefolding=1; - UNLESS(PyArg_ParseTupleAndKeywords(args,keywds,"O|Osiii",splitter_args,&doc,&synstop,&encoding,&single_char,&index_numbers,&max_len)) return NULL; + UNLESS(PyArg_ParseTupleAndKeywords(args,keywds,"O|Osiiii",splitter_args,&doc,&synstop,&encoding,&single_char,&index_numbers,&max_len,&casefolding)) return NULL; if (index_numbers<0 || index_numbers>1) { @@ -510,6 +515,11 @@ return NULL; } + if (casefolding<0 || casefolding>1) { + PyErr_SetString(PyExc_ValueError,"casefolding must be 0 or 1"); + return NULL; + } + if (single_char<0 || single_char>1) { PyErr_SetString(PyExc_ValueError,"singlechar must be 0 or 1"); return NULL; @@ -521,7 +531,6 @@ } - UNLESS(self = PyObject_NEW(Splitter, &SplitterType)) return NULL; if(synstop) { @@ -539,6 +548,7 @@ self->allow_single_chars = single_char; self->index_numbers = index_numbers; self->max_len = max_len; + self->casefolding = casefolding; self->index = -1; @@ -553,7 +563,7 @@ static struct PyMethodDef Splitter_module_methods[] = { { "ISO_8859_1_Splitter", (PyCFunction)get_Splitter, METH_VARARGS|METH_KEYWORDS, - "ISO_8859_1_Splitter(doc[,synstop][,encoding][,singlechar][,indexnumbers][,maxlen]) -- Return a word splitter" + "ISO_8859_1_Splitter(doc[,synstop][,encoding][,singlechar][,indexnumbers][,maxlen][,casefolding]) -- Return a word splitter" }, { NULL, NULL } From shane@cvs.zope.org Mon Apr 8 21:17:42 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Mon, 8 Apr 2002 16:17:42 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server - ServerChannelBase.py:1.1.2.6 Message-ID: <200204082017.g38KHgF10136@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server In directory cvs.zope.org:/tmp/cvs-serv10125 Modified Files: Tag: Zope3-Server-Branch ServerChannelBase.py Log Message: Protect against running multiple tasks at once. === Zope3/lib/python/Zope/Server/ServerChannelBase.py 1.1.2.5 => 1.1.2.6 === *** For thread safety, this should only be called from the main (async) thread. ***""" + if self.running_tasks: + # Can't start while another task is running! + # Otherwise two threads would work on the queue at the same time. + raise RuntimeError, 'Already executing tasks' self.running_tasks = 1 self.set_sync() self.server.addTask(task) From shane@cvs.zope.org Mon Apr 8 21:19:03 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Mon, 8 Apr 2002 16:19:03 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/LineReceiver - LineCommandParser.py:1.1.2.4 Message-ID: <200204082019.g38KJ3K10958@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/LineReceiver In directory cvs.zope.org:/tmp/cvs-serv10798 Modified Files: Tag: Zope3-Server-Branch LineCommandParser.py Log Message: Removed debugging code === Zope3/lib/python/Zope/Server/LineReceiver/LineCommandParser.py 1.1.2.3 => 1.1.2.4 === def parseLine(self, line): - print line parts = line.split(' ', 1) if len(parts) == 2: self.cmd, self.args = parts From shane@cvs.zope.org Mon Apr 8 21:19:19 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Mon, 8 Apr 2002 16:19:19 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/LineReceiver - LineServerChannel.py:1.1.2.6 LineTask.py:1.1.2.3 Message-ID: <200204082019.g38KJJE11350@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/LineReceiver In directory cvs.zope.org:/tmp/cvs-serv10982 Modified Files: Tag: Zope3-Server-Branch LineServerChannel.py LineTask.py Log Message: More exception handling === Zope3/lib/python/Zope/Server/LineReceiver/LineServerChannel.py 1.1.2.5 => 1.1.2.6 === import stat import socket +import sys import time from Zope.Server.ServerChannelBase import ServerChannelBase @@ -60,6 +61,7 @@ # Define the status messages status_messages = { 'CMD_UNKNOWN' : "500 '%s': command not understood.", + 'INTERNAL_ERROR' : "500 Internal error: %s", 'LOGIN_REQUIRED' : '530 Please log in with USER and PASS', } @@ -84,8 +86,7 @@ try: getattr(self, method)(command.args) except: - import traceback - traceback.print_exc() + self.exception() else: self.reply(self.unknown_reply, cmd.upper()) return None @@ -104,3 +105,13 @@ self.flush(0) # XXX: Some logging should go on here. + + + def exception(self): + t, v = sys.exc_info()[:2] + try: + info = '%s: %s' % (getattr(t, '__name__', t), v) + except: + info = str(t) + self.reply('INTERNAL_ERROR', info) + self.handle_error() === Zope3/lib/python/Zope/Server/LineReceiver/LineTask.py 1.1.2.2 => 1.1.2.3 === if self.channel.adj.log_socket_errors: raise + except: + self.channel.exception() finally: self.channel.end_task(self.close_on_finish) From shane@cvs.zope.org Mon Apr 8 21:21:38 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Mon, 8 Apr 2002 16:21:38 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - IReadFileSystem.py:1.1.2.4 IWriteFileSystem.py:1.1.2.4 OSFileSystem.py:1.1.2.12 Message-ID: <200204082021.g38KLcB12741@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv12552 Modified Files: Tag: Zope3-Server-Branch IReadFileSystem.py IWriteFileSystem.py OSFileSystem.py Log Message: Removed the open() method and replaced it with readfile(), writefile(), and check_writable(). These are more transaction-friendly. === Zope3/lib/python/Zope/Server/VFS/IReadFileSystem.py 1.1.2.3 => 1.1.2.4 === """ - def open(path, mode): - """Return an open file object. + def readfile(path, mode, outstream, start=0, end=-1): + """Outputs the file at path to a stream. """ - return file def stat(path): """Return the equivalent of os.stat() on the given path: === Zope3/lib/python/Zope/Server/VFS/IWriteFileSystem.py 1.1.2.3 => 1.1.2.4 === """ - def unlink(path): - """Remove file. Same as remove. + def writefile(path, mode, instream, start=0): + """Write data to a file. """ - def write(fd, data): - """Write the data to a file descriptor. + def check_writable(path, mode): + """Ensures a path is writable. Throws an IOError if not.""" - Returns the number of bytes written. - """ - - return int === Zope3/lib/python/Zope/Server/VFS/OSFileSystem.py 1.1.2.11 => 1.1.2.12 === path_module = os.path + copy_bytes = 65536 + def __init__ (self, root): self.root = root @@ -87,10 +89,22 @@ return unix_longify(path, stat_info) - def open(self, path, mode): + def readfile(self, path, mode, outstream, start=0, end=-1): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' p = self.translate(path) - return open(p, mode) + instream = open(p, mode) + if start: + instream.seek(start) + pos = start + while end < 0 or pos < end: + toread = self.copy_bytes + if end >= 0: + toread = min(toread, end - pos) + data = instream.read(toread) + if not data: + break + pos += len(data) + outstream.write(data) def stat(self, path): @@ -161,15 +175,30 @@ return os.symlink(src, dst) - def unlink(self, path): + def writefile(self, path, mode, instream, start=0): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' p = self.translate(path) - return os.unlink(p) - + outstream = open(p, mode) + if start: + outstream.seek(start) + while 1: + data = instream.read(self.copy_bytes) + if not data: + break + outstream.write(data) - def write(self, fd, data): + def check_writable(self, path, mode): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' - return os.write(fd, data) + p = self.translate(path) + if os.path.exists(p): + remove = 0 + else: + remove = 1 + f = open(p, 'a') # append mode + f.close() + if remove: + os.remove(p) + # ############################################################ From shane@cvs.zope.org Mon Apr 8 21:32:17 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Mon, 8 Apr 2002 16:32:17 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - PassiveAcceptor.py:1.1.2.3 Message-ID: <200204082032.g38KWH218614@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv18436 Modified Files: Tag: Zope3-Server-Branch PassiveAcceptor.py Log Message: Made sure data connections don't block. === Zope3/lib/python/Zope/Server/FTP/PassiveAcceptor.py 1.1.2.2 => 1.1.2.3 === def handle_accept (self): conn, addr = self.accept() + conn.setblocking(0) dc = self.control_channel.client_dc if dc is not None: dc.set_socket(conn) @@ -75,3 +76,4 @@ else: self.ready = conn, addr self.close() + From shane@cvs.zope.org Mon Apr 8 21:33:12 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Mon, 8 Apr 2002 16:33:12 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP/tests - testFTPServer.py:1.1.2.3 Message-ID: <200204082033.g38KXCi18866@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP/tests In directory cvs.zope.org:/tmp/cvs-serv18622/tests Modified Files: Tag: Zope3-Server-Branch testFTPServer.py Log Message: - Used new readfile(), writefile(), and check_writable() methods. This involved some new complexity, since we can't send the 150 response until the VFS confirms the file is accessible, but it's better to have this complexity in the FTP server than in the VFS implementation, which open() would have required. - Improved some status messages. - Redid the LIST test, added a STOR test, and re-enabled the socket leak detection. === Zope3/lib/python/Zope/Server/FTP/tests/testFTPServer.py 1.1.2.2 => 1.1.2.3 === import socket from types import StringType +from StringIO import StringIO from threading import Thread from Zope.Server.TaskThreads import ThreadedTaskDispatcher @@ -50,6 +51,12 @@ my_adj.inbuf_overflow = 10000 +def retrlines(ftpconn, cmd): + res = [] + ftpconn.retrlines(cmd, res.append) + return ''.join(res) + + class Tests(unittest.TestCase): def setUp(self): @@ -81,15 +88,14 @@ self.server.close() # Make sure all sockets get closed by asyncore normally. timeout = time() + 5 - #while 1: - # if len(socket_map) == self.orig_map_size: - # # Clean! - # break - # if time() >= timeout: - # print 'Leaked a socket: %s' % `socket_map` - # break - # #self.fail('Leaked a socket: %s' % `socket_map`) - # poll(0.1, socket_map) + while 1: + if len(socket_map) == self.orig_map_size: + # Clean! + break + if time() >= timeout: + self.fail('Leaked a socket: %s' % `socket_map`) + break + poll(0.1, socket_map) def loop(self): @@ -119,16 +125,18 @@ def execute(self, commands, login=1): ftp = self.getFTPConnection(login) - if type(commands) is StringType: - commands = (commands,) - - for command in commands: - ftp.send('%s\r\n' %command) - result = ftp.recv(10000) - #print result[:-2] - - self.failUnless(result.endswith('\r\n')) - ftp.close() + try: + if type(commands) is StringType: + commands = (commands,) + + for command in commands: + ftp.send('%s\r\n' %command) + result = ftp.recv(10000) + #print result[:-2] + + self.failUnless(result.endswith('\r\n')) + finally: + ftp.close() return result[:-2] @@ -155,10 +163,10 @@ open(os.path.join(self.root_dir, 'foo'), 'w').write('blah') self.assertEqual(self.execute('DELE foo', 1), status_msgs['SUCCESS_250'] %'DELE') - self.assertEqual(self.execute('DELE bar', 1), - status_msgs['ERR_DELETE_FILE']) + res = self.execute('DELE bar', 1).split()[0] + self.assertEqual(res, '550') self.assertEqual(self.execute('DELE', 1), - status_msgs['CMD_UNKNOWN'] %'DELE') + status_msgs['ERR_ARGS']) def testHELP(self): @@ -169,14 +177,18 @@ self.assertEqual(self.execute('HELP', 1), result) - # def testLIST(self): - # path = os.path.join(self.root_dir, 'foo') - # result = "[Errno 2] No such file or directory: '%s'" %path - # - # self.assertEqual(self.execute('LIST /foo', 1), - # status_msgs['ERR_NO_LIST'] %result) - # self.assertEqual(self.execute('LIST', 1), - # status_msgs['SUCCESS_200'] %'NOOP') + def testLIST(self): + conn = ftplib.FTP() + try: + conn.connect(LOCALHOST, self.port) + conn.login('foo', 'bar') + self.assertRaises(ftplib.Error, retrlines, conn, 'LIST /foo') + listing = retrlines(conn, 'LIST') + self.assert_(len(listing) > 0) + finally: + conn.close() + # Make sure no garbage was left behind. + self.testNOOP() def testNOOP(self): @@ -200,11 +212,29 @@ status_msgs['GOODBYE']) + def testSTOR(self): + conn = ftplib.FTP() + try: + conn.connect(LOCALHOST, self.port) + conn.login('foo', 'bar') + fp = StringIO('Speak softly') + # Can't overwrite directory + self.assertRaises( + ftplib.error_perm, conn.storbinary, 'STOR /test', fp) + fp = StringIO('Charity never faileth') + # Successful write + conn.storbinary('STOR /stuff', fp) + finally: + conn.close() + # Make sure no garbage was left behind. + self.testNOOP() + + def testUSER(self): self.assertEqual(self.execute('USER foo', 0), status_msgs['PASS_REQUIRED']) self.assertEqual(self.execute('USER', 0), - status_msgs['CMD_UNKNOWN'] %'USER') + status_msgs['ERR_ARGS']) From shane@cvs.zope.org Mon Apr 8 21:33:12 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Mon, 8 Apr 2002 16:33:12 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - FTPServerChannel.py:1.1.2.16 FTPStatusMessages.py:1.1.2.8 RecvChannel.py:1.1.2.6 XmitChannel.py:1.1.2.5 Message-ID: <200204082033.g38KXCX18865@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv18622 Modified Files: Tag: Zope3-Server-Branch FTPServerChannel.py FTPStatusMessages.py RecvChannel.py XmitChannel.py Log Message: - Used new readfile(), writefile(), and check_writable() methods. This involved some new complexity, since we can't send the 150 response until the VFS confirms the file is accessible, but it's better to have this complexity in the FTP server than in the VFS implementation, which open() would have required. - Improved some status messages. - Redid the LIST test, added a STOR test, and re-enabled the socket leak detection. === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.15 => 1.1.2.16 === import os import stat +import sys import socket import time @@ -27,7 +28,7 @@ from IFTPCommandHandler import IFTPCommandHandler from PassiveAcceptor import PassiveAcceptor from RecvChannel import RecvChannel -from XmitChannel import XmitChannel +from XmitChannel import XmitChannel, ApplicationXmitStream class FTPServerChannel(LineServerChannel): @@ -94,9 +95,10 @@ def cmd_abor(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' - if self.client_dc: - self.client_dc.close() - self.reply('TRANSFER_ABORTED') + if self.client_dc is not None: + self.client_dc.close('TRANSFER_ABORTED') + else: + self.reply('TRANSFER_ABORTED') def cmd_appe (self, args): @@ -127,17 +129,16 @@ def cmd_dele(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' if not args: - self.reply('CMD_UNKNOWN', 'DELE') - else: - path = self._generatePath(args) + self.reply('ERR_ARGS') + return + path = self._generatePath(args) - try: - self.server.filesystem.unlink(path) - self.reply('SUCCESS_250', 'DELE') - except: - self.reply('ERR_DELETE_FILE') - else: - self.reply('NO_FILE', file) + try: + self.server.filesystem.remove(path) + except OSError, err: + self.reply('ERR_DELETE_FILE', str(err)) + else: + self.reply('SUCCESS_250', 'DELE') def cmd_help(self, args): @@ -152,16 +153,17 @@ args = args.split() try: s = self.getDirectoryList(args, long) - except os.error, why: - self.reply('ERR_NO_LIST', str(why)) + except OSError, err: + self.reply('ERR_NO_LIST', str(err)) return + ok_reply = ('OPEN_DATA_CONN', self.type_map[self.transfer_mode]) + cdc = XmitChannel(self, ok_reply) + self.client_dc = cdc try: - self.reply('OPEN_DATA_CONN', self.type_map[self.transfer_mode]) - self.openDataChannel(XmitChannel, s) - finally: - if hasattr(s, 'close'): - # Close the stream. - s.close() + cdc.write(s) + cdc.close_when_done() + except OSError, err: + cdc.close('ERR_NO_LIST', str(err)) def cmd_mdtm(self, args): @@ -180,15 +182,15 @@ def cmd_mkd(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' if not args: - self.reply('CMD_UNKNOWN', 'MKD') + self.reply('ERR_ARGS') + return + path = self._generatePath(args) + try: + self.server.filesystem.mkdir(path) + except OSError, err: + self.reply('ERR_CREATE_DIR', str(err)) else: - path = self._generatePath(args) - - try: - self.server.filesystem.mkdir(path) - self.reply('SUCCESS_257', 'MKD') - except: - self.reply('ERR_CREATE_DIR') + self.reply('SUCCESS_257', 'MKD') def cmd_mode(self, args): @@ -236,18 +238,15 @@ def cmd_port(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' - try: - info = args.split(',') - ip = '.'.join(info[:4]) - port = int(info[4])*256 + int(info[5]) - # how many data connections at a time? - # I'm assuming one for now... - # XXX: we should (optionally) verify that the - # ip number belongs to the client. [wu-ftpd does this?] - self.client_addr = (ip, port) - self.reply('SUCCESS_200', 'PORT') - except: - return self.reply('CMD_UNKNOWN', 'PORT') + info = args.split(',') + ip = '.'.join(info[:4]) + port = int(info[4])*256 + int(info[5]) + # how many data connections at a time? + # I'm assuming one for now... + # XXX: we should (optionally) verify that the + # ip number belongs to the client. [wu-ftpd does this?] + self.client_addr = (ip, port) + self.reply('SUCCESS_200', 'PORT') def cmd_pwd(self, args): @@ -265,38 +264,32 @@ 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' if not args: self.reply('CMD_UNKNOWN', 'RETR') - else: - path = self._generatePath(args) + path = self._generatePath(args) - if not self.server.filesystem.isfile(path): - self.reply('ERR_IS_NOT_FILE', path) - else: - try: - mode = 'r' + self.type_mode_map[self.transfer_mode] - fd = self.server.filesystem.open(path, mode) - except IOError, why: - self.reply('ERR_OPEN_READ', str(why)) - return - try: - self.reply('OPEN_CONN', - (self.type_map[self.transfer_mode], path) ) - - if self.restart_position: - # try to position the file as requested, but - # give up silently on failure (the 'file object' - # may not support seek()) - try: - fd.seek(self.restart_position) - except: - pass - self.restart_position = 0 - - self.openDataChannel(XmitChannel, fd) - - finally: - if hasattr(fd, 'close'): - # Close the stream. - fd.close() + if not self.server.filesystem.isfile(path): + self.reply('ERR_IS_NOT_FILE', path) + return + + mode = 'r' + self.type_mode_map[self.transfer_mode] + start = 0 + if self.restart_position: + start = self.restart_position + self.restart_position = 0 + + ok_reply = ( + 'OPEN_CONN', (self.type_map[self.transfer_mode], path) ) + cdc = XmitChannel(self, ok_reply) + self.client_dc = cdc + outstream = ApplicationXmitStream(cdc) + + try: + self.server.filesystem.readfile( + path, mode, outstream, start) + cdc.close_when_done() + except OSError, err: + cdc.close('ERR_OPEN_READ', str(err)) + except IOError, err: + cdc.close('ERR_IO', str(err)) def cmd_rest(self, args): @@ -304,7 +297,8 @@ try: pos = int(args) except ValueError: - self.reply('CMD_UNKNWON', 'REST') + self.reply('ERR_ARGS') + return self.restart_position = pos self.reply('RESTART_TRANSFER', pos) @@ -312,14 +306,15 @@ def cmd_rmd(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' if not args: - self.reply('CMD_UNKNOWN', 'RMD') + self.reply('ERR_ARGS') + return + path = self._generatePath(args) + try: + self.server.filesystem.rmdir(path) + except OSError, err: + self.reply('ERR_DELETE_DIR', str(err)) else: - path = self._generatePath(args) - try: - self.server.filesystem.rmdir(path) - self.reply('SUCCESS_250', 'RMD') - except: - self.reply('ERR_DELETE_DIR') + self.reply('SUCCESS_250', 'RMD') def cmd_rnfr(self, args): @@ -339,9 +334,10 @@ self.reply('ERR_RENAME') try: self.server.filesystem.rename(self._rnfr, path) + except OSError, err: + self.reply('ERR_RENAME', (self._rnfr, rnto, str(err))) + else: self.reply('SUCCESS_250', 'RNTO') - except: - self.reply('ERR_RENAME', (self._rnfr, rnto)) self._rnfr = None @@ -358,50 +354,49 @@ def cmd_stor(self, args, write_mode='w'): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' if not args: - self.reply('CMD_UNKNOWN', 'STOR') - else: - path = self._generatePath(args) + self.reply('ERR_ARGS') + return + path = self._generatePath(args) - if self.restart_position: - restart_position = 0 - self.reply('ERR_RESTART_STOR') - return - mode = write_mode + self.type_mode_map[self.transfer_mode] + start = 0 + if self.restart_position: + self.start = self.restart_position + restart_position = 0 + mode = write_mode + self.type_mode_map[self.transfer_mode] - try: - # Optionally verify the file can be opened, - # but don't open it yet. The actually write - # should be transactional without holding up the - # application. - fs = self.server.filesystem - if hasattr(fs, 'check_open'): - fs.check_open(path, mode) - except IOError, why: - self.reply('ERR_OPEN_WRITE', str(why)) - return - self.reply('OPEN_CONN', (self.type_map[self.transfer_mode], file) ) - self.openDataChannel(RecvChannel, (path, mode)) + try: + # Verify the file can be opened, but don't open it yet. + # The actually write should be transactional without + # holding up the application. + fs = self.server.filesystem + fs.check_writable(path, mode) + except OSError, err: + self.reply('ERR_OPEN_WRITE', str(err)) + return + except IOError, err: + self.reply('ERR_IO', str(err)) + return + cdc = RecvChannel(self, (path, mode, start)) + self.client_dc = cdc + self.reply('OPEN_CONN', (self.type_map[self.transfer_mode], path)) + self.connectDataChannel(cdc) - def finishedRecv(self, buffer, path, mode): + def finishedRecv(self, buffer, (path, mode, start)): """Called by RecvChannel when the transfer is finished.""" # Always called in a task. try: - outfile = self.server.filesystem.open(path, mode) - try: - copy_bytes = self.adj.copy_bytes - while 1: - data = buffer.get(copy_bytes) - if not data: - break - buffer.skip(len(data), 1) - outfile.write(data) - finally: - outfile.close() - except IOError, why: - self.reply('ERR_OPEN_WRITE', str(why)) - return - self.reply('TRANS_SUCCESS') + infile = buffer.getfile() + infile.seek(0) + self.server.filesystem.writefile(path, mode, infile, start) + except OSError, err: + self.reply('ERR_OPEN_WRITE', str(err)) + except IOError, err: + self.reply('ERR_IO', str(err)) + except: + self.exception() + else: + self.reply('TRANS_SUCCESS') def cmd_stru(self, args): @@ -425,7 +420,7 @@ # no support for EBCDIC # if t not in ['a','e','i','l']: if t not in ['a','i','l']: - self.reply('CMD_UNKNOWN', 'TYPE') + self.reply('ERR_ARGS') elif t == 'l' and (len(args) > 2 and args[2] != '8'): self.reply('WRONG_BYTE_SIZE') @@ -441,7 +436,7 @@ self.username = args self.reply('PASS_REQUIRED') else: - self.reply('CMD_UNKNOWN', 'USER') + self.reply('ERR_ARGS') # ############################################################ @@ -466,8 +461,12 @@ def listdir (self, path, long=0): - """returns a string or stream""" - return self.server.filesystem.listdir(path, long) + """returns a string""" + res = self.server.filesystem.listdir(path, long) + if hasattr(res, 'read'): + # Dump the stream. + res = res.read() + return res def getDirectoryList(self, args, long=0): @@ -488,33 +487,34 @@ return self.listdir(dir, long) - def openDataChannel(self, class_, *args): + def connectDataChannel(self, cdc): pa = self.passive_acceptor if pa: # PASV mode. if pa.ready: # a connection has already been made. conn, addr = pa.ready - cdc = class_(self, addr, *args) cdc.set_socket (conn) cdc.connected = 1 self.passive_acceptor.close() self.passive_acceptor = None - else: - # we're still waiting for a connect to the PASV port. - # FTP Explorer is known to do this. - cdc = class_(self, None, *args) + # else we're still waiting for a connect to the PASV port. + # FTP Explorer is known to do this. else: # not in PASV mode. ip, port = self.client_addr - cdc = class_(self, self.client_addr, *args) cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) if self.bind_local_minus_one: cdc.bind(('', self.server.port - 1)) try: cdc.connect((ip, port)) - except socket.error, why: - self.reply(425) + except socket.error, err: + cdc.close('NO_DATA_CONN') - self.client_dc = cdc + + def notifyClientDCClosing(self, *reply_args): + if self.client_dc is not None: + self.client_dc = None + if reply_args: + self.reply(*reply_args) === Zope3/lib/python/Zope/Server/FTP/FTPStatusMessages.py 1.1.2.7 => 1.1.2.8 === 'TRANSFER_ABORTED' : '426 Connection closed; transfer aborted.', 'CMD_UNKNOWN' : "500 '%s': command not understood.", + 'INTERNAL_ERROR' : "500 Internal error: %s", + 'ERR_ARGS' : '500 Bad command arguments', 'MODE_UNKOWN' : '502 Unimplemented MODE type', 'WRONG_BYTE_SIZE' : '504 Byte size must be 8', 'STRU_UNKNOWN' : '504 Unimplemented STRU type', @@ -57,13 +59,13 @@ 'ERR_NO_FILE' : '550 "%s": No such file.', 'ERR_IS_NOT_FILE' : '550 "%s": Is not a file', 'ERR_CREATE_FILE' : '550 Error creating file.', - 'ERR_CREATE_DIR' : '550 Error creating directory.', - 'ERR_DELETE_FILE' : '550 Error deleting file.', - 'ERR_DELETE_DIR' : '550 Error removing directory.', + 'ERR_CREATE_DIR' : '550 Error creating directory: %s', + 'ERR_DELETE_FILE' : '550 Error deleting file: %s', + 'ERR_DELETE_DIR' : '550 Error removing directory: %s', 'ERR_OPEN_READ' : '553 Could not open file for reading: %s', 'ERR_OPEN_WRITE' : '553 Could not open file for writing: %s', - 'ERR_RESTART_STOR' : '553 Restart on STOR not yet supported', - 'ERR_RENAME' : '560 Could not rename "%s" to "%s".', + 'ERR_IO' : '553 I/O Error: %s', + 'ERR_RENAME' : '560 Could not rename "%s" to "%s": %s', 'ERR_RNFR_SOURCE' : '560 No source filename specify. Call RNFR first.', } === Zope3/lib/python/Zope/Server/FTP/RecvChannel.py 1.1.2.5 => 1.1.2.6 === """ """ - def __init__ (self, cmd_channel, client_addr, finish_args, + complete_transfer = 0 + _fileno = None # provide a default for asyncore.dispatcher._fileno + + def __init__ (self, control_channel, finish_args, adj=None, socket_map=None): - self.cmd_channel = cmd_channel - self.client_addr = client_addr + self.control_channel = control_channel self.finish_args = finish_args + self.inbuf = OverflowableBuffer(control_channel.adj.inbuf_overflow) ChannelBaseClass.__init__(self, None, None, adj, socket_map) - self.inbuf = OverflowableBuffer(self.adj.inbuf_overflow) - -## def log (self, *ignore): -## pass + # Note that this channel starts out in async mode. def writable (self): return 0 @@ -41,25 +41,41 @@ pass def received (self, data): - self.inbuf.append(data) + if data: + self.inbuf.append(data) def handle_close (self): - c = self.cmd_channel + """Client closed, indicating EOF.""" + c = self.control_channel task = FinishedRecvTask(c, self.inbuf, self.finish_args) + self.complete_transfer = 1 self.close() - self.cmd_channel = None c.start_task(task) + def close(self, *reply_args): + try: + c = self.control_channel + if c is not None: + self.control_channel = None + if not self.complete_transfer and not reply_args: + # Not all data transferred + reply_args = ('TRANSFER_ABORTED',) + c.notifyClientDCClosing(*reply_args) + finally: + if self.socket is not None: + # XXX asyncore.dispatcher.close() doesn't like socket == None + ChannelBaseClass.close(self) + class FinishedRecvTask: __implements__ = ITask - def __init__(self, cmd_channel, inbuf, args): - self.cmd_channel = cmd_channel + def __init__(self, control_channel, inbuf, finish_args): + self.control_channel = control_channel self.inbuf = inbuf - self.args = args + self.finish_args = finish_args ############################################################ @@ -70,10 +86,10 @@ """Called to execute the task. """ close_on_finish = 0 - c = self.cmd_channel + c = self.control_channel try: try: - c.finishedRecv(self.inbuf, *self.args) + c.finishedRecv(self.inbuf, self.finish_args) except socket.error: close_on_finish = 1 if c.adj.log_socket_errors: @@ -84,7 +100,7 @@ def cancel(self): 'See Zope.Server.ITask.ITask' - self.cmd_channel.close_when_done() + self.control_channel.close_when_done() def defer(self): === Zope3/lib/python/Zope/Server/FTP/XmitChannel.py 1.1.2.4 => 1.1.2.5 === class XmitChannel(ChannelBaseClass): - def __init__ (self, cmd_channel, client_addr, s, + opened = 0 + _fileno = None # provide a default for asyncore.dispatcher._fileno + + def __init__ (self, control_channel, ok_reply_args, adj=None, socket_map=None): - self.cmd_channel = cmd_channel - self.client_addr = client_addr + self.control_channel = control_channel + self.ok_reply_args = ok_reply_args + self.set_sync() ChannelBaseClass.__init__(self, None, None, adj, socket_map) - # Send the stream and close when finished. - self.writeAll(s) - self.close_when_done() - - def writeAll(self, s): - """Sends a stream or string. - - Returns the number of bytes sent. - """ - sent = 0 - if hasattr(s, 'read'): - # s is a stream. - copy_bytes = self.adj.copy_bytes - while 1: - data = s.read(copy_bytes) - if not data: - break - sent += len(data) - self.write(data) - else: - # s is a string. - sent = len(s) - self.write(s) - return sent + + def _open(self): + """Signal the client to open the connection.""" + self.opened = 1 + self.control_channel.reply(*self.ok_reply_args) + self.control_channel.connectDataChannel(self) + + def write(self, data): + if self.control_channel is None: + raise IOError, 'Client FTP connection closed' + if not self.opened: + self._open() + ChannelBaseClass.write(self, data) def readable(self): return not self.connected + def handle_read(self): + # This is only called when making the connection. + try: + self.recv(1) + except: + # The connection failed. + self.close('NO_DATA_CONN') + def handle_connect(self): pass def handle_comm_error(self): - if self.adj.log_socket_errors: - self.handle_error() - else: - self.close() - - def close (self): - c = self.cmd_channel - s = c.server - c.client_dc = None - #s.total_files_out += 1 - #s.total_bytes_out += self.bytes_out - if not len(self.outbuf): - # All data transferred - c.reply('TRANS_SUCCESS') - else: - # Not all data transferred - c.reply('TRANSFER_ABORTED') - del c - del s - del self.cmd_channel - ChannelBaseClass.close(self) + self.close('TRANSFER_ABORTED') + + def close(self, *reply_args): + try: + c = self.control_channel + if c is not None: + self.control_channel = None + if not reply_args: + if not len(self.outbuf): + # All data transferred + if not self.opened: + # Zero-length file + self._open() + reply_args = ('TRANS_SUCCESS',) + else: + # Not all data transferred + reply_args = ('TRANSFER_ABORTED',) + c.notifyClientDCClosing(*reply_args) + finally: + if self.socket is not None: + # XXX asyncore.dispatcher.close() doesn't like socket == None + ChannelBaseClass.close(self) + + +class ApplicationXmitStream: + """Provide stream output, remapping close() to close_when_done(). + """ + + def __init__(self, xmit_channel): + self.write = xmit_channel.write + self.flush = xmit_channel.flush + self.close = xmit_channel.close_when_done From shane@cvs.zope.org Mon Apr 8 21:49:21 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Mon, 8 Apr 2002 16:49:21 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS/tests - testOSFileSystem.py:1.1.2.7 Message-ID: <200204082049.g38KnLE25750@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS/tests In directory cvs.zope.org:/tmp/cvs-serv25380 Modified Files: Tag: Zope3-Server-Branch testOSFileSystem.py Log Message: Brought OSFilesystem tests up to date === Zope3/lib/python/Zope/Server/VFS/tests/testOSFileSystem.py 1.1.2.6 => 1.1.2.7 === import stat import tempfile +from StringIO import StringIO from Interface.Verify import verifyClass from Zope.Server.VFS.IReadFileSystem import IReadFileSystem @@ -120,10 +121,12 @@ os.remove(path) - def testOpen(self): + def testReadfile(self): path = os.path.join(self.root, 'foo') open(path, 'w').write('writing test') - self.assertEqual(self.filesystem.open('foo', 'r').read(), 'writing test') + s = StringIO() + self.filesystem.readfile('foo', 'r', s) + self.assertEqual(s.getvalue(), 'writing test') os.remove(path) @@ -207,19 +210,31 @@ os.remove(path+'1') - def testUnlink(self): + def testWritefile(self): + s = StringIO('foo bar') + self.filesystem.writefile('foo', 'w', s) path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - self.filesystem.unlink('foo') - self.failIf(os.path.exists(path)) - - - def testWrite(self): - path = os.path.join(self.root, 'foo') - file = open(path, 'w') - self.assertEqual(self.filesystem.write(file.fileno(), 'foo bar'), 7) + file = open(path, 'r') + self.assertEqual(file.read(), 'foo bar') file.close() os.remove(path) + + + def testCheckWriteable(self): + s = StringIO() + dirpath = os.path.join(self.root, 'somename') + os.mkdir(dirpath) + try: + # Can't overwrite a directory. + self.assertRaises( + IOError, self.filesystem.writefile, 'somename', 'w', s) + finally: + os.rmdir(dirpath) + try: + # Now it's ok. + self.filesystem.writefile('somename', 'w', s) + finally: + os.remove(dirpath) def testInterface(self): From srichter@cbu.edu Tue Apr 9 09:16:25 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 04:16:25 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Interface - pyskel.py:1.1.2.11 Message-ID: <200204090816.g398GPJ16671@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Interface In directory cvs.zope.org:/tmp/cvs-serv16546 Modified Files: Tag: Zope-3x-branch pyskel.py Log Message: Based on the desire of a single individual, I changed the code so that the first letter is only clipped for the class name, if it is an 'I'. I also fixed another small bug I found. === Zope3/lib/python/Interface/pyskel.py 1.1.2.10 => 1.1.2.11 === def skel(name): iface = resolve(name) + class_name = iface.__name__ + if class_name.startswith('I'): + class_name = class_name[1:] print "from %s import %s" % (iface.__module__, iface.__name__) print - print "class %s:" %iface.__name__[1:] + print "class %s:" %class_name print print " __implements__ = ", iface.__name__ print @@ -104,7 +107,7 @@ names=name.split('.') last=names[-1] mod='.'.join(names[:-1]) - + while 1: m=__import__(mod, _globals, _globals, _silly) try: @@ -146,7 +149,7 @@ if name_order is None: # Something's wrong. Oh well. - return interface.__dict__.values() + return interface.__dict__.items() else: items = [] for key, value in interface.namesAndDescriptions(): From m.faassen@vet.uu.nl Tue Apr 9 09:33:54 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Tue, 9 Apr 2002 04:33:54 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/Find Zope3/lib/python/Zope/App/OFS/Container/Find - New directory Message-ID: <200204090833.g398XsQ24556@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Find In directory cvs.zope.org:/tmp/cvs-serv24541/Find Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Find added to the repository --> Using per-directory sticky tag `Zope-3x-branch' === Added directory Zope3/lib/python/Zope/App/OFS/Container/Find === From m.faassen@vet.uu.nl Tue Apr 9 09:35:47 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Tue, 9 Apr 2002 04:35:47 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/Find/Views Zope3/lib/python/Zope/App/OFS/Container/Find/Views - New directory Message-ID: <200204090835.g398Zlr26070@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Find/Views In directory cvs.zope.org:/tmp/cvs-serv26048/Views Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Find/Views added to the repository --> Using per-directory sticky tag `Zope-3x-branch' === Added directory Zope3/lib/python/Zope/App/OFS/Container/Find/Views === From m.faassen@vet.uu.nl Tue Apr 9 09:35:53 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Tue, 9 Apr 2002 04:35:53 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/Find/tests Zope3/lib/python/Zope/App/OFS/Container/Find/tests - New directory Message-ID: <200204090835.g398ZrE26109@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Find/tests In directory cvs.zope.org:/tmp/cvs-serv26082/tests Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Find/tests added to the repository --> Using per-directory sticky tag `Zope-3x-branch' === Added directory Zope3/lib/python/Zope/App/OFS/Container/Find/tests === From m.faassen@vet.uu.nl Tue Apr 9 09:36:23 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Tue, 9 Apr 2002 04:36:23 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/Find/Views/Browser Zope3/lib/python/Zope/App/OFS/Container/Find/Views/Browser - New directory Message-ID: <200204090836.g398aNN26391@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Find/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv26338/Browser Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Find/Views/Browser added to the repository --> Using per-directory sticky tag `Zope-3x-branch' === Added directory Zope3/lib/python/Zope/App/OFS/Container/Find/Views/Browser === From philikon@gmx.net Tue Apr 9 09:38:36 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Tue, 9 Apr 2002 04:38:36 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl Zope3/lib/python/Zope/App/OFS/ApplicationControl - New directory Message-ID: <200204090838.g398ca827024@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl In directory cvs.zope.org:/tmp/cvs-serv27017/ApplicationControl Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl added to the repository --> Using per-directory sticky tag `Zope-3x-branch' === Added directory Zope3/lib/python/Zope/App/OFS/ApplicationControl === From philikon@gmx.net Tue Apr 9 10:11:13 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Tue, 9 Apr 2002 05:11:13 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl - ApplicationControl.py:1.1.2.1 IApplicationControl.py:1.1.2.1 Message-ID: <200204090911.g399BDc08258@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl In directory cvs.zope.org:/tmp/cvs-serv7237 Added Files: Tag: Zope-3x-branch ApplicationControl.py IApplicationControl.py Log Message: Introduced files for Application Control, formerly known as Control_Panel === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/ApplicationControl.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## __doc__ = """ Application Control $Id: ApplicationControl.py,v 1.1.2.1 2002/04/09 09:11:12 philikon Exp $""" from IApplicationControl import IApplicationControl class ApplicationControl: """ """ __implements__ = IApplicationControl === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/IApplicationControl.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## __doc__ = """ Application Control $Id: IApplicationControl.py,v 1.1.2.1 2002/04/09 09:11:12 philikon Exp $""" from Interface import Interface class IApplicationControl(Interface): """ """ From jim@zope.com Tue Apr 9 10:44:33 2002 From: jim@zope.com (Jim Fulton) Date: Tue, 9 Apr 2002 05:44:33 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl - __init__.py:1.1.2.1 Message-ID: <200204090944.g399iXP19835@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl In directory cvs.zope.org:/tmp/cvs-serv19828 Added Files: Tag: Zope-3x-branch __init__.py Log Message: added __init__ === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/__init__.py === From jim@zope.com Tue Apr 9 10:47:04 2002 From: jim@zope.com (Jim Fulton) Date: Tue, 9 Apr 2002 05:47:04 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl - ApplicationControl.py:1.1.2.2 Message-ID: <200204090947.g399l4V20997@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl In directory cvs.zope.org:/tmp/cvs-serv20990 Modified Files: Tag: Zope-3x-branch ApplicationControl.py Log Message: Created an instance. === Zope3/lib/python/Zope/App/OFS/ApplicationControl/ApplicationControl.py 1.1.2.1 => 1.1.2.2 === __implements__ = IApplicationControl + +ApplicationController = ApplicationControl() + From jim@zope.com Tue Apr 9 11:24:50 2002 From: jim@zope.com (Jim Fulton) Date: Tue, 9 Apr 2002 06:24:50 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication - PublicationTraverse.py:1.1.2.13 ZopePublication.py:1.1.2.34 Message-ID: <200204091024.g39AOo002577@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication In directory cvs.zope.org:/tmp/cvs-serv1240/Zope/App/ZopePublication Modified Files: Tag: Zope-3x-branch PublicationTraverse.py ZopePublication.py Log Message: Added new name to the etc namespace, ApplicationController. This is an object that provides global application control. It is similar to the Zope2 control panel. It *is not* stored in the object database, so you can get to it even if your database is toast or your root object is messed up. It's handled kind of weirdly, since it's effectively an alternative application object. === Zope3/lib/python/Zope/App/ZopePublication/PublicationTraverse.py 1.1.2.12 => 1.1.2.13 === from Zope.App.ZMI.Addable import ContentAddables from Zope.App.OFS.Container.IContainer import IWriteContainer +from Zope.App.OFS.ApplicationControl.ApplicationControl \ + import ApplicationController class DuplicateNamespaces(Exception): """More than one namespave was specified in a request""" @@ -128,6 +130,9 @@ # not all get methods may satisfy this assumption. It might be # best to introduce some sort of etc registry. + if name == 'ApplicationController' and ob is None: + return self.__etcApplicationController() + if name != 'Services': raise NotFound(ob, name, request) @@ -140,6 +145,9 @@ self._wrap(method, ob, name, name) return method() + + def __etcApplicationController(self): + return ApplicationController def _traverseacquire(self, request, ob, name): i = 0 === Zope3/lib/python/Zope/App/ZopePublication/ZopePublication.py 1.1.2.33 => 1.1.2.34 === def getApplication(self, request): + + # If the first name is 'ApplicationControl;etc', then we should + # get it rather than look in the database! + stack = request.getTraversalStack() + if stack: + name = stack[-1] + if name[:22] == 'ApplicationController;': + parms = name.split(';') + if 'etc' in parms or 'ns=etc' in parms: + stack.pop() # consume the name + request.setTraversalStack(stack) # Reset the stack + return self.traverseName(request, None, name) + # Open the database. version = request.get(self.version_cookie, '') conn = self.db.open(version) From jim@zope.com Tue Apr 9 11:24:50 2002 From: jim@zope.com (Jim Fulton) Date: Tue, 9 Apr 2002 06:24:50 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication/tests - testZopePublication.py:1.1.2.22 Message-ID: <200204091024.g39AOoZ02579@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/tests In directory cvs.zope.org:/tmp/cvs-serv1240/Zope/App/ZopePublication/tests Modified Files: Tag: Zope-3x-branch testZopePublication.py Log Message: Added new name to the etc namespace, ApplicationController. This is an object that provides global application control. It is similar to the Zope2 control panel. It *is not* stored in the object database, so you can get to it even if your database is toast or your root object is messed up. It's handled kind of weirdly, since it's effectively an alternative application object. === Zope3/lib/python/Zope/App/ZopePublication/tests/testZopePublication.py 1.1.2.21 => 1.1.2.22 === self.assertEqual(getcontext(ob2), ob) - def testTraverseNameEtc(self): + def testTraverseNameServices(self): pub = self.klass(self.db) class C: def getServiceManager(self): @@ -312,6 +312,19 @@ ob2 = pub.traverseName(r, ob, 'Services;etc') self.assertEqual(getobject(ob2), 1) self.assertEqual(getcontext(ob2), ob) + + def testTraverseNameApplicationControl(self): + from Zope.App.OFS.ApplicationControl.ApplicationControl \ + import ApplicationController + pub = self.klass(self.db) + r = self._createRequest('/ApplicationController;etc;skin=zmi',pub) + ac = pub.traverseName(r, None, 'ApplicationController;etc;skin=zmi') + self.assertEqual(ac, ApplicationController) + r = self._createRequest('/ApplicationController;etc;skin=zmi',pub) + app = r.getPublication().getApplication(r) + self.assertEqual(app, ApplicationController) + self.failIf(r.getTraversalStack()) + def test_suite(): t1 = unittest.makeSuite(ZopePublicationTests, 'test') From philikon@gmx.net Tue Apr 9 12:06:46 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Tue, 9 Apr 2002 07:06:46 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests - New directory Message-ID: <200204091106.g39B6kP25542@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests In directory cvs.zope.org:/tmp/cvs-serv25536/tests Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests added to the repository --> Using per-directory sticky tag `Zope-3x-branch' === Added directory Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests === From tdickenson@geminidataloggers.com Tue Apr 9 12:49:37 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Tue, 9 Apr 2002 07:49:37 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - ObjectManager.py:1.148.4.1 Message-ID: <200204091149.g39BnbD10790@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv10778/OFS Modified Files: Tag: toby-metatype-branch ObjectManager.py Log Message: fixed typo causing _product_meta_types to be ignored when doing an interface-constrained all_meta_types === Zope/lib/python/OFS/ObjectManager.py 1.148 => 1.148.4.1 === pmt = [] - for entry in pmt: + for entry in _pmt: try: eil = entry.get('interfaces',None) From tdickenson@geminidataloggers.com Tue Apr 9 13:52:40 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Tue, 9 Apr 2002 08:52:40 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.453.2.1 Message-ID: <200204091252.g39CqeR31977@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv31970/doc Modified Files: Tag: toby-metatype-branch CHANGES.txt Log Message: implementation of RestrictedCreation proposal === Zope/doc/CHANGES.txt 1.453 => 1.453.2.1 === - New implementation of ZODB object cache. + - Implementation of RestrictedCreation fishbowl proposal; + Product registration can now include a function used to + determine whether that product constructor want to allow + objects to be created in the specified container object. + Bugs: - Fixed bug reported on maillist during EWOULDBLOCK when using FTP server From tdickenson@geminidataloggers.com Tue Apr 9 13:53:44 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Tue, 9 Apr 2002 08:53:44 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - ObjectManager.py:1.148.4.2 Message-ID: <200204091253.g39Cri932217@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv32210/lib/python/OFS Modified Files: Tag: toby-metatype-branch ObjectManager.py Log Message: rationalised interface checking, and added implementation of RestrictedCreation proposal === Zope/lib/python/OFS/ObjectManager.py 1.148.4.1 => 1.148.4.2 === def all_meta_types(self, interfaces=None): + # A list of products registered elsewhere + external_candidates = [] + + # Look at _product_meta_types, if there is one _pmt=() if hasattr(self, '_product_meta_types'): _pmt=self._product_meta_types elif hasattr(self, 'aq_acquire'): try: _pmt=self.aq_acquire('_product_meta_types') except: pass + external_candidates.extend(list(_pmt)) - if interfaces is None: pmt = list(_pmt) - else: - pmt = [] + # Look at all globally visible meta types. + for entry in Products.meta_types: + if ( (interfaces is not None) or (entry.get("visibility", None)=="Global") ): + external_candidates.append(entry) - for entry in _pmt: + # Filter the list of external candidates based on the + # specified interface constraint + if interfaces is None: + interface_constrained_meta_types = external_candidates + else: + interface_constrained_meta_types = [] + for entry in external_candidates: try: eil = entry.get('interfaces',None) - if eil is not None: for ei in eil: for i in interfaces: if ei is i or ei.extends(i): - pmt.append(entry) + interface_constrained_meta_types.append(entry) raise BreakoutException # only append 1ce except BreakoutException: pass - - gmt = [] - - for entry in Products.meta_types: - if interfaces is None: - if entry.get("visibility", None) == "Global": - gmt.append(entry) + # Meta types specified by this instance are not checked against the + # interface constraint. This is as it always has been, but Im not + # sure it is correct. + interface_constrained_meta_types.extend(list(self.meta_types)) + + # Filter the list based on each meta-types's container_filter + meta_types = [] + for entry in interface_constrained_meta_types: + container_filter = entry.get('container_filter',None) + if container_filter is None: + meta_types.append(entry) else: - try: - eil = entry.get("interfaces", None) - if eil is not None: - for ei in eil: - for i in interfaces: - if ei is i or ei.extends(i): - gmt.append(entry) - raise BreakoutException # only append 1ce - except BreakoutException: - pass + if container_filter(self): + meta_types.append(entry) - return list(self.meta_types)+gmt+pmt + return meta_types def _subobject_permissions(self): return (Products.__ac_permissions__+ From tdickenson@geminidataloggers.com Tue Apr 9 13:54:31 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Tue, 9 Apr 2002 08:54:31 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - ProductContext.py:1.38.36.1 Message-ID: <200204091254.g39CsVA32490@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv32478/lib/python/App Modified Files: Tag: toby-metatype-branch ProductContext.py Log Message: implementation of RestrictedCreation proposal === Zope/lib/python/App/ProductContext.py 1.38 => 1.38.36.1 === permission=None, constructors=(), icon=None, permissions=None, legacy=(), - visibility="Global",interfaces=_marker + visibility="Global",interfaces=_marker, + container_filter=None ): """Register a constructor @@ -88,6 +89,10 @@ interfaces -- a list of the interfaces the object supports + container_filter -- function that is called with an ObjectManager + object as the only parameter, which should return a true object + if the object is happy to be created in that container. + """ app=self.__app pack=self.__pack @@ -171,6 +176,7 @@ 'visibility': visibility, 'interfaces': interfaces, 'instance': instance_class, + 'container_filter': container_filter },) m[name]=initial @@ -325,3 +331,4 @@ ht=APIHelpTopic.APIHelpTopic(file, '', os.path.join(path, file)) self.registerHelpTopic(file, ht) + From steve@cat-box.net Tue Apr 9 14:13:09 2002 From: steve@cat-box.net (Steve Alexander) Date: Tue, 9 Apr 2002 09:13:09 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication/tests - testDefaultTraverser.py:1.1.2.11 Message-ID: <200204091313.g39DD9n06531@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/tests In directory cvs.zope.org:/tmp/cvs-serv6427/App/ZopePublication/tests Modified Files: Tag: Zope-3x-branch testDefaultTraverser.py Log Message: removed characters from the ends of lines === Zope3/lib/python/Zope/App/ZopePublication/tests/testDefaultTraverser.py 1.1.2.10 => 1.1.2.11 === $Id$ """ - -import unittest, sys -from Zope.ComponentArchitecture.tests.Request import Request -from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup -from Zope.ComponentArchitecture import provideView -from Zope.App.ZopePublication.Traversers import DefaultTraverser -from Interface import Interface -from Zope.Exceptions import NotFoundError - - -class I(Interface): pass - - -class Container: - - def __init__(self, **kw): - - for k in kw: - setattr(self, k , kw[k]) - - - def getObject(self, name, default=None): - - return getattr(self, name, default) - - -class Request(Request): - - def getEffectiveURL(self): - return '' - - -class View: - - def __init__(self, comp): - self._comp = comp - - - -class Test(CleanUp, unittest.TestCase): - - def testAttr(self): - """ test container traver """ - - foo = Container() - c = Container( foo=foo ) - req = Request( I, '') - - T = DefaultTraverser(c) - self.failUnless(T.publishTraverse(req,'foo') is foo) - - self.assertRaises(NotFoundError , T.publishTraverse, req ,'morebar') - - - def testView(self): - """ test getting a view """ - - - foo = Container() - c = Container( foo=foo ) - req = Request( I, '') - - T = DefaultTraverser(c) - provideView(None , 'foo', I, View) - - self.failUnless(T.publishTraverse(req,'foo;view').__class__ is View ) - self.failUnless(T.publishTraverse(req,'foo') is foo) - - self.assertRaises(NotFoundError , T.publishTraverse, req ,'morebar') - self.assertRaises(NotFoundError , T.publishTraverse, req , - 'morebar;view') - - - -def test_suite(): - loader=unittest.TestLoader() - return loader.loadTestsFromTestCase(Test) - -if __name__=='__main__': - unittest.TextTestRunner().run(test_suite()) + +import unittest, sys +from Zope.ComponentArchitecture.tests.Request import Request +from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup +from Zope.ComponentArchitecture import provideView +from Zope.App.ZopePublication.Traversers import DefaultTraverser +from Interface import Interface +from Zope.Exceptions import NotFoundError + + +class I(Interface): pass + + +class Container: + + def __init__(self, **kw): + + for k in kw: + setattr(self, k , kw[k]) + + + def getObject(self, name, default=None): + + return getattr(self, name, default) + + +class Request(Request): + + def getEffectiveURL(self): + return '' + + +class View: + + def __init__(self, comp): + self._comp = comp + + + +class Test(CleanUp, unittest.TestCase): + + def testAttr(self): + """ test container traver """ + + foo = Container() + c = Container( foo=foo ) + req = Request( I, '') + + T = DefaultTraverser(c) + self.failUnless(T.publishTraverse(req,'foo') is foo) + + self.assertRaises(NotFoundError , T.publishTraverse, req ,'morebar') + + + def testView(self): + """ test getting a view """ + + + foo = Container() + c = Container( foo=foo ) + req = Request( I, '') + + T = DefaultTraverser(c) + provideView(None , 'foo', I, View) + + self.failUnless(T.publishTraverse(req,'foo;view').__class__ is View ) + self.failUnless(T.publishTraverse(req,'foo') is foo) + + self.assertRaises(NotFoundError , T.publishTraverse, req ,'morebar') + self.assertRaises(NotFoundError , T.publishTraverse, req , + 'morebar;view') + + + +def test_suite(): + loader=unittest.TestLoader() + return loader.loadTestsFromTestCase(Test) + +if __name__=='__main__': + unittest.TextTestRunner().run(test_suite()) From philikon@gmx.net Tue Apr 9 14:53:29 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Tue, 9 Apr 2002 09:53:29 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl - ApplicationControl.py:1.1.2.3 Message-ID: <200204091353.g39DrTe20535@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl In directory cvs.zope.org:/tmp/cvs-serv20407 Modified Files: Tag: Zope-3x-branch ApplicationControl.py Log Message: - Implemented the getStartTime interface method - Registering time on object instanciation === Zope3/lib/python/Zope/App/OFS/ApplicationControl/ApplicationControl.py 1.1.2.2 => 1.1.2.3 === from IApplicationControl import IApplicationControl +import time + class ApplicationControl: """ """ __implements__ = IApplicationControl + + def __init__(self): + self.start_time = time.time() + + ############################################################ + # Implementation methods for interface + # Zope.App.OFS.ApplicationControl.IApplicationControl. + + def getStartTime(self): + 'See Zope.App.OFS.ApplicationControl.IApplicationControl.IApplicationControl' + return self.start_time + + # + ############################################################ ApplicationController = ApplicationControl() From philikon@gmx.net Tue Apr 9 14:54:26 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Tue, 9 Apr 2002 09:54:26 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl - IApplicationControl.py:1.1.2.2 Message-ID: <200204091354.g39DsQP20705@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl In directory cvs.zope.org:/tmp/cvs-serv20556 Modified Files: Tag: Zope-3x-branch IApplicationControl.py Log Message: - added getStartTime() method to the IApplicationControl interface, which tells you when the ApplicationControl has been instanciated === Zope3/lib/python/Zope/App/OFS/ApplicationControl/IApplicationControl.py 1.1.2.1 => 1.1.2.2 === """ """ + def getStartTime(): + """Return the time when the ApplicationControl object has been instanciated + in seconds since the epoch""" From philikon@gmx.net Tue Apr 9 14:55:49 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Tue, 9 Apr 2002 09:55:49 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests - __init__.py:1.1.2.1 Message-ID: <200204091355.g39Dtnj21676@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests In directory cvs.zope.org:/tmp/cvs-serv21650/tests Added Files: Tag: Zope-3x-branch __init__.py Log Message: added __init__.py for python package compatibility === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests/__init__.py === From philikon@gmx.net Tue Apr 9 14:57:07 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Tue, 9 Apr 2002 09:57:07 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests - testZopeVersion.py:1.1.2.1 Message-ID: <200204091357.g39Dv7K21968@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests In directory cvs.zope.org:/tmp/cvs-serv21725/tests Added Files: Tag: Zope-3x-branch testZopeVersion.py Log Message: - introduced the IZopeVersion interface and utility to retrieve information about the current zope version === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests/testZopeVersion.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ Revision information: $Id: testZopeVersion.py,v 1.1.2.1 2002/04/09 13:57:07 philikon Exp $ """ from unittest import TestCase, TestSuite, main, makeSuite from Zope.App.OFS.ApplicationControl.IZopeVersion import IZopeVersion from Zope.App.OFS.ApplicationControl.ZopeVersion import ZopeVersion import os ############################################################################# # If your tests change any global registries, then uncomment the # following import and include CleanUp as a base class of your # test. It provides a setUp and tearDown that clear global data that # has registered with the test cleanup framework. Don't use this # tests outside the Zope package. # from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup ############################################################################# class Test(TestCase): def _Test__new(self): return ZopeVersion() def _getZopeVersion(self): """example zope version implementation """ version_id = "Development/Unknown" version_tag = "" is_cvs = 0 import Zope zopedir = os.path.dirname(Zope.__file__) # is this a CVS checkout? cvsdir = os.path.join(zopedir, "CVS" ) if os.path.isdir(cvsdir): is_cvs = 1 tagfile = os.path.join(cvsdir, "Tag") # get the tag information if os.path.isfile(tagfile): f = open(tagfile) tag = f.read() if tag[0] == "T": version_tag = " (%s)" % tag[1:-1] # try to get official Zope release information versionfile = os.path.join(zopedir, "version.txt") if os.path.isfile(versionfile) and not is_cvs: f = open(versionfile) version_id = f.read().split("\n")[0] version = "%s%s" % (version_id, version_tag) return version def test_ZopeVersion(self): zope_version = self._Test__new() self.assertEqual(zope_version.getZopeVersion(), self._getZopeVersion()) def test_suite(): return TestSuite(( makeSuite(Test), )) if __name__=='__main__': main(defaultTest='test_suite') From philikon@gmx.net Tue Apr 9 14:57:07 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Tue, 9 Apr 2002 09:57:07 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl - IZopeVersion.py:1.1.2.1 ZopeVersion.py:1.1.2.1 Message-ID: <200204091357.g39Dv7V21966@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl In directory cvs.zope.org:/tmp/cvs-serv21725 Added Files: Tag: Zope-3x-branch IZopeVersion.py ZopeVersion.py Log Message: - introduced the IZopeVersion interface and utility to retrieve information about the current zope version === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/IZopeVersion.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## __doc__ = """Zope version $Id: IZopeVersion.py,v 1.1.2.1 2002/04/09 13:57:07 philikon Exp $""" from Interface import Interface class IZopeVersion(Interface): """ Zope version """ def getZopeVersion(): """Return a string containing the Zope version (possibly including CVS information)""" === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/ZopeVersion.py === from Zope.App.OFS.ApplicationControl.IZopeVersion import IZopeVersion import os class ZopeVersion: __implements__ = IZopeVersion ############################################################ # Implementation methods for interface # Zope.App.OFS.ApplicationControl.IZopeVersion. def getZopeVersion(self): 'See Zope.App.OFS.ApplicationControl.IZopeVersion.IZopeVersion' version_id = "Development/Unknown" version_tag = "" is_cvs = 0 import Zope zopedir = os.path.dirname(Zope.__file__) # is this a CVS checkout? cvsdir = os.path.join(zopedir, "CVS" ) if os.path.isdir(cvsdir): is_cvs = 1 tagfile = os.path.join(cvsdir, "Tag") # get the tag information if os.path.isfile(tagfile): f = open(tagfile) tag = f.read() if tag[0] == "T": version_tag = " (%s)" % tag[1:-1] # try to get official Zope release information versionfile = os.path.join(zopedir, "version.txt") if os.path.isfile(versionfile) and not is_cvs: f = open(versionfile) version_id = f.read().split("\n")[0] version = "%s%s" % (version_id, version_tag) return version # ############################################################ From philikon@gmx.net Tue Apr 9 14:57:55 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Tue, 9 Apr 2002 09:57:55 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl - IRuntimeInfo.py:1.1.2.1 RuntimeInfo.py:1.1.2.1 Message-ID: <200204091357.g39Dvte22099@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl In directory cvs.zope.org:/tmp/cvs-serv22029 Added Files: Tag: Zope-3x-branch IRuntimeInfo.py RuntimeInfo.py Log Message: - introduced the IRuntimeInfo interface and adapter to be used for the first ApplicationControl view === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/IRuntimeInfo.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## __doc__ = """ Runtime Information $Id: IRuntimeInfo.py,v 1.1.2.1 2002/04/09 13:57:55 philikon Exp $""" from Interface import Interface class IRuntimeInfo(Interface): """ Runtime Information Adapter for Application Control """ def getZopeVersion(): """Return a string containing the descriptive version of the current zope installation""" def getPythonVersion(): """Return a string containing verbose description of the python interpreter""" def getSystemPlatform(): """Return the system platform name in a 5 tuple of (sysname, nodename, release, version, machine)""" def getCommandLine(): """Return the command line string Zope was invoked with""" def getProcessId(): """Return the process id number currently serving the request""" def getUptime(): """Return a string containing the Zope server uptime in unix uptime format with seconds ([NN days, ]HH:MM:SS)""" def getEnvironment(): """Return a dictionary with the environment variables of the python interpreter""" === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/RuntimeInfo.py === from Zope.App.OFS.ApplicationControl.IRuntimeInfo import IRuntimeInfo from Zope.App.OFS.ApplicationControl.IApplicationControl import IApplicationControl from Zope.ComponentArchitecture import getUtility from IZopeVersion import IZopeVersion import sys, os, time class RuntimeInfo: __implements__ = IRuntimeInfo __used_for__ = IApplicationControl def __init__(self, context): self._context = context def getContext(self): return self._context ############################################################ # Implementation methods for interface # Zope.App.OFS.ApplicationControl.IRuntimeInfo. def getZopeVersion(self): 'See Zope.App.OFS.ApplicationControl.IRuntimeInfo.IRuntimeInfo' version_utility = getUtility(self.getContext(), IZopeVersion, None) if version_utility is None: return "" return version_utility.getZopeVersion() def getPythonVersion(self): 'See Zope.App.OFS.ApplicationControl.IRuntimeInfo.IRuntimeInfo' return sys.version def getSystemPlatform(self): 'See Zope.App.OFS.ApplicationControl.IRuntimeInfo.IRuntimeInfo' return os.uname() def getCommandLine(self): 'See Zope.App.OFS.ApplicationControl.IRuntimeInfo.IRuntimeInfo' return sys.argv def getProcessId(self): 'See Zope.App.OFS.ApplicationControl.IRuntimeInfo.IRuntimeInfo' return os.getpid() def getUptime(self): 'See Zope.App.OFS.ApplicationControl.IRuntimeInfo.IRuntimeInfo' return time.time() - self.getContext().getStartTime() def getEnvironment(self): 'See Zope.App.OFS.ApplicationControl.IRuntimeInfo.IRuntimeInfo' return os.environ # ############################################################ From philikon@gmx.net Tue Apr 9 14:57:56 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Tue, 9 Apr 2002 09:57:56 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests - testRuntimeInfo.py:1.1.2.1 Message-ID: <200204091357.g39Dvul22101@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests In directory cvs.zope.org:/tmp/cvs-serv22029/tests Added Files: Tag: Zope-3x-branch testRuntimeInfo.py Log Message: - introduced the IRuntimeInfo interface and adapter to be used for the first ApplicationControl view === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests/testRuntimeInfo.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. ############################################################################## """ Revision information: $Id: testRuntimeInfo.py,v 1.1.2.1 2002/04/09 13:57:55 philikon Exp $ """ from unittest import TestCase, TestSuite, main, makeSuite from Interface.Verify import verifyObject import os, sys, time from Zope.ComponentArchitecture import getUtility, provideUtility from Zope.App.OFS.ApplicationControl.IRuntimeInfo import IRuntimeInfo from Zope.App.OFS.ApplicationControl.ApplicationControl import ApplicationController from Zope.App.OFS.ApplicationControl.IZopeVersion import IZopeVersion # seconds, time values may differ in order to be assumed equal time_tolerance = 3 stupid_version_string = "3085t0klvn93850voids" class TestZopeVersion: """A fallback implementation for the ZopeVersion utility.""" __implements__ = IZopeVersion def getZopeVersion(self): return stupid_version_string ############################################################################# # If your tests change any global registries, then uncomment the # following import and include CleanUp as a base class of your # test. It provides a setUp and tearDown that clear global data that # has registered with the test cleanup framework. Don't use this # tests outside the Zope package. # from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup ############################################################################# class Test(TestCase): def _Test__new(self): from Zope.App.OFS.ApplicationControl.RuntimeInfo import RuntimeInfo return RuntimeInfo(ApplicationController) ############################################################ # Interface-driven tests: def testIRuntimeInfoVerify(self): verifyObject(IRuntimeInfo, self._Test__new()) def test_ZopeVersion(self): runtime_info = self._Test__new() # we expect that there is no utility self.assertEqual(runtime_info.getZopeVersion(), "") provideUtility(IZopeVersion, TestZopeVersion()) self.assertEqual(runtime_info.getZopeVersion(), stupid_version_string) def test_PythonVersion(self): runtime_info = self._Test__new() self.assertEqual(runtime_info.getPythonVersion(), sys.version) def test_SystemPlatform(self): runtime_info = self._Test__new() self.assertEqual(runtime_info.getSystemPlatform(), os.uname()) def test_CommandLine(self): runtime_info = self._Test__new() self.assertEqual(runtime_info.getCommandLine(), sys.argv) def test_ProcessId(self): runtime_info = self._Test__new() self.assertEqual(runtime_info.getProcessId(), os.getpid()) def test_Uptime(self): runtime_info = self._Test__new() # whats the uptime we expect? start_time = ApplicationController.getStartTime() asserted_uptime = time.time() - start_time # get the uptime the current implementation calculates test_uptime = runtime_info.getUptime() self.failUnless(abs(asserted_uptime - test_uptime) < time_tolerance) def test_Environment(self): runtime_info = self._Test__new() self.assertEqual(runtime_info.getEnvironment(), os.environ) def test_suite(): return TestSuite(( makeSuite(Test), )) if __name__=='__main__': main(defaultTest='test_suite') From philikon@gmx.net Tue Apr 9 15:09:23 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Tue, 9 Apr 2002 10:09:23 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope - zope.zcml:1.1.2.8 Message-ID: <200204091409.g39E9NE26869@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope In directory cvs.zope.org:/tmp/cvs-serv26772 Modified Files: Tag: Zope-3x-branch zope.zcml Log Message: - introduced new permission: "Zope.ManageApplication" for access to the ApplicationControl area === Zope3/lib/python/Zope/zope.zcml 1.1.2.7 => 1.1.2.8 === + From m.faassen@vet.uu.nl Tue Apr 9 16:24:33 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Tue, 9 Apr 2002 11:24:33 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/Find - FindAdapter.py:1.1.2.1 IFind.py:1.1.2.1 __init__.py:1.1.2.1 find.zcml:1.1.2.1 Message-ID: <200204091524.g39FOXS21871@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Find In directory cvs.zope.org:/tmp/cvs-serv21631/OFS/Container/Find Added Files: Tag: Zope-3x-branch FindAdapter.py IFind.py __init__.py find.zcml Log Message: Added a basic framework for finding objects. The UI right now only exposes looking for ids (see find;view). === Added File Zope3/lib/python/Zope/App/OFS/Container/Find/FindAdapter.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: FindAdapter.py,v 1.1.2.1 2002/04/09 15:24:30 faassen Exp $ """ from Zope.App.OFS.Container.Find.IFind import IFind, IIdFindFilter from Zope.App.OFS.Container.IContainer import IReadContainer # XXX need to do this manually to wrap objects from Zope.ContextWrapper import Wrapper class FindAdapter(object): __implements__ = IFind __used_for__ = IReadContainer def __init__(self, context): self._context = context ############################################################ # Implementation methods for interface # Zope.App.OFS.Container.Find.IFind.IFind def find(self, id_filters=None, object_filters=None): 'See Zope.App.OFS.Container.Find.IFind.IFind' id_filters = id_filters or [] object_filters = object_filters or [] result = [] container = self._context for id, object in container.objectItems(): _find_helper(id, object, container, id_filters, object_filters, result) return result # ############################################################ def _find_helper(id, object, container, id_filters, object_filters, result): for id_filter in id_filters: if not id_filter.matches(id): break else: # if we didn't break out of the loop, all name filters matched # now check all object filters for object_filter in object_filters: if not object_filter.matches(object): break else: # XXX wrap object object = Wrapper(object, container, name=id) # if we didn't break out of the loop, all filters matched result.append(object) if not IReadContainer.isImplementedBy(object): return container = object for id, object in container.objectItems(): _find_helper(id, object, container, id_filters, object_filters, result) class SimpleIdFindFilter(object): __implements__ = IIdFindFilter def __init__(self, ids): self._ids = ids ############################################################ # Implementation methods for interface # Zope.App.OFS.Container.Find.IFind.INameFindFilter def matches(self, id): 'See Zope.App.OFS.Container.Find.IFind.INameFindFilter' return id in self._ids # ############################################################ === Added File Zope3/lib/python/Zope/App/OFS/Container/Find/IFind.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IFind.py,v 1.1.2.1 2002/04/09 15:24:30 faassen Exp $ """ from Interface import Interface class IFind(Interface): """ Find support for containers. """ def find(id_filters=None, object_filters=None): """Find object that matches all filters in all sub objects, not including this container itself. """ class IObjectFindFilter(Interface): def matches(object): """Returns true if the object matches the filter criteria. """ class IIdFindFilter(Interface): def matches(id): """Returns true if the id matches the filter criteria. """ === Added File Zope3/lib/python/Zope/App/OFS/Container/Find/__init__.py === # make this a package === Added File Zope3/lib/python/Zope/App/OFS/Container/Find/find.zcml === From m.faassen@vet.uu.nl Tue Apr 9 16:24:33 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Tue, 9 Apr 2002 11:24:33 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/Find/Views/Browser - Find.py:1.1.2.1 __init__.py:1.1.2.1 browser.zcml:1.1.2.1 find.pt:1.1.2.1 Message-ID: <200204091524.g39FOXk21887@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Find/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv21631/OFS/Container/Find/Views/Browser Added Files: Tag: Zope-3x-branch Find.py __init__.py browser.zcml find.pt Log Message: Added a basic framework for finding objects. The UI right now only exposes looking for ids (see find;view). === Added File Zope3/lib/python/Zope/App/OFS/Container/Find/Views/Browser/Find.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: Find.py,v 1.1.2.1 2002/04/09 15:24:31 faassen Exp $ """ from Zope.Publisher.Browser.AttributePublisher import AttributePublisher from Zope.PageTemplate.PageTemplateFile import PageTemplateFile from Zope.App.OFS.Container.Find.IFind import IFind # XXX this needs to be looked up in a registry from Zope.App.OFS.Container.Find.FindAdapter import SimpleIdFindFilter from Zope.ComponentArchitecture import getAdapter # XXX very simple implementation right now class Find(AttributePublisher): def __init__(self, context): self._context = context def getContext(self): return self._context index = PageTemplateFile('find.pt') def findByIds(self, ids): """Do a find for the ids listed in ids, which is a string. """ finder = getAdapter(self._context, IFind) ids = ids.split() # if we don't have any ids listed, don't search at all if not ids: return [] found = finder.find([SimpleIdFindFilter(ids)]) return [getId(object) for object in found] from Zope.ContextWrapper import getdict # XXX get the id of an object (should be imported from somewhere) def getId(object): dict = getdict(object) if dict: return dict.get('name') return None === Added File Zope3/lib/python/Zope/App/OFS/Container/Find/Views/Browser/__init__.py === # this is a package === Added File Zope3/lib/python/Zope/App/OFS/Container/Find/Views/Browser/browser.zcml === === Added File Zope3/lib/python/Zope/App/OFS/Container/Find/Views/Browser/find.pt ===

id
From m.faassen@vet.uu.nl Tue Apr 9 16:24:33 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Tue, 9 Apr 2002 11:24:33 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/Find/Views - __init__.py:1.1.2.1 views.zcml:1.1.2.1 Message-ID: <200204091524.g39FOXK21875@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Find/Views In directory cvs.zope.org:/tmp/cvs-serv21631/OFS/Container/Find/Views Added Files: Tag: Zope-3x-branch __init__.py views.zcml Log Message: Added a basic framework for finding objects. The UI right now only exposes looking for ids (see find;view). === Added File Zope3/lib/python/Zope/App/OFS/Container/Find/Views/__init__.py === # make this a package === Added File Zope3/lib/python/Zope/App/OFS/Container/Find/Views/views.zcml === From m.faassen@vet.uu.nl Tue Apr 9 16:24:34 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Tue, 9 Apr 2002 11:24:34 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/Find/tests - __init__.py:1.1.2.1 testFind.py:1.1.2.1 Message-ID: <200204091524.g39FOYe21890@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Find/tests In directory cvs.zope.org:/tmp/cvs-serv21631/OFS/Container/Find/tests Added Files: Tag: Zope-3x-branch __init__.py testFind.py Log Message: Added a basic framework for finding objects. The UI right now only exposes looking for ids (see find;view). === Added File Zope3/lib/python/Zope/App/OFS/Container/Find/tests/__init__.py === # make this a package === Added File Zope3/lib/python/Zope/App/OFS/Container/Find/tests/testFind.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ Revision information: $Id: testFind.py,v 1.1.2.1 2002/04/09 15:24:32 faassen Exp $ """ from unittest import TestCase, TestSuite, main, makeSuite from Zope.App.OFS.Container.IContainer import IReadContainer, _RAISE_KEYERROR from Zope.App.OFS.Container.Find.IFind import IObjectFindFilter from Zope.App.OFS.Container.Find.FindAdapter\ import FindAdapter, SimpleIdFindFilter class FakeContainer: __implements__ = IReadContainer def __init__(self, id, objects): self._id = id self._objects = objects def objectIds(self): return [object._id for object in self._objects] def objectValues(self): return self._objects def objectItems(self): return [(object._id, object) for object in self._objects] def getObject(self, id, default=_RAISE_KEYERROR): for object in self._objects: if object._id == id: return object if default is _RAISE_KEYERROR: raise KeyError, "Could not find %s" % id else: return default def hasObject(self, id): for object in self._objects: if object.id == id: return 1 return 0 def objectCount(self): return len(self._objects) class TestObjectFindFilter(object): __implements__ = IObjectFindFilter def __init__(self, count): self._count = count def matches(self, object): if IReadContainer.isImplementedBy(object): return object.objectCount() == self._count else: return 0 class Test(TestCase): def test_idFind(self): alpha = FakeContainer('alpha', []) delta = FakeContainer('delta', []) beta = FakeContainer('beta', [delta]) gamma = FakeContainer('gamma', []) tree = FakeContainer( 'tree', [alpha, beta, gamma]) find = FindAdapter(tree) # some simple searches result = find.find([SimpleIdFindFilter(['beta'])]) self.assertEquals([beta], result) result = find.find([SimpleIdFindFilter(['gamma'])]) self.assertEquals([gamma], result) result = find.find([SimpleIdFindFilter(['delta'])]) self.assertEquals([delta], result) # we should not find the container we search on result = find.find([SimpleIdFindFilter(['tree'])]) self.assertEquals([], result) # search for multiple ids result = find.find([SimpleIdFindFilter(['alpha', 'beta'])]) self.assertEquals([alpha, beta], result) result = find.find([SimpleIdFindFilter(['beta', 'delta'])]) self.assertEquals([beta, delta], result) # search without any filters, find everything result = find.find([]) self.assertEquals([alpha, beta, delta, gamma], result) # search for something that doesn't exist result = find.find([SimpleIdFindFilter(['foo'])]) self.assertEquals([], result) # find for something that has two ids at the same time, # can't ever be the case result = find.find([SimpleIdFindFilter(['alpha']), SimpleIdFindFilter(['beta'])]) self.assertEquals([], result) def test_objectFind(self): alpha = FakeContainer('alpha', []) delta = FakeContainer('delta', []) beta = FakeContainer('beta', [delta]) gamma = FakeContainer('gamma', []) tree = FakeContainer( 'tree', [alpha, beta, gamma]) find = FindAdapter(tree) result = find.find(object_filters=[TestObjectFindFilter(0)]) self.assertEquals([alpha, delta, gamma], result) result = find.find(object_filters=[TestObjectFindFilter(1)]) self.assertEquals([beta], result) result = find.find(object_filters=[TestObjectFindFilter(2)]) self.assertEquals([], result) def test_combinedFind(self): alpha = FakeContainer('alpha', []) delta = FakeContainer('delta', []) beta = FakeContainer('beta', [delta]) gamma = FakeContainer('gamma', []) tree = FakeContainer( 'tree', [alpha, beta, gamma]) find = FindAdapter(tree) result = find.find(id_filters=[SimpleIdFindFilter(['alpha'])], object_filters=[TestObjectFindFilter(0)]) self.assertEquals([alpha], result) result = find.find(id_filters=[SimpleIdFindFilter(['alpha'])], object_filters=[TestObjectFindFilter(1)]) self.assertEquals([], result) def test_suite(): return TestSuite(( makeSuite(Test), )) if __name__=='__main__': main(defaultTest='test_suite') From m.faassen@vet.uu.nl Tue Apr 9 16:25:00 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Tue, 9 Apr 2002 11:25:00 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS - ofs.zcml:1.1.2.13 Message-ID: <200204091525.g39FP0K22257@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS In directory cvs.zope.org:/tmp/cvs-serv21631/OFS Modified Files: Tag: Zope-3x-branch ofs.zcml Log Message: Added a basic framework for finding objects. The UI right now only exposes looking for ids (see find;view). === Zope3/lib/python/Zope/App/OFS/ofs.zcml 1.1.2.12 => 1.1.2.13 === - - - - - + From m.faassen@vet.uu.nl Tue Apr 9 16:25:01 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Tue, 9 Apr 2002 11:25:01 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container - container.zcml:1.1.2.3 Message-ID: <200204091525.g39FP1322278@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container In directory cvs.zope.org:/tmp/cvs-serv21631/OFS/Container Added Files: Tag: Zope-3x-branch container.zcml Log Message: Added a basic framework for finding objects. The UI right now only exposes looking for ids (see find;view). === Zope3/lib/python/Zope/App/OFS/Container/container.zcml 1.1.2.2 => 1.1.2.3 === + xmlns='http://namespaces.zope.org/zope' + xmlns:browser='http://namespaces.zope.org/browser' + xmlns:xmlrpc='http://namespaces.zope.org/xmlrpc' +> + + + + + + + + + + From jim@zope.com Tue Apr 9 16:56:57 2002 From: jim@zope.com (Jim Fulton) Date: Tue, 9 Apr 2002 11:56:57 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL - New directory Message-ID: <200204091556.g39Fuv801324@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL In directory cvs.zope.org:/tmp/cvs-serv1318/AbsoluteURL Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL added to the repository --> Using per-directory sticky tag `Zope-3x-branch' === Added directory Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL === From jim@zope.com Tue Apr 9 16:57:09 2002 From: jim@zope.com (Jim Fulton) Date: Tue, 9 Apr 2002 11:57:09 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL/tests Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL/tests - New directory Message-ID: <200204091557.g39Fv9t01427@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL/tests In directory cvs.zope.org:/tmp/cvs-serv1421/tests Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL/tests added to the repository --> Using per-directory sticky tag `Zope-3x-branch' === Added directory Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL/tests === From jim@zope.com Tue Apr 9 16:59:49 2002 From: jim@zope.com (Jim Fulton) Date: Tue, 9 Apr 2002 11:59:49 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/HTTP/tests - TestRequest.py:1.1.2.1 Message-ID: <200204091559.g39FxnV02185@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/HTTP/tests In directory cvs.zope.org:/tmp/cvs-serv2177 Added Files: Tag: Zope-3x-branch TestRequest.py Log Message: Added test HTTP request to test AbsoluteURL. === Added File Zope3/lib/python/Zope/Publisher/HTTP/tests/TestRequest.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ Test request for writing tests that need HTTP requests. Note that this is used by tests in other packages. $Id: TestRequest.py,v 1.1.2.1 2002/04/09 15:59:49 jim Exp $ """ from StringIO import StringIO from Zope.Publisher.HTTP.HTTPRequest import HTTPRequest _testEnv = { 'SERVER_URL': 'http://foobar.com', 'HTTP_HOST': 'foobar.com', 'CONTENT_LENGTH': '0', 'GATEWAY_INTERFACE': 'Test/1.0', } class TestRequest(HTTPRequest): def __init__(self, body_instream=None, outstream=None, environ=None, **kw): if body_instream is None: body_instream = StringIO('') if outstream is None: outstream = StringIO() env = {} env.update(_testEnv) if environ: env.update(environ) env.update(kw) super(TestRequest, self).__init__(body_instream, outstream, env) From jim@zope.com Tue Apr 9 17:00:22 2002 From: jim@zope.com (Jim Fulton) Date: Tue, 9 Apr 2002 12:00:22 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL - AbsoluteURL.py:1.1.2.1 __init__.py:1.1.2.1 config.zcml:1.1.2.1 Message-ID: <200204091600.g39G0Ma02349@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL In directory cvs.zope.org:/tmp/cvs-serv2326/lib/python/Zope/App/ZopePublication/AbsoluteURL Added Files: Tag: Zope-3x-branch AbsoluteURL.py __init__.py config.zcml Log Message: added AbsoluteURL view === Added File Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL/AbsoluteURL.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ Revision information: $Id: AbsoluteURL.py,v 1.1.2.1 2002/04/09 16:00:20 jim Exp $ """ from Zope.Publisher.Browser.IBrowserPublisher import IBrowserPublisher from Zope.ContextWrapper import getinnercontext, getdict from Zope.ComponentArchitecture import getRequestView class AbsoluteURL: __implements__ = IBrowserPublisher def __init__(self, context): self.__context = context def setViewRequest(self, request): self.__request = request def __str__(self): context = self.__context dict = getdict(context) name = dict and dict.get('name') or None container = getinnercontext(context) if name is None or container is None: import pdb; pdb.set_trace() raise TypeError, 'Not enough context information to get a URL' return "%s/%s" % (getRequestView(container, 'url', self.__request), name) __call__ = __str__ class SiteAbsoluteURL: __implements__ = IBrowserPublisher def __init__(self, context): self.__context = context def setViewRequest(self, request): self.__request = request def __str__(self): return self.__request.getApplicationURL() __call__ = __str__ === Added File Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL/__init__.py === === Added File Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL/config.zcml === From jim@zope.com Tue Apr 9 17:00:22 2002 From: jim@zope.com (Jim Fulton) Date: Tue, 9 Apr 2002 12:00:22 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL/tests - __init__.py:1.1.2.1 testAbsoluteURL.py:1.1.2.1 Message-ID: <200204091600.g39G0Mw02351@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL/tests In directory cvs.zope.org:/tmp/cvs-serv2326/lib/python/Zope/App/ZopePublication/AbsoluteURL/tests Added Files: Tag: Zope-3x-branch __init__.py testAbsoluteURL.py Log Message: added AbsoluteURL view === Added File Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL/tests/__init__.py === === Added File Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL/tests/testAbsoluteURL.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Test the AbsoluteURL view Revision information: $Id: testAbsoluteURL.py,v 1.1.2.1 2002/04/09 16:00:21 jim Exp $ """ from unittest import TestCase, TestSuite, main, makeSuite ############################################################################# # If your tests change any global registries, then uncomment the # following import and include CleanUp as a base class of your # test. It provides a setUp and tearDown that clear global data that # has registered with the test cleanup framework. Don't use this # tests outside the Zope package. from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup ############################################################################# from Zope.ComponentArchitecture import getRequestView, provideView from Zope.Publisher.Browser.IBrowserPublisher import IBrowserPublisher from Zope.Publisher.HTTP.tests.TestRequest import TestRequest from Zope.ContextWrapper import Wrapper from Interface import Interface class IRoot(Interface): pass class Root: __implements__ = IRoot class Test(CleanUp, TestCase): def setUp(self): from Zope.App.ZopePublication.AbsoluteURL.AbsoluteURL \ import AbsoluteURL, SiteAbsoluteURL provideView(None, 'url', IBrowserPublisher, AbsoluteURL) provideView(IRoot, 'url', IBrowserPublisher, SiteAbsoluteURL) def testNoContext(self): request = TestRequest() request.setViewType(IBrowserPublisher) view = getRequestView(Root(), 'url', request) self.assertEqual(str(view), 'http://foobar.com') def testBasicContext(self): request = TestRequest() request.setViewType(IBrowserPublisher) content = Wrapper(None, Root(), name='a') content = Wrapper(None, content, name='b') content = Wrapper(None, content, name='c') view = getRequestView(content, 'url', request) self.assertEqual(str(view), 'http://foobar.com/a/b/c') def test_suite(): return TestSuite(( makeSuite(Test), )) if __name__=='__main__': main(defaultTest='test_suite') From jim@zope.com Tue Apr 9 17:00:51 2002 From: jim@zope.com (Jim Fulton) Date: Tue, 9 Apr 2002 12:00:51 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication - zopepublication.zcml:1.1.2.4 Message-ID: <200204091600.g39G0pG02855@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication In directory cvs.zope.org:/tmp/cvs-serv2326/lib/python/Zope/App/ZopePublication Modified Files: Tag: Zope-3x-branch zopepublication.zcml Log Message: added AbsoluteURL view === Zope3/lib/python/Zope/App/ZopePublication/zopepublication.zcml 1.1.2.3 => 1.1.2.4 === factory=".Traversers.DefaultTraverser." /> + + From jim@zope.com Tue Apr 9 17:10:38 2002 From: jim@zope.com (Jim Fulton) Date: Tue, 9 Apr 2002 12:10:38 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL - AbsoluteURL.py:1.1.2.2 Message-ID: <200204091610.g39GAc905398@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL In directory cvs.zope.org:/tmp/cvs-serv4945 Modified Files: Tag: Zope-3x-branch AbsoluteURL.py Log Message: Fixed bug in handling failed url case. === Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL/AbsoluteURL.py 1.1.2.1 => 1.1.2.2 === container = getinnercontext(context) if name is None or container is None: - import pdb; pdb.set_trace() raise TypeError, 'Not enough context information to get a URL' return "%s/%s" % (getRequestView(container, 'url', self.__request), From jim@zope.com Tue Apr 9 17:10:38 2002 From: jim@zope.com (Jim Fulton) Date: Tue, 9 Apr 2002 12:10:38 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL/tests - testAbsoluteURL.py:1.1.2.2 Message-ID: <200204091610.g39GAcl05400@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL/tests In directory cvs.zope.org:/tmp/cvs-serv4945/tests Modified Files: Tag: Zope-3x-branch testAbsoluteURL.py Log Message: Fixed bug in handling failed url case. === Zope3/lib/python/Zope/App/ZopePublication/AbsoluteURL/tests/testAbsoluteURL.py 1.1.2.1 => 1.1.2.2 === provideView(None, 'url', IBrowserPublisher, AbsoluteURL) provideView(IRoot, 'url', IBrowserPublisher, SiteAbsoluteURL) + + def testBadObject(self): + request = TestRequest() + request.setViewType(IBrowserPublisher) + view = getRequestView(None, 'url', request) + self.assertRaises(TypeError, view.__str__) def testNoContext(self): request = TestRequest() From srichter@cbu.edu Tue Apr 9 17:12:03 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 12:12:03 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/StartUp - RequestFactory.py:1.1.2.2.2.1 Message-ID: <200204091612.g39GC3Q05627@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/StartUp In directory cvs.zope.org:/tmp/cvs-serv4334/StartUp Modified Files: Tag: Zope3-Server-Branch RequestFactory.py Log Message: Check in my big mess of stuff, which is working towards making FTP work together with the Publisher. I will keep working on startup now, so that we can test easier. This is basically a check-in, so that Shane can see what I have done last night. Please do not expect anything towork, since this is more than just work in progress... it is a prototype to get FTP running via Publisher! === Zope3/lib/python/Zope/StartUp/RequestFactory.py 1.1.2.2 => 1.1.2.2.2.1 === # ############################################################################## -""" - -$Id$ -""" - -from Interface import Interface -import copy - - -class IRequestFactory(Interface): - """This is a pure read-only interface, since the values are set through - a ZCML directive and we shouldn't be able to change them. - """ - - def realize(db): - """Realize the factory by initalizing the publication. - - The method returns the realized object. - """ - - - def __call__(input_stream, output_steam, env): - """Call the Request Factory""" - - - - - -class RequestFactory: - """This class will generically create RequestFactories. This way I do - not have to create a method for each Server Type there is. - """ - - __implements__ = IRequestFactory - - def __init__(self, publication, request): - """Initialize Request Factory""" - self._pubFactory = publication - self._publication = None - self._request = request - - - ############################################################ - # Implementation methods for interface - # Zope.StartUp.RequestFactory.IRequestFactory - - def realize(self, db): - 'See Zope.StartUp.RequestFactory.IRequestFactory' - realized = copy.copy(self) - realized._publication = realized._pubFactory(db) - return realized - - - def __call__(self, input_stream, output_steam, env): - 'See Zope.StartUp.RequestFactory.IRequestFactory' - request = self._request(input_stream, output_steam, env) - request.setPublication(self._publication) - return request - - # - ############################################################ +"""ctory.py,v 1.1.2.2 2002/04/02 02:20:40 srichter Exp $ +""" + +from Interface import Interface +import copy + + +class IRequestFactory(Interface): + """This is a pure read-only interface, since the values are set through + a ZCML directive and we shouldn't be able to change them. + """ + + def realize(db): + """Realize the factory by initalizing the publication. + + The method returns the realized object. + """ + + + def __call__(input_stream, output_steam, env): + """Call the Request Factory""" + + + + + +class RequestFactory: + """This class will generically create RequestFactories. This way I do + not have to create a method for each Server Type there is. + """ + + __implements__ = IRequestFactory + + def __init__(self, publication, request): + """Initialize Request Factory""" + self._pubFactory = publication + self._publication = None + self._request = request + + + ############################################################ + # Implementation methods for interface + # Zope.StartUp.RequestFactory.IRequestFactory + + def realize(self, db): + 'See Zope.StartUp.RequestFactory.IRequestFactory' + realized = copy.copy(self) + realized._publication = realized._pubFactory(db) + return realized + + + def __call__(self, input_stream, output_steam, env): + 'See Zope.StartUp.RequestFactory.IRequestFactory' + request = self._request(input_stream, output_steam, env) + request.setPublication(self._publication) + return request + + # + ############################################################ From srichter@cbu.edu Tue Apr 9 17:12:30 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 12:12:30 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container - IContainer.py:1.1.2.2.2.1 Message-ID: <200204091612.g39GCUY05662@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container In directory cvs.zope.org:/tmp/cvs-serv4334/App/OFS/Container Modified Files: Tag: Zope3-Server-Branch IContainer.py Log Message: Check in my big mess of stuff, which is working towards making FTP work together with the Publisher. I will keep working on startup now, so that we can test easier. This is basically a check-in, so that Shane can see what I have done last night. Please do not expect anything towork, since this is more than just work in progress... it is a prototype to get FTP running via Publisher! === Zope3/lib/python/Zope/App/OFS/Container/IContainer.py 1.1.2.2 => 1.1.2.2.2.1 === class IContainer(IReadContainer, IWriteContainer): """The interface for working with a readable and writable container.""" - - - - - From srichter@cbu.edu Tue Apr 9 17:12:31 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 12:12:31 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Folder/Views - views.zcml:1.1.4.1.6.1 Message-ID: <200204091612.g39GCVA05665@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Folder/Views In directory cvs.zope.org:/tmp/cvs-serv4334/App/OFS/Folder/Views Modified Files: Tag: Zope3-Server-Branch views.zcml Log Message: Check in my big mess of stuff, which is working towards making FTP work together with the Publisher. I will keep working on startup now, so that we can test easier. This is basically a check-in, so that Shane can see what I have done last night. Please do not expect anything towork, since this is more than just work in progress... it is a prototype to get FTP running via Publisher! === Zope3/lib/python/Zope/App/OFS/Folder/Views/views.zcml 1.1.4.1 => 1.1.4.1.6.1 === + From srichter@cbu.edu Tue Apr 9 17:12:31 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 12:12:31 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication/VFS - Publication.py:1.1.2.2 Message-ID: <200204091612.g39GCVf05668@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/VFS In directory cvs.zope.org:/tmp/cvs-serv4334/App/ZopePublication/VFS Modified Files: Tag: Zope3-Server-Branch Publication.py Log Message: Check in my big mess of stuff, which is working towards making FTP work together with the Publisher. I will keep working on startup now, so that we can test easier. This is basically a check-in, so that Shane can see what I have done last night. Please do not expect anything towork, since this is more than just work in progress... it is a prototype to get FTP running via Publisher! === Zope3/lib/python/Zope/App/ZopePublication/VFS/Publication.py 1.1.2.1 => 1.1.2.2 === from Zope.App.ZopePublication.ZopePublication import ZopePublication +from Zope.ComponentArchitecture import getRequestView +from Zope.Publisher.Exceptions import NotFound +from Zope.Publisher.mapply import mapply + + class VFSPublication(ZopePublication): """The Publication will do all the work for the VFS""" + + + def callObject(self, request, ob): + + view = getRequestView(ob, 'vfs', request, self) + + if view is not self: + method = getattr(view, request.method) + else: + raise NotFound(ob, 'vfs', request) + + return mapply(method, request.getPositionalArguments(), request) From srichter@cbu.edu Tue Apr 9 17:12:31 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 12:12:31 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher - publisher-meta.zcml:1.1.4.1.6.2 Message-ID: <200204091612.g39GCVW05669@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher In directory cvs.zope.org:/tmp/cvs-serv4334/Publisher Modified Files: Tag: Zope3-Server-Branch publisher-meta.zcml Log Message: Check in my big mess of stuff, which is working towards making FTP work together with the Publisher. I will keep working on startup now, so that we can test easier. This is basically a check-in, so that Shane can see what I have done last night. Please do not expect anything towork, since this is more than just work in progress... it is a prototype to get FTP running via Publisher! === Zope3/lib/python/Zope/Publisher/publisher-meta.zcml 1.1.4.1.6.1 => 1.1.4.1.6.2 === - + From srichter@cbu.edu Tue Apr 9 17:12:32 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 12:12:32 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/VFS - IVFSDirectoryPublisher.py:1.1.2.2 IVFSFilePublisher.py:1.1.2.2 IVFSObjectPublisher.py:1.1.2.2 VFSRequest.py:1.1.2.2 VFSResponse.py:1.1.2.2 metaConfigure.py:1.1.2.2 Message-ID: <200204091612.g39GCWd05679@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/VFS In directory cvs.zope.org:/tmp/cvs-serv4334/Publisher/VFS Modified Files: Tag: Zope3-Server-Branch IVFSDirectoryPublisher.py IVFSFilePublisher.py IVFSObjectPublisher.py VFSRequest.py VFSResponse.py metaConfigure.py Log Message: Check in my big mess of stuff, which is working towards making FTP work together with the Publisher. I will keep working on startup now, so that we can test easier. This is basically a check-in, so that Shane can see what I have done last night. Please do not expect anything towork, since this is more than just work in progress... it is a prototype to get FTP running via Publisher! === Zope3/lib/python/Zope/Publisher/VFS/IVFSDirectoryPublisher.py 1.1.2.1 => 1.1.2.2 === from IVFSObjectPublisher import IVFSObjectPublisher + class IVFSDirectoryPublisher(IVFSObjectPublisher): """ """ - - def listdir(): - """Returns a sequence of names""" + def exists(name): + """Checks whether the name exists. + """ + + def listdir(with_stats=0, pattern='*'): + """Returns a sequence of names ot (name, stat) + """ + + def mkdir(name, mode=777): + """Create a container with name in this object. + """ def remove(name): - """Removes a file""" - - - def rename(oldname, newname): - """Renames a file""" - + """Remove file with naem from this container. + """ - def getfile(name): - """Returns an existing IVFSObject""" + def rmdir(name): + """Remove the container name from this container. + """ + + def rename(old, new): + """Rename an object from old name to new name. + """ === Zope3/lib/python/Zope/Publisher/VFS/IVFSFilePublisher.py 1.1.2.1 => 1.1.2.2 === class IVFSFilePublisher(IVFSObjectPublisher): - """ """ + """This interface describes the necessary methods a VFS view has to + implement in order to be used by teh VFS. + """ - def read(): - """Returns a string or a stream""" + def read(mode, outstream, start=0, end=-1): + """Read the content of this object. + """ + + def write(mode, instream, start=0): + """Write data specified in instream to object. + """ - - def write(stream): - """Writes the stream to this object""" + def check_writable(mode): + """Check whether we can write to this object. + """ === Zope3/lib/python/Zope/Publisher/VFS/IVFSObjectPublisher.py 1.1.2.1 => 1.1.2.2 === """ """ + def isdir(): + """Returns true, if the object is a container, namely implements + IContainer. For all other cases it returns false. + """ + + def isfile(): + """Returns always the oposite of isdir() for the same reasons. + """ + def stat(): - """Similar to os.stat()""" + """This method should return the typical file stat information: + (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) + """ === Zope3/lib/python/Zope/Publisher/VFS/VFSRequest.py 1.1.2.1 => 1.1.2.2 === self._environ = environ + self.method = '' self.__setupPath() @@ -50,14 +51,14 @@ 'See Zope.Publisher.IPublisherRequest.IPublisherRequest' if self._environ.has_key('command'): - self.setPathSuffix((self._environ['command'],)) + self.method = self._environ['command'] # ############################################################ def __setupPath(self): - path = self.get('PATH_INFO', '/').strip() + path = self.get('path', '/').strip() if path.endswith('/'): path = path[:-1] # XXX Why? Not sure @@ -82,3 +83,9 @@ self.setTraversalStack(clean) self._path_suffix = None + + + def __repr__(self): + # Returns a *short* string. + return '<%s instance at 0x%x, path=%s>' % ( + str(self.__class__), id(self), '/'.join(self._traversal_stack)) === Zope3/lib/python/Zope/Publisher/VFS/VFSResponse.py 1.1.2.1 => 1.1.2.2 === + def outputBody(self): + 'See Zope.Publisher.IPublisherResponse.IPublisherResponse' + pass + + def getResult(self): """ """ return self._getBody() === Zope3/lib/python/Zope/Publisher/VFS/metaConfigure.py 1.1.2.1 => 1.1.2.2 === $Id$ """ -from Zope.ComponentArchitecture import setDefaultViewName +from Zope.ComponentArchitecture import provideView, setDefaultViewName from Zope.Configuration.Action import Action from IVFSPublisher import IVFSPublisher @@ -30,5 +30,10 @@ discriminator = ('defaultViewName', for_, name, IVFSPublisher), callable = setDefaultViewName, args = (for_, IVFSPublisher, name), + ) + Action( + discriminator = ('view', for_, name, IVFSPublisher, layer), + callable = provideView, + args = (for_, name, IVFSPublisher, factory, layer), ) ] From srichter@cbu.edu Tue Apr 9 17:12:32 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 12:12:32 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/SMTP - SMTPServerChannel.py:1.1.2.3 Message-ID: <200204091612.g39GCWu05687@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/SMTP In directory cvs.zope.org:/tmp/cvs-serv4334/Server/SMTP Modified Files: Tag: Zope3-Server-Branch SMTPServerChannel.py Log Message: Check in my big mess of stuff, which is working towards making FTP work together with the Publisher. I will keep working on startup now, so that we can test easier. This is basically a check-in, so that Shane can see what I have done last night. Please do not expect anything towork, since this is more than just work in progress... it is a prototype to get FTP running via Publisher! === Zope3/lib/python/Zope/Server/SMTP/SMTPServerChannel.py 1.1.2.2 => 1.1.2.3 === # XXX: send mail to next server pass + + self._from = '' self._to = [] self._message = '' From srichter@cbu.edu Tue Apr 9 17:12:32 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 12:12:32 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - FTPServer.py:1.1.2.10 FTPServerChannel.py:1.1.2.17 PublisherFTPServer.py:1.1.2.3 Message-ID: <200204091612.g39GCWs05684@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv4334/Server/FTP Modified Files: Tag: Zope3-Server-Branch FTPServer.py FTPServerChannel.py PublisherFTPServer.py Log Message: Check in my big mess of stuff, which is working towards making FTP work together with the Publisher. I will keep working on startup now, so that we can test easier. This is basically a check-in, so that Shane can see what I have done last night. Please do not expect anything towork, since this is more than just work in progress... it is a prototype to get FTP running via Publisher! === Zope3/lib/python/Zope/Server/FTP/FTPServer.py 1.1.2.9 => 1.1.2.10 === """ import asyncore +import pwd from FTPServerChannel import FTPServerChannel from Zope.Server.ServerBase import ServerBase -from Zope.Server.VFS.UnixFileSystem import UnixFileSystem +from Zope.Server.VFS.UnixFileSystem import \ + SchizophrenicUnixFileSystem from Zope.Server.Authentication.DictionaryAuthentication import \ DictionaryAuthentication +class FileSystemOpener: + + filesystem_class = SchizophrenicUnixFileSystem + + def __init__(self, root_dir): + self.root_dir = root_dir + + def __call__(self, username): + persona = pwd.getpwnam(username)[2:4] + return self.filesystem_class(self.root_dir, persona) + + class FTPServer(ServerBase): """Generic FTP Server""" @@ -35,28 +49,19 @@ task_dispatcher=None, adj=None, start=1, hit_log=None, verbose=0, socket_map=None): - self.filesystem = UnixFileSystem(dir) + self.openFilesystem = FileSystemOpener(dir) self.auth_source = auth_source super(FTPServer, self).__init__(ip, port, task_dispatcher, adj, start, hit_log, verbose, socket_map) - # statistics -## self.total_sessions = 0 -## self.closed_sessions = 0 -## self.total_files_out = 0 -## self.total_files_in = 0 -## self.total_bytes_out = 0 -## self.total_bytes_in = 0 -## self.total_exceptions = 0 - if __name__ == '__main__': from Zope.Server.TaskThreads import ThreadedTaskDispatcher td = ThreadedTaskDispatcher() td.setThreadCount(4) - auth_source = DictionaryAuthentication({'foo': 'bar'}) + auth_source = DictionaryAuthentication({'root': 'bar'}) FTPServer('', 8021, '/', auth_source, task_dispatcher=td) try: while 1: === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.16 => 1.1.2.17 === from Zope.Server.LineReceiver.LineServerChannel import LineServerChannel from FTPStatusMessages import status_msgs +from OSEmulators import unix_longify as longify from IFTPCommandHandler import IFTPCommandHandler from PassiveAcceptor import PassiveAcceptor @@ -109,7 +110,7 @@ def cmd_cdup(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' path = self._generatePath('../') - if self.server.filesystem.exists(path): + if self.server.openFilesystem(self.username).exists(path): self.cwd = path self.reply('SUCCESS_250', 'CDUP') else: @@ -119,7 +120,7 @@ def cmd_cwd(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' path = self._generatePath(args) - if self.server.filesystem.exists(path): + if self.server.openFilesystem(self.username).exists(path): self.cwd = path self.reply('SUCCESS_250', 'CWD') else: @@ -134,7 +135,7 @@ path = self._generatePath(args) try: - self.server.filesystem.remove(path) + self.server.openFilesystem(self.username).remove(path) except OSError, err: self.reply('ERR_DELETE_FILE', str(err)) else: @@ -169,11 +170,12 @@ def cmd_mdtm(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' path = self._generatePath(args) - if not self.server.filesystem.isfile(path): + if not self.server.openFilesystem(self.username).isfile(path): self.reply('ERR_IS_NOT_FILE', path) else: mtime = time.gmtime( - self.server.filesystem.stat(path)[stat.ST_MTIME] + self.server.openFilesystem( + self.username).stat(path)[stat.ST_MTIME] ) self.reply('FILE_DATE', (mtime[0], mtime[1], mtime[2], mtime[3], mtime[4], mtime[5]) ) @@ -186,7 +188,7 @@ return path = self._generatePath(args) try: - self.server.filesystem.mkdir(path) + self.server.openFilesystem(self.username).mkdir(path) except OSError, err: self.reply('ERR_CREATE_DIR', str(err)) else: @@ -266,7 +268,7 @@ self.reply('CMD_UNKNOWN', 'RETR') path = self._generatePath(args) - if not self.server.filesystem.isfile(path): + if not self.server.openFilesystem(self.username).isfile(path): self.reply('ERR_IS_NOT_FILE', path) return @@ -283,7 +285,7 @@ outstream = ApplicationXmitStream(cdc) try: - self.server.filesystem.readfile( + self.server.openFilesystem(self.username).readfile( path, mode, outstream, start) cdc.close_when_done() except OSError, err: @@ -310,7 +312,7 @@ return path = self._generatePath(args) try: - self.server.filesystem.rmdir(path) + self.server.openFilesystem(self.username).rmdir(path) except OSError, err: self.reply('ERR_DELETE_DIR', str(err)) else: @@ -320,7 +322,7 @@ def cmd_rnfr(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' path = self._generatePath(args) - if self.server.filesystem.exists(path): + if self.server.openFilesystem(self.username).exists(path): self._rnfr = path self.reply('READY_FOR_DEST') else: @@ -333,7 +335,7 @@ if self._rnfr is None: self.reply('ERR_RENAME') try: - self.server.filesystem.rename(self._rnfr, path) + self.server.openFilesystem(self.username).rename(self._rnfr, path) except OSError, err: self.reply('ERR_RENAME', (self._rnfr, rnto, str(err))) else: @@ -344,11 +346,11 @@ def cmd_size(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' path = self._generatePath(args) - if not self.server.filesystem.isfile(path): + if not self.server.openFilesystem(self.username).isfile(path): self.reply('ERR_NO_FILE', path) else: - self.reply('FILE_SIZE', - self.server.filesystem.stat(path)[stat.ST_SIZE]) + self.reply('FILE_SIZE', self.server.openFilesystem( + self.username).stat(path)[stat.ST_SIZE]) def cmd_stor(self, args, write_mode='w'): @@ -368,7 +370,7 @@ # Verify the file can be opened, but don't open it yet. # The actually write should be transactional without # holding up the application. - fs = self.server.filesystem + fs = self.server.openFilesystem(self.username) fs.check_writable(path, mode) except OSError, err: self.reply('ERR_OPEN_WRITE', str(err)) @@ -388,7 +390,8 @@ try: infile = buffer.getfile() infile.seek(0) - self.server.filesystem.writefile(path, mode, infile, start) + self.server.openFilesystem(self.username).writefile(path, mode, + infile, start) except OSError, err: self.reply('ERR_OPEN_WRITE', str(err)) except IOError, err: @@ -462,11 +465,12 @@ def listdir (self, path, long=0): """returns a string""" - res = self.server.filesystem.listdir(path, long) - if hasattr(res, 'read'): - # Dump the stream. - res = res.read() - return res + path = self._generatePath(path) + file_list = self.server.openFilesystem(self.username).listdir(path, + long) + if long: + file_list = map(longify, file_list) + return '\r\n'.join(file_list) + '\r\n' def getDirectoryList(self, args, long=0): === Zope3/lib/python/Zope/Server/FTP/PublisherFTPServer.py 1.1.2.2 => 1.1.2.3 === $Id$ """ +import asyncore +import pwd +from FTPServerChannel import FTPServerChannel +from Zope.Server.ServerBase import ServerBase -from FTPServer import FTPServer +from Zope.StartUp.RequestFactory import RequestFactory from Zope.Server.VFS.PublisherFileSystem import PublisherFileSystem +from Zope.Server.Authentication.DictionaryAuthentication import \ + DictionaryAuthentication +from ZODB import DB +from ZODB.FileStorage import FileStorage +from Zope.Publisher.VFS.VFSRequest import VFSRequest +from Zope.App.ZopePublication.VFS.Publication import VFSPublication -class PublisherFTPServer(FTPServer): - """Zope Publisher-specific HTTP Server""" +class FileSystemOpener: - __implements__ = FTPServer.__implements__ - filesystem = PublisherFileSystem('/') + def __init__(self, root_dir, request_factory): + self.root_dir = root_dir + self.filesystem_class = PublisherFileSystem + self.filesystem_class.request_factory = request_factory + def __call__(self, username): + persona = pwd.getpwnam(username)[2:4] + return self.filesystem_class(self.root_dir, persona) - def __init__(self, request_factory, sub_protocol=None, *args, **kw): - self.request_factory = request_factory - self.filesystem.request_factory = self.request_factory - if sub_protocol: - self.SERVER_IDENT += ' (%s)' %sub_protocol +class PublisherFTPServer(ServerBase): + """Generic FTP Server""" + + channel_class = FTPServerChannel + SERVER_IDENT = 'Zope.Server.FTPServer' + + + def __init__(self, request_factory, ip, port, task_dispatcher=None, + adj=None, start=1, hit_log=None, verbose=0, socket_map=None, + fs_opener=None, auth_source=None): + + self.request_factory = request_factory + self.openFilesystem = fs_opener + self.auth_source = auth_source - FTPServer.__init__(self, *args, **kw) + super(PublisherFTPServer, self).__init__(ip, port, task_dispatcher, + adj, start, hit_log, + verbose, socket_map) + + +if __name__ == '__main__': + from Zope.Server.TaskThreads import ThreadedTaskDispatcher + td = ThreadedTaskDispatcher() + td.setThreadCount(4) + + auth_source = DictionaryAuthentication({'root': 'bar'}) + req = RequestFactory(VFSPublication, VFSRequest) + db = DB(FileStorage('/opt/Zope3-Branches/Zope-3x-Server/Data.fs')) + req = req.realize(db) + fs_opener = FileSystemOpener(dir, req) + + + from Zope.App.OFS.Container.Views.VFS.VFSContainerView import \ + VFSContainerView + from Zope.App.OFS.Container.ContainerTraverser import ContainerTraverser + from Zope.Publisher.VFS.IVFSPublisher import IVFSPublisher + from Zope.App.OFS.Container.IContainer import IContainer + from Zope.App.OFS.Folder.RootFolder import IRootFolder + from Zope.ComponentArchitecture import provideView, setDefaultViewName + setDefaultViewName(IContainer, IVFSPublisher, 'vfs') + provideView(IContainer, 'vfs', IVFSPublisher, VFSContainerView, '') + provideView(IContainer, '_traverse', IVFSPublisher, ContainerTraverser, '') + + from Zope.App.Security.PrincipalRoleManager import \ + principalRoleManager as principal_role_mgr + from Zope.App.Security.PrincipalRegistry import principalRegistry + + principalRegistry.defineDefaultPrincipal('anybody', 'anybody', 'All') + principal_role_mgr.assignRoleToPrincipal('Manager', 'anybody') + + PublisherFTPServer(req, '', 8021, task_dispatcher=td, fs_opener=fs_opener, + auth_source=auth_source) + try: + while 1: + asyncore.poll(5) + print 'active channels:', FTPServerChannel.active_channels + except KeyboardInterrupt: + print 'shutting down...' + td.shutdown() From srichter@cbu.edu Tue Apr 9 17:12:33 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 12:12:33 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - IReadFileSystem.py:1.1.2.5 IWriteFileSystem.py:1.1.2.5 OSFileSystem.py:1.1.2.13 PublisherFileSystem.py:1.1.2.4 UnixFileSystem.py:1.1.2.5 Message-ID: <200204091612.g39GCXi05694@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv4334/Server/VFS Modified Files: Tag: Zope3-Server-Branch IReadFileSystem.py IWriteFileSystem.py OSFileSystem.py PublisherFileSystem.py UnixFileSystem.py Log Message: Check in my big mess of stuff, which is working towards making FTP work together with the Publisher. I will keep working on startup now, so that we can test easier. This is basically a check-in, so that Shane can see what I have done last night. Please do not expect anything towork, since this is more than just work in progress... it is a prototype to get FTP running via Publisher! === Zope3/lib/python/Zope/Server/VFS/IReadFileSystem.py 1.1.2.4 => 1.1.2.5 === """ - def listdir(path, long=0): - """Return a listing of the directory at 'path' The empty string - indicates the current directory. If 'long' is set, instead - return a list of (name, stat_info) tuples + def listdir(path, with_stats=0, pattern='*'): + """Return a listing of the directory at 'path' The empty + string indicates the current directory. If 'with_stats' is set, + instead return a list of (name, stat_info) tuples. All file + names are filtered by the pattern, which is epected to be a regular + filesystem search pattern. """ return list(tuple(str, str)) - - def longify(path, stat): - """Return a 'long' representation of the filename - [for the output of the LIST command] - """ def readfile(path, mode, outstream, start=0, end=-1): """Outputs the file at path to a stream. === Zope3/lib/python/Zope/Server/VFS/IWriteFileSystem.py 1.1.2.4 => 1.1.2.5 === """ - def chmod(path, mode): - """Change the access permissions of a file. - """ - - def chown(path, uid, gid): - """Change the owner and group id of path to numeric uid and gid. - """ - - def link(src, dst): - """Create a heard link to a file. - """ - def mkdir(path, mode=777): """Create a directory. """ - def mkfifo(path, mode=777): - """Create a FIFO (a POSIX named pipe). - """ - def remove(path): """Remove a file. Same as unlink. """ @@ -57,10 +41,6 @@ def rename(old, new): """Rename a file or directory. - """ - - def symlink(src, dst): - """Create a symbolic link at dst pointing to src. """ def writefile(path, mode, instream, start=0): === Zope3/lib/python/Zope/Server/VFS/OSFileSystem.py 1.1.2.12 => 1.1.2.13 === $Id$ """ - import os import re import stat import time +import fnmatch -from IReadFileSystem import IReadFileSystem -from IWriteFileSystem import IWriteFileSystem +from IPosixFileSystem import IPosixFileSystem -class OSFileSystem: +class OSFileSystem(object): """Generic OS FileSystem implementation. The root of this file system is a string describing the path to the directory used as root. """ - __implements__ = IReadFileSystem, IWriteFileSystem + __implements__ = IPosixFileSystem path_module = os.path @@ -42,10 +41,43 @@ def __init__ (self, root): self.root = root - ############################################################ # Implementation methods for interface - # Zope.Server.VFS.IReadFileSystem.IReadFileSystem + # Zope.Server.VFS.IPosixFileSystem.IPosixFileSystem + + def chmod(self, path, mode): + 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' + p = self.translate (path) + return os.chmod(p, mode) + + + def chown(self, path, uid, gid): + 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' + p = self.translate (path) + return os.chown(p, uid, gid) + + + def link(self, src, dst): + 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' + src = self.translate(src) + dst = self.translate(dst) + return os.link(src, dst) + + + def mkfifo(self, path, mode=6*2**6): + 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' + return os.mkfifo(path, mode) + + + def symlink(self, src, dst): + 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' + src = self.translate(src) + dst = self.translate(dst) + return os.symlink(src, dst) + + + ###################################### + # from: Zope.Server.VFS.IReadFileSystem.IReadFileSystem def exists(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' @@ -65,14 +97,16 @@ return self.path_module.isfile(p) - def listdir(self, path, long=0): + def listdir(self, path, with_stats=0, pattern='*'): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' p = self.translate(path) - # I think we should glob, but limit it to the current - # directory only. + # list the directory's files ld = os.listdir(p) + # filter them using the pattern + ld = filter(lambda f, p=pattern, fnm=fnmatch.fnmatch: fnm(f, p), ld) + # sort them alphabetically ld.sort() - if not long: + if not with_stats: result = ld else: result = [] @@ -80,13 +114,8 @@ path = self.path_module.join(p, file) stat = safe_stat(path) if stat is not None: - result.append(self.longify(file, safe_stat(path))) - return '\r\n'.join(result) + '\r\n' - - - def longify(self, path, stat_info): - 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' - return unix_longify(path, stat_info) + result.append((file, stat)) + return result def readfile(self, path, mode, outstream, start=0, end=-1): @@ -112,31 +141,9 @@ p = self.translate(path) return os.stat(p) - # - ############################################################ - - ############################################################ - # Implementation methods for interface - # Zope.Server.VFS.IWriteFileSystem. - - def chmod(self, path, mode): - 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' - p = self.translate (path) - return os.chmod(p, mode) - - - def chown(self, path, uid, gid): - 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' - p = self.translate (path) - return os.chown(p, uid, gid) - - - def link(self, src, dst): - 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' - src = self.translate(src) - dst = self.translate(dst) - return os.link(src, dst) + ###################################### + # from: Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem def mkdir(self, path, mode=6*2**6): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' @@ -144,11 +151,6 @@ return os.mkdir(p, mode) - def mkfifo(self, path, mode=6*2**6): - 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' - return os.mkfifo(path, mode) - - def remove(self, path): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' p = self.translate (path) @@ -168,13 +170,6 @@ return os.rename(old, new) - def symlink(self, src, dst): - 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' - src = self.translate(src) - dst = self.translate(dst) - return os.symlink(src, dst) - - def writefile(self, path, mode, instream, start=0): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' p = self.translate(path) @@ -198,7 +193,6 @@ f.close() if remove: os.remove(p) - # ############################################################ @@ -239,77 +233,6 @@ def __repr__ (self): return '' % self.root - -months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] - -mode_table = { - '0':'---', - '1':'--x', - '2':'-w-', - '3':'-wx', - '4':'r--', - '5':'r-x', - '6':'rw-', - '7':'rwx' - } - - -def unix_longify (file, stat_info): - # for now, only pay attention to the lower bits - - import pwd, grp - - try: username = pwd.getpwuid(int(stat_info[stat.ST_UID]))[0] - except: username = stat_info[stat.ST_UID] - - try: grpname = grp.getgrgid(int(stat_info[stat.ST_GID]))[0] - except: grpname = stat_info[stat.ST_GID] - - - mode = ('%o' % stat_info[stat.ST_MODE])[-3:] - mode = ''.join(map (lambda x: mode_table[x], mode)) - if stat.S_ISDIR (stat_info[stat.ST_MODE]): - dirchar = 'd' - else: - dirchar = '-' - date = ls_date (long(time.time()), stat_info[stat.ST_MTIME]) - return '%s%s %3d %-8s %-8s %8d %s %s' % ( - dirchar, - mode, - stat_info[stat.ST_NLINK], - username, - grpname, - stat_info[stat.ST_SIZE], - date, - file - ) - - -def ls_date (now, t): - """Emulate the unix 'ls' command's date field. it has two formats - - if the date is more than 180 days in the past, then it's like - this: Oct 19 1995 otherwise, it looks like this: Oct 19 17:33 - """ - try: - info = time.gmtime(t) - except: - info = time.gmtime(0) - - # 15,600,000 == 86,400 * 180 - if (now - t) > 15600000: - return '%s %2d %d' % ( - months[info[1]-1], - info[2], - info[0] - ) - else: - return '%s %2d %02d:%02d' % ( - months[info[1]-1], - info[2], - info[3], - info[4] - ) def safe_stat (path): === Zope3/lib/python/Zope/Server/VFS/PublisherFileSystem.py 1.1.2.3 => 1.1.2.4 === import time +from cStringIO import StringIO + from IReadFileSystem import IReadFileSystem from IWriteFileSystem import IWriteFileSystem @@ -33,10 +35,11 @@ __implements__ = IReadFileSystem, IWriteFileSystem + path_module = os.path request_factory = None - def __init__ (self, root): + def __init__ (self, root, persona): self.root = root @@ -48,25 +51,29 @@ env['command'] = command env['path'] = path - request = self.request_factory(StringIO(''), StringIO(''), env) + request = self.request_factory(StringIO(''), StringIO(), env) + resp = request._response publish(request) - return request.getResponse().getResult() + print resp.getResult() + return resp.getResult() ############################################################ # Implementation methods for interface - # Zope.Server.VFS.IReadFileSystem.IReadFileSystem + # Zope.Server.VFS.IReadFileSystem. def exists(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) - return self._execute(path, 'exists') - + path, file = os.path.split(path) + env = {'name': file} + return self._execute(path, 'exists', env) + def isdir(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) - return self._execute(path, 'isdir') + return self._execute(path, 'isdir', env) def isfile(self, path): @@ -75,29 +82,22 @@ return self._execute(path, 'isfile') - def listdir(self, path, long=0): + def listdir(self, path, with_stats=0, pattern='*'): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) - # Returns a list of Wrapper objects representing the objects - # Also, the Wrapper object should contain *all* stat information - ld = self._execute(path, 'listdir') - ld.sort() - if not long: - result = ld - else: - result = map(self.longify, ld) - return '\r\n'.join(result) + '\r\n' - - - def longify(self, (path, stat_info)): - 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' - return unix_longify (path, stat_info) + env = {'with_stats' : with_stats, + 'pattern' : pattern} + return self._execute(path, 'listdir', env) - def open(self, path, mode): + def readfile(self, path, mode, outstream, start=0, end=-1): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) - return self._execute(path, 'open', {'mode': mode}) + env = {'mode' : mode, + 'outstream' : outstream, + 'start' : start, + 'end' : end} + return self._execute(path, 'read', env) def stat(self, path): @@ -112,70 +112,60 @@ # Implementation methods for interface # Zope.Server.VFS.IWriteFileSystem. - def chmod(self, path, mode): - 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' - p = self.translate (path) - return os.chmod(p, mode) - - - def chown(self, path, uid, gid): - 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' - p = self.translate (path) - raise NotImplementedError('This function is not implemented.') - - - def link(self, src, dst): + def mkdir(self, path, mode=777): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' - src = self.translate(src) - dst = self.translate(dst) - raise NotImplementedError('This function is not implemented.') - - - def mkdir(self, path, mode=6*2**6): - 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' - p = self.translate(path) - + path = self.translate(path) + path, dir = os.path.split(path) + env = {'name': dir} + return self._execute(path, 'mkdir', env) - def mkfifo(self, path, mode=6*2**6): - 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' - raise NotImplementedError('This function is not implemented.') def remove(self, path): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' - p = self.translate (path) + path = self.translate(path) + path, name = os.path.split(path) + env = {'name': file} + return self._execute(path, 'remove', env) def rmdir(self, path): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' - p = self.translate (path) + path = self.translate(path) + path, dir = os.path.split(path) + env = {'name': dir} + return self._execute(path, 'rmdir', env) def rename(self, old, new): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' old = self.translate(old) new = self.translate(new) + path0, old = os.path.split(old) + path1, new = os.path.split(new) + assert path0 == path1 + env = {'old' : old, + 'new' : new} + return self._execute(path0, 'rename', env) - - def symlink(self, src, dst): - 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' - src = self.translate(src) - dst = self.translate(dst) - raise NotImplementedError('This function is not implemented.') - - - def unlink(self, path): + def writefile(self, path, mode, instream, start=0): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' - pass + path = self.translate(path) + env = {'mode' : mode, + 'outstream' : outstream, + 'start' : start, + 'end' : end} + return self._execute(path, 'write', env) - def write(self, fd, data): + def check_writable(self, path, mode): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' - pass + path = self.translate(path) + env = {'mode': mode} + return self._execute(path, 'check_writable', env) # ############################################################ - # utility methods def normalize (self, path): @@ -203,91 +193,9 @@ # Prepare for joining with root if path[0] == '/': path = path[1:] - # Join path with root - path = self.path_module.join(self.root, path) + return path def __repr__ (self): - return '' % self.root - - - - -months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] - -mode_table = { - '0':'---', - '1':'--x', - '2':'-w-', - '3':'-wx', - '4':'r--', - '5':'r-x', - '6':'rw-', - '7':'rwx' - } - - -def unix_longify (file, stat_info): - # for now, only pay attention to the lower bits - - import pwd, grp - - try: username = pwd.getpwuid(int(stat_info[stat.ST_UID]))[0] - except: username = stat_info[stat.ST_UID] - - try: grpname = grp.getgrgid(int(stat_info[stat.ST_GID]))[0] - except: grpname = stat_info[stat.ST_GID] - - - mode = ('%o' % stat_info[stat.ST_MODE])[-3:] - mode = ''.join(map (lambda x: mode_table[x], mode)) - if stat.S_ISDIR (stat_info[stat.ST_MODE]): - dirchar = 'd' - else: - dirchar = '-' - date = ls_date (long(time.time()), stat_info[stat.ST_MTIME]) - return '%s%s %3d %-8s %-8s %8d %s %s' % ( - dirchar, - mode, - stat_info[stat.ST_NLINK], - username, - grpname, - stat_info[stat.ST_SIZE], - date, - file - ) - - -def ls_date (now, t): - """Emulate the unix 'ls' command's date field. it has two formats - - if the date is more than 180 days in the past, then it's like - this: Oct 19 1995 otherwise, it looks like this: Oct 19 17:33 - """ - try: - info = time.gmtime(t) - except: - info = time.gmtime(0) - - # 15,600,000 == 86,400 * 180 - if (now - t) > 15600000: - return '%s %2d %d' % ( - months[info[1]-1], - info[2], - info[0] - ) - else: - return '%s %2d %02d:%02d' % ( - months[info[1]-1], - info[2], - info[3], - info[4] - ) - - -def safe_stat (path): - try: - return os.stat(path) - except: - return None + return '' === Zope3/lib/python/Zope/Server/VFS/UnixFileSystem.py 1.1.2.4 => 1.1.2.5 === # Get process information - PROCESS_UID = os.getuid() + PROCESS_UID = os.getuid() PROCESS_EUID = os.geteuid() - PROCESS_GID = os.getgid() + PROCESS_GID = os.getgid() PROCESS_EGID = os.getegid() def __init__ (self, root, persona=(None, None)): - super(SchizophrenicUnixFileSystem, self).__init__(root, wd) + super(SchizophrenicUnixFileSystem, self).__init__(root) self.persona = persona From casey@zope.com Tue Apr 9 17:20:22 2002 From: casey@zope.com (Casey Duncan) Date: Tue, 9 Apr 2002 12:20:22 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security/Management Zope3/lib/python/Zope/App/Security/Management - New directory Message-ID: <200204091620.g39GKMM07620@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Security/Management In directory cvs.zope.org:/tmp/cvs-serv7614/Zope/App/Security/Management Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/Security/Management added to the repository --> Using per-directory sticky tag `casey-security-reorg-branch' === Added directory Zope3/lib/python/Zope/App/Security/Management === From casey@zope.com Tue Apr 9 17:23:02 2002 From: casey@zope.com (Casey Duncan) Date: Tue, 9 Apr 2002 12:23:02 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security/Management/tests Zope3/lib/python/Zope/App/Security/Management/tests - New directory Message-ID: <200204091623.g39GN2Z08343@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Security/Management/tests In directory cvs.zope.org:/tmp/cvs-serv8323/Zope/App/Security/Management/tests Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/Security/Management/tests added to the repository --> Using per-directory sticky tag `casey-security-reorg-branch' === Added directory Zope3/lib/python/Zope/App/Security/Management/tests === From casey@zope.com Tue Apr 9 17:36:45 2002 From: casey@zope.com (Casey Duncan) Date: Tue, 9 Apr 2002 12:36:45 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZMI - ZMIViewService.py:1.1.2.8.6.1 Message-ID: <200204091636.g39GajE12961@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZMI In directory cvs.zope.org:/tmp/cvs-serv11768/Zope/App/ZMI Modified Files: Tag: casey-security-reorg-branch ZMIViewService.py Log Message: Mass checkin for security reorganization branch. I will retest this and merge upon BDFL approval... === Zope3/lib/python/Zope/App/ZMI/ZMIViewService.py 1.1.2.8 => 1.1.2.8.6.1 === res.append( view_value ) - + print res return res def _createContext(self, object): From casey@zope.com Tue Apr 9 17:36:45 2002 From: casey@zope.com (Casey Duncan) Date: Tue, 9 Apr 2002 12:36:45 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication/tests - testZopePublication.py:1.1.2.20.2.1 Message-ID: <200204091636.g39Gaj412967@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/tests In directory cvs.zope.org:/tmp/cvs-serv11768/Zope/App/ZopePublication/tests Modified Files: Tag: casey-security-reorg-branch testZopePublication.py Log Message: Mass checkin for security reorganization branch. I will retest this and merge upon BDFL approval... === Zope3/lib/python/Zope/App/ZopePublication/tests/testZopePublication.py 1.1.2.20 => 1.1.2.20.2.1 === from Zope.App.Security.PrincipalRegistry import principalRegistry -from Zope.App.Security.PrincipalRoleManager import principalRoleManager +from Zope.App.Security.Management.GlobalPrincipalRoles \ + import principalRolesManager from Zope.ComponentArchitecture import provideView @@ -158,7 +159,7 @@ 'timbot', 'ai at its best') - principalRoleManager.assignRoleToPrincipal('Manager', 'tim') + principalRolesManager.assignRoleToPrincipal('Manager', 'tim') # now place our object inside the application From casey@zope.com Tue Apr 9 17:36:45 2002 From: casey@zope.com (Casey Duncan) Date: Tue, 9 Apr 2002 12:36:45 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security/Management - GlobalPrincipalPermissions.py:1.1.2.1 GlobalPrincipalRoles.py:1.1.2.1 GlobalRolePermissions.py:1.1.2.1 IPrincipalPermissions.py:1.1.2.1 IPrincipalRoles.py:1.1.2.1 IRolePermissions.py:1.1.2.1 MementoPrincipalPermissions.py:1.1.2.1 MementoPrincipalRoles.py:1.1.2.1 MementoRolePermissions.py:1.1.2.1 PrincipalPermissionsView.py:1.1.2.1 PrincipalRolesView.py:1.1.2.1 RolePermissionsView.py:1.1.2.1 Settings.py:1.1.2.1 __init__.py:1.1.2.1 management.zcml:1.1.2.1 Message-ID: <200204091636.g39GajB12960@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Security/Management In directory cvs.zope.org:/tmp/cvs-serv11768/Zope/App/Security/Management Added Files: Tag: casey-security-reorg-branch GlobalPrincipalPermissions.py GlobalPrincipalRoles.py GlobalRolePermissions.py IPrincipalPermissions.py IPrincipalRoles.py IRolePermissions.py MementoPrincipalPermissions.py MementoPrincipalRoles.py MementoRolePermissions.py PrincipalPermissionsView.py PrincipalRolesView.py RolePermissionsView.py Settings.py __init__.py management.zcml Log Message: Mass checkin for security reorganization branch. I will retest this and merge upon BDFL approval... === Added File Zope3/lib/python/Zope/App/Security/Management/GlobalPrincipalPermissions.py === # GlobalPrincipalPermissions.py # # Copyright (c) 2001 Zope Coporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. """ $Id: GlobalPrincipalPermissions.py,v 1.1.2.1 2002/04/09 16:36:43 caseman Exp $ """ from Zope.App.Security.Management.IPrincipalPermissions \ import IPrincipalPermissionsManager from Zope.App.Security.LocalSecurityMap import LocalSecurityMap from Zope.App.Security.Management.Settings import Allow, Deny, Unset class PrincipalPermissionsManager(LocalSecurityMap): """Mappings between principals and permissions.""" __implements__ = IPrincipalPermissionsManager def grantPermissionToPrincipal( self, permission_id, principal_id ): ''' See the interface IPrincipalPermissionManager ''' self.addCell( permission_id, principal_id, Allow ) def denyPermissionToPrincipal( self, permission_id, principal_id ): ''' See the interface IPrincipalPermissionManager ''' self.addCell( permission_id, principal_id, Deny ) def unsetPermissionForPrincipal( self, permission_id, principal_id ): ''' See the interface IPrincipalPermissionManager ''' self.delCell( permission_id, principal_id ) def getPrincipalsForPermission( self, permission_id ): ''' See the interface IPrincipalPermissionManager ''' return self.getRow( permission_id ) def getPermissionsForPrincipal( self, principal_id ): ''' See the interface IPrincipalPermissionManager ''' return self.getCol( principal_id ) def getSetting( self, permission_id, principal_id ): ''' See the interface IPrincipalPermissionManager ''' return self.getCell( permission_id, principal_id, default=Unset ) def getPrincipalsAndPermissions( self ): ''' See the interface IPrincipalPermissionManager ''' return self.getAllCells() # Permissions are our rows, and principals are our columns principalPermissionsManager = PrincipalPermissionsManager() # Register our cleanup with Testing.CleanUp to make writing unit tests simpler. from Zope.Testing.CleanUp import addCleanUp addCleanUp(principalPermissionsManager._clear) del addCleanUp === Added File Zope3/lib/python/Zope/App/Security/Management/GlobalPrincipalRoles.py === # GlobalPrincipalRoles.py # # Copyright (c) 2001 Zope Coporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. """ $Id: GlobalPrincipalRoles.py,v 1.1.2.1 2002/04/09 16:36:43 caseman Exp $ """ from Zope.App.Security.LocalSecurityMap import LocalSecurityMap from Zope.App.Security.Management.Settings import Assign, Remove, Unset from Zope.App.Security.Management.IPrincipalRoles \ import IPrincipalRolesManager class PrincipalRolesManager(LocalSecurityMap): """Mappings between principals and roles.""" __implements__ = IPrincipalRolesManager def assignRoleToPrincipal( self, role_id, principal_id ): ''' See the interface IPrincipalRoleManager ''' self.addCell( role_id, principal_id, Assign ) def removeRoleFromPrincipal( self, role_id, principal_id ): ''' See the interface IPrincipalRoleManager ''' self.addCell( role_id, principal_id, Remove ) def unsetRoleForPrincipal( self, role_id, principal_id ): ''' See the interface IPrincipalRoleManager ''' self.delCell( role_id, principal_id ) def getPrincipalsForRole( self, role_id ): ''' See the interface IPrincipalRoleMap ''' return self.getRow( role_id ) def getRolesForPrincipal( self, principal_id ): ''' See the interface IPrincipalRoleMap ''' return self.getCol( principal_id ) def getSetting( self, role_id, principal_id ): ''' See the interface IPrincipalRoleMap ''' return self.getCell( role_id, principal_id, default=Unset ) def getPrincipalsAndRoles( self ): ''' See the interface IPrincipalRoleMap ''' return self.getAllCells() # Roles are our rows, and principals are our columns principalRolesManager = PrincipalRolesManager() # Register our cleanup with Testing.CleanUp to make writing unit tests simpler. from Zope.Testing.CleanUp import addCleanUp addCleanUp(principalRolesManager._clear) del addCleanUp === Added File Zope3/lib/python/Zope/App/Security/Management/GlobalRolePermissions.py === # GlobalRolePermissions.py # # Copyright (c) 2001 Zope Coporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. """ $Id: GlobalRolePermissions.py,v 1.1.2.1 2002/04/09 16:36:43 caseman Exp $ """ from Zope.App.Security.LocalSecurityMap import LocalSecurityMap from Zope.App.Security.Management.Settings import Allow, Deny from Zope.App.Security.Management.IRolePermissions \ import IRolePermissionsManager class RolePermissionsManager(LocalSecurityMap): """Mappings between roles and permissions.""" __implements__ = IRolePermissionsManager def grantPermissionToRole( self, permission_id, role_id ): '''See interface IRolePermissionMap''' self.addCell( permission_id, role_id, Allow ) def denyPermissionToRole( self, permission_id, role_id ): '''See interface IRolePermissionMap''' self.addCell( permission_id, role_id, Deny ) def unsetPermissionFromRole( self, permission_id, role_id ): '''See interface IRolePermissionMap''' self.delCell( permission_id, role_id ) def getRolesForPermission( self, permission_id ): '''See interface IRolePermissionMap''' return self.getRow( permission_id ) def getPermissionsForRole( self, role_id ): '''See interface IRolePermissionMap''' return self.getCol( role_id ) def getSetting( self, permission_id, role_id ): '''See interface IRolePermissionMap''' return self.getCell( permission_id, role_id ) def getRolesAndPermissions( self ): '''See interface IRolePermissionMap''' return self.getAllCells() # Permissions are our rows, and roles are our columns rolePermissionsManager = RolePermissionsManager() # Register our cleanup with Testing.CleanUp to make writing unit tests simpler. from Zope.Testing.CleanUp import addCleanUp addCleanUp(rolePermissionsManager._clear) del addCleanUp === Added File Zope3/lib/python/Zope/App/Security/Management/IPrincipalPermissions.py === # IPrincipalPermissions.py # # Copyright (c) 2001 Zope Coporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. """Mappings between principals and permissions.""" from Interface import Interface class IPrincipalPermissions(Interface): """Mappings between principals and permissions.""" def getPrincipalsForPermission(permission_id): """Return the list of (principal_id, setting) tuples that describe security assertions for this permission. If no principals have been set for this permission, then the empty list is returned. """ def getPermissionsForPrincipal(principal_id): """Return the list of (permission, setting) tuples that describe security assertions for this principal. If no permissions have been set for this principal, then the empty list is returned. """ def getSetting(permission_id, principal_id): """Get the setting (Allow/Deny/Unset) for a given permission and principal. """ def getPrincipalsAndPermissions(): """Get the principal security assertions here in the form of a list of three tuple containing (permission id, principal id, setting) """ class IPrincipalPermissionsManager(IPrincipalPermissions): """Management interface for mappings between principals and permissions.""" def grantPermissionToPrincipal(permission_id, principal_id): """Assert that the permission is allowed for the principal. """ def denyPermissionToPrincipal(permission_id, principal_id): """Assert that the permission is denied to the principal. """ def unsetPermissionForPrincipal(permission_id, principal_id): """Remove the permission (either denied or allowed) from the principal. """ === Added File Zope3/lib/python/Zope/App/Security/Management/IPrincipalRoles.py === # IPrincipalRoleManager.py # # Copyright (c) 2001 Zope Coporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. """Mappings between principals and roles.""" from Interface import Interface class IPrincipalRoles(Interface): """Mappings between principals and roles.""" def getPrincipalsForRole(role_id): """Return the list of (principal, setting) who have been assigned or removed from a role. If no principals have been assigned this role, then the empty list is returned. """ def getRolesForPrincipal(principal_id): """Return the list of (role, setting) assigned or removed from this principal. If no roles have been assigned to this principal, then the empty list is returned. """ def getSetting(role_id, principal_id): """Return the setting for this principal, role combination """ def getPrincipalsAndRoles(): """Return all the principal/role combinations along with the setting for each combination. """ class IPrincipalRolesManager(IPrincipalRoles): """Management interface for mappings between principals and roles.""" def assignRoleToPrincipal(role_id, principal_id): """Assign the role to the principal. """ def removeRoleFromPrincipal(role_id, principal_id): """Remove a role from the principal """ def unsetRoleForPrincipal(role_id, principal_id): """Unset the role for the principal """ === Added File Zope3/lib/python/Zope/App/Security/Management/IRolePermissions.py === # IRolePermissionManager.py # # Copyright (c) 2001 Zope Coporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. """Mappings between roles and permissions.""" from Interface import Interface class IRolePermissions(Interface): """Mappings between roles and permissions.""" def getPermissionsForRole(role_id): """Return a sequence of (permission id, setting) tuples for the given role. If no permissions have been granted to this role, then the empty list is returned. """ def getRolesForPermission(permission_id): """Return a sequence of (role id, setting) tuples for the given permission. If no roles have been granted this permission, then the empty list is returned. """ def getSetting(permission_id, role_id): """Return the setting for the given permission id and role id If there is no setting, Unset is returned """ def getPrincipalsAndRoles(): """Return a sequence of (principal_id, role_id, setting) here. If no principal/role assertions have been made here, then the empty list is returned. """ class IRolePermissionsManager(IRolePermissions): """Management interface for mappings between roles and permissions.""" def grantPermissionToRole(permission_id, role_id): """allow the permission to the role. """ def denyPermissionToRole(permission_id, role_id): """Deny the permission to the role """ def unsetPermissionFromRole(permission_id, role_id): """Clear the setting of the permission to the role. """ === Added File Zope3/lib/python/Zope/App/Security/Management/MementoPrincipalPermissions.py === # AttributePrincipalPermissionManager.py # # Copyright (c) 2001 Zope Coporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. """ $Id: MementoPrincipalPermissions.py,v 1.1.2.1 2002/04/09 16:36:43 caseman Exp $ """ from Zope.ComponentArchitecture import getAdapter from Zope.App.OFS.Memento.IMementoBag import IMementoBag from Zope.App.Security.Management.IPrincipalPermissions \ import IPrincipalPermissionsManager from Zope.App.Security.LocalSecurityMap import LocalSecurityMap from Zope.App.Security.Management.Settings import Allow, Deny, Unset memo_key = 'Zope.App.Security.Management.MementoPrincipalPermissionsManager' class MementoPrincipalPermissionsManager: """ Provide adapter to manage principal permission data in a memento """ __implements__ = IPrincipalPermissionsManager def __init__(self, context): self._context = context def grantPermissionToPrincipal( self, permission_id, principal_id ): ''' See the interface IPrincipalPermissionManager ''' pp = self._getPrincipalPermissions(create=1) pp.addCell( permission_id, principal_id, Allow ) self._context._p_changed = 1 def denyPermissionToPrincipal( self, permission_id, principal_id ): ''' See the interface IPrincipalPermissionManager ''' pp = self._getPrincipalPermissions(create=1) pp.addCell( permission_id, principal_id, Deny ) self._context._p_changed = 1 def unsetPermissionForPrincipal( self, permission_id, principal_id ): ''' See the interface IPrincipalPermissionManager ''' pp = self._getPrincipalPermissions() # Only unset if there is a security map, otherwise, we're done if pp: pp.delCell( permission_id, principal_id ) self._context._p_changed = 1 def getPrincipalsForPermission( self, permission_id ): ''' See the interface IPrincipalPermissionManager ''' pp = self._getPrincipalPermissions() if pp: return pp.getRow( permission_id ) return [] def getPermissionsForPrincipal( self, principal_id ): ''' See the interface IPrincipalPermissionManager ''' pp = self._getPrincipalPermissions() if pp: return pp.getCol( principal_id ) return [] def getSetting( self, permission_id, principal_id ): ''' See the interface IPrincipalPermissionManager ''' pp = self._getPrincipalPermissions() if pp: return pp.getCell( permission_id, principal_id, default=Unset ) return [] def getPrincipalsAndPermissions( self ): ''' See the interface IPrincipalPermissionManager ''' pp = self._getPrincipalPermissions() if pp: return pp.getAllCells() return [] # Implementation helpers def _getPrincipalPermissions(self, create=0): """ Get the principal permission map stored in the context, optionally creating one if necessary """ memo = getAdapter(self._context, IMementoBag) try: return memo[memo_key] except KeyError: if create: rp = memo[memo_key] = LocalSecurityMap() return rp return None === Added File Zope3/lib/python/Zope/App/Security/Management/MementoPrincipalRoles.py === # AttributePrincipalRoleManager.py # # Copyright (c) 2001 Zope Coporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. """ $Id: MementoPrincipalRoles.py,v 1.1.2.1 2002/04/09 16:36:43 caseman Exp $ """ from Zope.ComponentArchitecture import getAdapter from Zope.App.OFS.Memento.IMementoBag import IMementoBag from Zope.App.Security.Management.IPrincipalRoles \ import IPrincipalRolesManager from Zope.App.Security.LocalSecurityMap import LocalSecurityMap from Zope.App.Security.Management.Settings import Assign, Remove, Unset memo_key = 'Zope.App.Security.Management.MementoPrincipalRoles' class MementoPrincipalRolesManager: """ Provide adapter to manage principal role data in a memento """ __implements__ = IPrincipalRolesManager def __init__(self, context): self._context = context def assignRoleToPrincipal( self, role_id, principal_id ): ''' See the interface IPrincipalRoleManager ''' pr = self._getPrincipalRoles(create=1) pr.addCell( role_id, principal_id, Assign ) self._context._p_changed = 1 def removeRoleFromPrincipal( self, role_id, principal_id ): ''' See the interface IPrincipalRoleManager ''' pr = self._getPrincipalRoles(create=1) pr.addCell( role_id, principal_id, Remove ) self._context._p_changed = 1 def unsetRoleForPrincipal( self, role_id, principal_id ): ''' See the interface IPrincipalRoleManager ''' pr = self._getPrincipalRoles() # Only unset if there is a security map, otherwise, we're done if pr: pr.delCell( role_id, principal_id ) self._context._p_changed = 1 def getPrincipalsForRole( self, role_id ): ''' See the interface IPrincipalRoleManager ''' pr = self._getPrincipalRoles() if pr: return pr.getRow( role_id ) return [] def getRolesForPrincipal( self, principal_id ): ''' See the interface IPrincipalRoleManager ''' pr = self._getPrincipalRoles() if pr: return pr.getCol( principal_id ) return [] def getSetting( self, role_id, principal_id ): ''' See the interface IPrincipalRoleManager ''' pr = self._getPrincipalRoles() if pr: return pr.getCell( role_id, principal_id, default=Unset ) return Unset def getPrincipalsAndRoles( self ): ''' See the interface IPrincipalRoleManager ''' pr = self._getPrincipalRoles() if pr: return pr.getAllCells() return [] # Implementation helpers def _getPrincipalRoles(self, create=0): """ Get the principal role map stored in the context, optionally creating one if necessary """ memo = getAdapter(self._context, IMementoBag) try: return memo[memo_key] except KeyError: if create: rp = memo[memo_key] = LocalSecurityMap() return rp return None === Added File Zope3/lib/python/Zope/App/Security/Management/MementoRolePermissions.py === ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ $Id: MementoRolePermissions.py,v 1.1.2.1 2002/04/09 16:36:43 caseman Exp $ """ from Zope.ComponentArchitecture import getAdapter from Zope.App.OFS.Memento.IMementoBag import IMementoBag from Zope.App.Security.Management.IRolePermissions \ import IRolePermissionsManager from Zope.App.Security.LocalSecurityMap import LocalSecurityMap from Zope.App.Security.Management.Settings import Allow, Deny, Unset memo_key = 'Zope.App.Security.Management.MementoRolePermissions' class MementoRolePermissionsManager: """ provide adaptor that manages role permission data in a memento """ __implements__ = IRolePermissionsManager def __init__(self, context): self._context = context def grantPermissionToRole( self, permission_id, role_id ): ''' See the interface IRolePermissionManager ''' rp = self._getRolePermissions(create=1) rp.addCell( permission_id, role_id, Allow ) self._context._p_changed = 1 def denyPermissionToRole( self, permission_id, role_id ): ''' See the interface IRolePermissionManager ''' rp = self._getRolePermissions(create=1) rp.addCell( permission_id, role_id, Deny ) self._context._p_changed = 1 def unsetPermissionFromRole( self, permission_id, role_id ): ''' See the interface IRolePermissionManager ''' rp = self._getRolePermissions() # Only unset if there is a security map, otherwise, we're done if rp: rp.delCell( permission_id, role_id ) self._context._p_changed = 1 def getRolesForPermission( self, permission_id ): '''See interface IRolePermissionMap''' rp = self._getRolePermissions() if rp: return rp.getRow( permission_id ) else: return [] def getPermissionsForRole( self, role_id ): '''See interface IRolePermissionMap''' rp = self._getRolePermissions() if rp: return rp.getCol( role_id ) else: return [] def getRolesAndPermissions( self ): '''See interface IRolePermissionMap''' rp = self._getRolePermissions() if rp: return rp.getAllCells( role_id ) else: return [] def getSetting( self, permission_id, role_id ): '''See interface IRolePermissionMap''' rp = self._getRolePermissions() if rp: return rp.getCell( permission_id, role_id ) else: return Unset def _getRolePermissions(self, create=0): """ Get the role permission map stored in the context, optionally creating one if necessary """ memo = getAdapter(self._context, IMementoBag) try: return memo[memo_key] except KeyError: if create: rp = memo[memo_key] = LocalSecurityMap() return rp return None === Added File Zope3/lib/python/Zope/App/Security/Management/PrincipalPermissionsView.py === ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE ############################################################################## """ $Id: PrincipalPermissionsView.py,v 1.1.2.1 2002/04/09 16:36:43 caseman Exp $ """ import time from Zope.PageTemplate.PageTemplateFile import PageTemplateFile from Zope.Publisher.Browser.AttributePublisher import AttributePublisher from Zope.ComponentArchitecture.ContextDependent import ContextDependent from Zope.ComponentArchitecture import getService, getAdapter from IPrincipalPermissions \ import IPrincipalPermissions, IPrincipalPermissionsManager from Settings import Allow, Deny, Unset class PrincipalPermissionsView(AttributePublisher, ContextDependent): index = PageTemplateFile('pt/principal_permission_edit.pt') def get_permission_service(self): return getService(self.getContext(), 'PermissionService') def get_principal(self, principal_id): return getService(self.getContext(), 'AuthenticationService' ).getPrincipal(principal_id) def unsetPermissions(self, principal_id, permission_ids, REQUEST=None): """Form action unsetting a principals permissions""" permission_service = self.get_permission_service() principal = self.get_principal(principal_id) ppm = getAdapter(self.getContext(), IPrincipalPermissionsManager) for perm_id in permission_ids: permission = permission_service.getPermission(perm_id) ppm.unsetPermissionForPrincipal(permission , principal) if REQUEST is not None: return self.index(message="Settings changed at %s" % time.ctime(time.time())) def grantPermissions(self, principal_id, permission_ids, REQUEST=None): """Form action granting a list of permissions to a principal""" permission_service = self.get_permission_service() principal = self.get_principal(principal_id) ppm = getAdapter(self.getContext(), IPrincipalPermissionsManager) for perm_id in permission_ids: permission = permission_service.getPermission(perm_id) ppm.grantPermissionToPrincipal(permission , principal) if REQUEST is not None: return self.index(message="Settings changed at %s" % time.ctime(time.time())) def denyPermissions(self, principal_id, permission_ids, REQUEST=None): """Form action denying a list of permissions for a principal""" permission_service = self.get_permission_service() principal = self.get_principal(principal_id) ppm = getAdapter(self.getContext(), IPrincipalPermissionsManager) for perm_id in permission_ids: permission = permission_service.getPermission(perm_id) ppm.denyPermissionToPrincipal(permission , principal) if REQUEST is not None: return self.index(message="Settings changed at %s" % time.ctime(time.time())) # Methods only called from the zpt view def getUnsetPermissionsForPrincipal(self, principal_id): """Returns all unset permissions for this principal""" ppmap = getAdapter(self.getContext(), IPrincipalPermissions) principal = self.get_principal(principal_id) perm_serv = getService(self.getContext(), 'PermissionService') result = [] for perm in perm_serv.getPermissions(): if ppmap.getSetting(perm, principal) == Unset: result.append(perm) return result def getPermissionsForPrincipal(self, principal_id, setting_name): """Return a list of permissions with the given setting_name string for the principal. Return empty list if there are no permissions. """ ppmap = getAdapter(self.getContext(), IPrincipalPermissions) principal = self.get_principal(principal_id) permission_settings = ppmap.getPermissionsForPrincipal(principal) setting_map = {'Deny': Deny, 'Allow':Allow} asked_setting = setting_map[setting_name] result = [] for permission, setting in permission_settings: if asked_setting == setting: result.append(permission) return result === Added File Zope3/lib/python/Zope/App/Security/Management/PrincipalRolesView.py === ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ Management view component for principal-role management (Zope2's "local roles"). $Id: PrincipalRolesView.py,v 1.1.2.1 2002/04/09 16:36:43 caseman Exp $ """ import time from Zope.PageTemplate.PageTemplateFile import PageTemplateFile from Zope.Publisher.Browser.AttributePublisher import AttributePublisher from Zope.ComponentArchitecture.ContextDependent import ContextDependent from Zope.ComponentArchitecture import getService, getAdapter from Zope.App.Security.Management.IPrincipalRoles \ import IPrincipalRolesManager, IPrincipalRoles from Zope.App.Security.IPermission import IPermission from Zope.App.Security.IRole import IRole class PrincipalRolesView(AttributePublisher, ContextDependent): index = PageTemplateFile('pt/principal_role_association.pt') def getAllPrincipals(self): principals = getattr(self, '_principals', None) if principals is None: principals = self._principals = getService( self.getContext(), 'AuthenticationService' ).getPrincipals() return principals def getAllRoles(self): roles = getattr(self, '_roles', None) if roles is None: roles = self._roles = getService( self.getContext(), 'RoleService' ).getRoles() return roles def createGrid( self, principals=None, roles=None ): if not principals: principals = self.getAllPrincipals() if not roles: roles = self.getAllRoles() return PrincipalRoleGrid( principals, roles, self.getContext() ) def action(self, principals, roles, mapping, testing=None): for row in mapping: pid = row.permission_id roles = row.role_ids if not testing: return self.index( message="Settings changed at %s" % time.ctime(time.time()) ) class PrincipalRoleGrid: def __init__( self, principals, roles, context ): self._principals = principals self._roles = roles self._grid = {} map = getAdapter( context, IPrincipalRoles ) for role in roles: for principal in principals: setting = map.getSetting( role, principal ) self._grid[ ( role, principal ) ] = setting def principals( self ): return self._principals def roles( self ): return self._roles def getValue( self, role, principal ): return self._grid[ ( role, principal ) ] def listAvailableValues( self ): return ( 'Unset', 'Assigned', 'Removed' ) === Added File Zope3/lib/python/Zope/App/Security/Management/RolePermissionsView.py === ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ $Id: RolePermissionsView.py,v 1.1.2.1 2002/04/09 16:36:43 caseman Exp $ """ import os, time from Zope.PageTemplate.PageTemplateFile import PageTemplateFile from Zope.Publisher.Browser.AttributePublisher import AttributePublisher from Zope.ComponentArchitecture.ContextDependent import ContextDependent from Zope.ComponentArchitecture import getService, getAdapter from Zope.App.Security.Management.IRolePermissions \ import IRolePermissionsManager from Zope.App.Security.IPermission import IPermission from Zope.App.Security.IRole import IRole from Zope.App.Security.Management.Settings import Allow, Assign class RolePermissionsView(AttributePublisher, ContextDependent): index = PageTemplateFile('pt/manage_access.pt') manage_permissionForm = PageTemplateFile('pt/manage_permissionForm.pt') manage_roleForm = PageTemplateFile('pt/manage_roleForm.pt') def roles(self): roles = getattr(self, '_roles', None) if roles is None: roles = self._roles = getService( self.getContext(), 'RoleService' ).getRoles() return roles def permissions(self): permissions = getattr(self, '_permissions', None) if permissions is None: permissions = self._permissions = getService( self.getContext(), 'PermissionService' ).getPermissions() return permissions def permissionRoles(self): context = self.getContext() roles = self.roles() return [PermissionRoles(permission, context, roles) for permission in self.permissions()] def permissionForID(self, pid): context = self.getContext() roles = self.roles() perm = getService(context, 'PermissionService' ).getPermission(pid) return PermissionRoles(perm, context, roles) def roleForID(self, rid): context = self.getContext() permissions = self.permissions() role = getService(context, 'RoleService' ).getRole(rid) return RolePermissions(role, context, permissions) def action(self, REQUEST, testing=None): roles = [r.getId() for r in self.roles()] permissions = [p.getId() for p in self.permissions()] prm = getAdapter(self.getContext(), IRolePermissionsManager) for ip in range(len(permissions)): rperm = REQUEST.get("p%s" % ip) if rperm not in permissions: continue for ir in range(len(roles)): rrole = REQUEST.get("r%s" % ir) if rrole not in roles: continue if REQUEST.has_key("p%sr%s" % (ip, ir)): prm.grantPermissionToRole(rperm, rrole) else: prm.unsetPermissionFromRole(rperm, rrole) if not testing: return self.index( REQUEST, message="Settings changed at %s" % time.ctime(time.time()) ) def update_permission(self, REQUEST, permission_id, roles=(), testing=None): prm = getAdapter(self.getContext(), IRolePermissionsManager) for ir in [r.getId() for r in self.roles()]: if ir in roles: prm.grantPermissionToRole(permission_id, ir) else: prm.unsetPermissionFromRole(permission_id, ir) if not testing: return self.index(REQUEST, message="Settings changed at %s" % time.ctime(time.time()) ) def update_role(self, REQUEST, role_id, permissions=(), testing=None): prm = getAdapter(self.getContext(), IRolePermissionsManager) for ip in [p.getId() for p in self.permissions()]: if ip in permissions: prm.grantPermissionToRole(ip, role_id) else: prm.unsetPermissionFromRole(ip, role_id) if not testing: return self.index(REQUEST, message="Settings changed at %s" % time.ctime(time.time()) ) class PermissionRoles: __implements__ = IPermission def __init__(self, permission, context, roles): self._permission = permission self._context = context self._roles = roles def getId(self): return self._permission.getId() def getTitle(self): return self._permission.getTitle() def getDescription(self): return self._permission.getDescription() def roles(self): prm = getAdapter(self._context, IRolePermissionsManager) proles = prm.getRolesForPermission(self._permission.getId()) proles = [role for role,setting in proles if setting==Allow] return [((role.getId() in proles) and '1' or None) for role in self._roles] def rolesInfo(self): prm = getAdapter(self._context, IRolePermissionsManager) proles = prm.getRolesForPermission(self._permission.getId()) proles = [role for role,setting in proles if setting==Allow] return [{'id': role.getId(), 'title': role.getTitle(), 'checked': ((role.getId() in proles) and '1' or None)} for role in self._roles] class RolePermissions: __implements__ = IRole def __init__(self, role, context, permissions): self._role = role self._context = context self._permissions = permissions def getId(self): return self._role.getId() def getTitle(self): return self._role.getTitle() def getDescription(self): return self._role.getDescription() def permissionsInfo(self): prm = getAdapter(self._context, IRolePermissionsManager) rperms = prm.getPermissionsForRole(self._role.getId()) rperms = [permission for permission,setting in rperms if setting==Allow] return [{'id': permission.getId(), 'title': permission.getTitle(), 'checked': ((permission.getId() in rperms) and '1' or None)} for permission in self._permissions] === Added File Zope3/lib/python/Zope/App/Security/Management/Settings.py === # Settings.py # # Copyright (c) 2001 Zope Coporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. """ Security setting constants """ class PermissionSetting(object): """PermissionSettings should be considered as immutable. They can be compared by identity. They are identified by their name. """ def __new__(cls, name, description=None): """Keep a dict of PermissionSetting instances, indexed by name. If the name already exists in the dict, return that instance rather than creating a new one. """ instances = cls.__dict__.get('__instances__') if instances is None: cls.__instances__ = instances = {} it = instances.get(name) if it is None: instances[name] = it = object.__new__(cls) it._init(name, description) return it def _init(self, name, description): self.__name = name self.__description = description def getDescription(self): return self.__description def getName(self): return self.__name def __str__(self): return "PermissionSetting: %s" % self.__name # register PermissionSettings to be symbolic constants by identity, # even when pickled and unpickled. import copy_reg copy_reg.constructor(PermissionSetting) copy_reg.pickle(PermissionSetting, PermissionSetting.getName, PermissionSetting) Allow = PermissionSetting('Allow', 'Explicit allow setting for permissions') Deny = PermissionSetting('Deny', 'Explicit deny setting for permissions') Unset = PermissionSetting('Unset', 'Unset constant that denotes no setting for permission and role') Assign = PermissionSetting('Assign', 'Explicit assign setting for roles') Remove = PermissionSetting('Remove', 'Explicit remove setting for roles') === Added File Zope3/lib/python/Zope/App/Security/Management/__init__.py === === Added File Zope3/lib/python/Zope/App/Security/Management/management.zcml === From casey@zope.com Tue Apr 9 17:36:45 2002 From: casey@zope.com (Casey Duncan) Date: Tue, 9 Apr 2002 12:36:45 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security/Management/tests - RolePermissionsManager.py:1.1.2.1 __init__.py:1.1.2.1 testGlobalPrincipalPermissions.py:1.1.2.1 testGlobalPrincipalRoles.py:1.1.2.1 testGlobalRolePermissions.py:1.1.2.1 testMementoPrincipalPermissions.py:1.1.2.1 testMementoPrincipalRoles.py:1.1.2.1 testMementoRolePermissions.py:1.1.2.1 testPrincipalPermissionsView.py:1.1.2.1 testPrincipalRolesView.py:1.1.2.1 testRolePermissionsView.py:1.1.2.1 testSettings.py:1.1.2.1 Message-ID: <200204091636.g39GajU12966@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Security/Management/tests In directory cvs.zope.org:/tmp/cvs-serv11768/Zope/App/Security/Management/tests Added Files: Tag: casey-security-reorg-branch RolePermissionsManager.py __init__.py testGlobalPrincipalPermissions.py testGlobalPrincipalRoles.py testGlobalRolePermissions.py testMementoPrincipalPermissions.py testMementoPrincipalRoles.py testMementoRolePermissions.py testPrincipalPermissionsView.py testPrincipalRolesView.py testRolePermissionsView.py testSettings.py Log Message: Mass checkin for security reorganization branch. I will retest this and merge upon BDFL approval... === Added File Zope3/lib/python/Zope/App/Security/Management/tests/RolePermissionsManager.py === ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ $Id: RolePermissionsManager.py,v 1.1.2.1 2002/04/09 16:36:43 caseman Exp $ """ from Zope.App.Security.Management.IRolePermissions \ import IRolePermissionsManager from Zope.App.Security.Management.Settings import Allow, Assign class RolePermissionsManager: __implements__ = IRolePermissionsManager def __init__(self, **rp): self._rp = rp # Implementation methods for interface # Zope.App.Security.IRolePermissionManager. def getRolesForPermission(self, permission): '''See interface IRolePermissionMap''' r=[] for role, permissions in self._rp.items(): if permission in permissions: r.append((role, Allow)) return r def getPermissionAcquired(self, permission): '''See interface IRolePermissionMap''' return 1 def getPermissionsForRole(self, role): '''See interface IRolePermissionMap''' return [(perm, Allow) for perm in self._rp[role]] def setPermissionAcquired(self, permission, flag): '''See interface IRolePermissionManager''' raise TypeError def unsetPermissionFromRole(self, permission, role): '''See interface IRolePermissionManager''' permissions = self._rp.get(role, ()) if permission in permissions: permissions.remove(permission) if not permissions: # XXX: this del removed by Steve and Casey # in order to get the PermissionsForRole # view unit tests to work correctly. # # Why is this del here? # # It doesn't seem to break anything to remove # it, like this! #del self._rp[role] pass def grantPermissionToRole(self, permission, role): '''See interface IRolePermissionManager''' if role in self._rp: if permission not in self._rp[role]: self._rp[role].append(permission) else: self._rp[role] = [permission] === Added File Zope3/lib/python/Zope/App/Security/Management/tests/__init__.py === === Added File Zope3/lib/python/Zope/App/Security/Management/tests/testGlobalPrincipalPermissions.py === # Copyright (c) 2001 Zope Coporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. """ $Id: testGlobalPrincipalPermissions.py,v 1.1.2.1 2002/04/09 16:36:43 caseman Exp $ """ import sys import unittest from Zope.App.Security.PermissionRegistry \ import permissionRegistry as permregistry from Zope.App.Security.PrincipalRegistry \ import principalRegistry as prinregistry from Zope.App.Security.Management.GlobalPrincipalPermissions \ import principalPermissionsManager as manager from Zope.App.Security.Management.Settings import Allow, Deny, Unset from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup class Test(CleanUp, unittest.TestCase): def _make_principal(self, id=None, title=None): p = prinregistry.definePrincipal( id or 'APrincipal', title or 'A Principal', login = id or 'APrincipal') return p.getId() def testUnboundPrincipalPermission(self): permission = permregistry.definePermission('APerm', 'title').getId() principal = self._make_principal() self.assertEqual(manager.getPrincipalsForPermission(permission), []) self.assertEqual(manager.getPermissionsForPrincipal(principal), []) def testPrincipalPermission(self): permission = permregistry.definePermission('APerm', 'title').getId() principal = self._make_principal() # check that an allow permission is saved correctly manager.grantPermissionToPrincipal(permission, principal) self.assertEqual(manager.getPrincipalsForPermission(permission), [(principal, Allow)]) self.assertEqual(manager.getPermissionsForPrincipal(principal), [(permission, Allow)]) # check that the allow permission is removed. manager.unsetPermissionForPrincipal(permission, principal) self.assertEqual(manager.getPrincipalsForPermission(permission), []) self.assertEqual(manager.getPermissionsForPrincipal(principal), []) # now put a deny in there, check it's set. manager.denyPermissionToPrincipal(permission, principal) self.assertEqual(manager.getPrincipalsForPermission(permission), [(principal, Deny)]) self.assertEqual(manager.getPermissionsForPrincipal(principal), [(permission, Deny)]) # test for deny followed by allow . The latter should override. manager.grantPermissionToPrincipal(permission, principal) self.assertEqual(manager.getPrincipalsForPermission(permission), [(principal, Allow)]) self.assertEqual(manager.getPermissionsForPrincipal(principal), [(permission, Allow)]) # check that allow followed by allow is just a single allow. manager.grantPermissionToPrincipal(permission, principal) self.assertEqual(manager.getPrincipalsForPermission(permission), [(principal, Allow)]) self.assertEqual(manager.getPermissionsForPrincipal(principal), [(permission, Allow)]) # check that two unsets in a row quietly ignores the second one. manager.unsetPermissionForPrincipal(permission, principal) manager.unsetPermissionForPrincipal(permission, principal) self.assertEqual(manager.getPrincipalsForPermission(permission), []) self.assertEqual(manager.getPermissionsForPrincipal(principal), []) # check the result of getSetting() when it's empty. self.assertEqual(manager.getSetting(permission, principal), Unset) # check the result of getSetting() when it's allowed. manager.grantPermissionToPrincipal(permission, principal) self.assertEqual(manager.getSetting(permission, principal), Allow) # check the result of getSetting() when it's denied. manager.denyPermissionToPrincipal(permission, principal) self.assertEqual(manager.getSetting(permission, principal), Deny) def testManyPermissionsOnePrincipal(self): perm1 = permregistry.definePermission('Perm One', 'title').getId() perm2 = permregistry.definePermission('Perm Two', 'title').getId() prin1 = self._make_principal() manager.grantPermissionToPrincipal(perm1, prin1) manager.grantPermissionToPrincipal(perm2, prin1) perms = manager.getPermissionsForPrincipal(prin1) self.assertEqual(len(perms), 2) self.failUnless((perm1,Allow) in perms) self.failUnless((perm2,Allow) in perms) manager.denyPermissionToPrincipal(perm2, prin1) perms = manager.getPermissionsForPrincipal(prin1) self.assertEqual(len(perms), 2) self.failUnless((perm1,Allow) in perms) self.failUnless((perm2,Deny) in perms) perms = manager.getPrincipalsAndPermissions() self.failUnless((perm1,prin1,Allow) in perms) self.failUnless((perm2,prin1,Deny) in perms) def testManyPrincipalsOnePermission(self): perm1 = permregistry.definePermission('Perm One', 'title').getId() prin1 = self._make_principal() prin2 = self._make_principal('Principal 2', 'Principal Two') manager.grantPermissionToPrincipal(perm1, prin1) manager.denyPermissionToPrincipal(perm1, prin2) principals = manager.getPrincipalsForPermission(perm1) self.assertEqual(len(principals), 2) self.failUnless((prin1,Allow) in principals) self.failUnless((prin2,Deny) in principals) def test_suite(): loader=unittest.TestLoader() return loader.loadTestsFromTestCase(Test) if __name__=='__main__': unittest.TextTestRunner().run(test_suite()) === Added File Zope3/lib/python/Zope/App/Security/Management/tests/testGlobalPrincipalRoles.py === # Copyright (c) 2001 Zope Coporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. """ $Id: testGlobalPrincipalRoles.py,v 1.1.2.1 2002/04/09 16:36:43 caseman Exp $ """ import sys import unittest from Zope.App.Security.RoleRegistry import roleRegistry as rregistry from Zope.App.Security.PrincipalRegistry import principalRegistry as pregistry from Zope.App.Security.Management.GlobalPrincipalRoles \ import principalRolesManager as manager from Zope.App.Security.Management.Settings import Assign, Remove from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup class Test(CleanUp, unittest.TestCase): def _make_principal(self, id=None, title=None): p = pregistry.definePrincipal( id or 'APrincipal', title or 'A Principal', login = id or 'APrincipal') return p.getId() def testUnboundPrincipalRole(self): role = rregistry.defineRole('ARole', 'A Role').getId() principal = self._make_principal() self.assertEqual(manager.getPrincipalsForRole(role), []) self.assertEqual(manager.getRolesForPrincipal(principal), []) def testPrincipalRoleAssign(self): role = rregistry.defineRole('ARole', 'A Role').getId() principal = self._make_principal() manager.assignRoleToPrincipal(role, principal) self.assertEqual(manager.getPrincipalsForRole(role), [(principal,Assign)]) self.assertEqual(manager.getRolesForPrincipal(principal), [(role,Assign)]) def testPrincipalRoleRemove(self): role = rregistry.defineRole('ARole', 'A Role').getId() principal = self._make_principal() manager.removeRoleFromPrincipal(role, principal) self.assertEqual(manager.getPrincipalsForRole(role), [(principal,Remove)]) self.assertEqual(manager.getRolesForPrincipal(principal), [(role,Remove)]) def testPrincipalRoleUnset(self): role = rregistry.defineRole('ARole', 'A Role').getId() principal = self._make_principal() manager.removeRoleFromPrincipal(role, principal) manager.unsetRoleForPrincipal(role, principal) self.assertEqual(manager.getPrincipalsForRole(role), []) self.assertEqual(manager.getRolesForPrincipal(principal), []) def testManyRolesOnePrincipal(self): role1 = rregistry.defineRole('Role One', 'Role #1').getId() role2 = rregistry.defineRole('Role Two', 'Role #2').getId() prin1 = self._make_principal() manager.assignRoleToPrincipal(role1, prin1) manager.assignRoleToPrincipal(role2, prin1) roles = manager.getRolesForPrincipal(prin1) self.assertEqual(len(roles), 2) self.failUnless((role1,Assign) in roles) self.failUnless((role2,Assign) in roles) def testManyPrincipalsOneRole(self): role1 = rregistry.defineRole('Role One', 'Role #1').getId() prin1 = self._make_principal() prin2 = self._make_principal('Principal 2', 'Principal Two') manager.assignRoleToPrincipal(role1, prin1) manager.assignRoleToPrincipal(role1, prin2) principals = manager.getPrincipalsForRole(role1) self.assertEqual(len(principals), 2) self.failUnless((prin1,Assign) in principals) self.failUnless((prin2,Assign) in principals) def testPrincipalsAndRoles(self): role1 = rregistry.defineRole('Role One', 'Role #1').getId() role2 = rregistry.defineRole('Role Two', 'Role #2').getId() prin1 = self._make_principal() prin2 = self._make_principal('Principal 2', 'Principal Two') manager.assignRoleToPrincipal(role1, prin1) manager.assignRoleToPrincipal(role1, prin2) manager.assignRoleToPrincipal(role2, prin1) principalsAndRoles = manager.getPrincipalsAndRoles() self.assertEqual(len(principalsAndRoles), 3) self.failUnless((role1,prin1,Assign) in principalsAndRoles) self.failUnless((role1,prin2,Assign) in principalsAndRoles) self.failUnless((role2,prin1,Assign) in principalsAndRoles) def test_suite(): loader=unittest.TestLoader() return loader.loadTestsFromTestCase(Test) if __name__=='__main__': unittest.TextTestRunner().run(test_suite()) === Added File Zope3/lib/python/Zope/App/Security/Management/tests/testGlobalRolePermissions.py === # Copyright (c) 2001 Zope Coporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. """ $Id: testGlobalRolePermissions.py,v 1.1.2.1 2002/04/09 16:36:43 caseman Exp $ """ import sys import unittest from Zope.App.Security.PermissionRegistry \ import permissionRegistry as pregistry from Zope.App.Security.RoleRegistry \ import roleRegistry as rregistry from Zope.App.Security.Management.GlobalRolePermissions \ import rolePermissionsManager as manager from Zope.App.Security.Management.Settings \ import Allow, Deny, Unset from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup class Test(CleanUp, unittest.TestCase): def testUnboundRolePermission(self): permission = pregistry.definePermission('APerm', 'aPerm title').getId() role = rregistry.defineRole('ARole', 'A Role').getId() self.assertEqual(manager.getRolesForPermission(permission), []) self.assertEqual(manager.getPermissionsForRole(role), []) def testRolePermission(self): permission = pregistry.definePermission('APerm', 'aPerm title').getId() role = rregistry.defineRole('ARole', 'A Role').getId() manager.grantPermissionToRole(permission, role) self.assertEqual(manager.getRolesForPermission(permission), [(role,Allow)]) self.assertEqual(manager.getPermissionsForRole(role), [(permission,Allow)]) def testManyPermissionsOneRole(self): perm1 = pregistry.definePermission('Perm One', 'P1').getId() perm2 = pregistry.definePermission('Perm Two', 'P2').getId() perm3 = pregistry.definePermission('Perm Three', 'P3').getId() role1 = rregistry.defineRole('Role One', 'Role #1').getId() perms = manager.getPermissionsForRole(role1) self.assertEqual(len(perms), 0) manager.grantPermissionToRole(perm1, role1) manager.grantPermissionToRole(perm2, role1) manager.grantPermissionToRole(perm2, role1) manager.denyPermissionToRole(perm3, role1) perms = manager.getPermissionsForRole(role1) self.assertEqual(len(perms), 3) self.failUnless((perm1,Allow) in perms) self.failUnless((perm2,Allow) in perms) self.failUnless((perm3,Deny) in perms) manager.unsetPermissionFromRole(perm1, role1) perms = manager.getPermissionsForRole(role1) self.assertEqual(len(perms), 2) self.failUnless((perm2,Allow) in perms) def testManyRolesOnePermission(self): perm1 = pregistry.definePermission('Perm One', 'title').getId() role1 = rregistry.defineRole('Role One', 'Role #1').getId() role2 = rregistry.defineRole('Role Two', 'Role #2').getId() roles = manager.getRolesForPermission(perm1) self.assertEqual(len(roles), 0) manager.grantPermissionToRole(perm1, role1) manager.grantPermissionToRole(perm1, role2) manager.grantPermissionToRole(perm1, role2) manager.denyPermissionToRole(perm1, role1) roles = manager.getRolesForPermission(perm1) self.assertEqual(len(roles), 2) self.failIf((role1,Allow) in roles) self.failUnless((role1,Deny) in roles) self.failUnless((role2,Allow) in roles) manager.unsetPermissionFromRole(perm1, role1) roles = manager.getRolesForPermission(perm1) self.assertEqual(len(roles), 1) self.failUnless((role2,Allow) in roles) def test_suite(): loader=unittest.TestLoader() return loader.loadTestsFromTestCase(Test) if __name__=='__main__': unittest.TextTestRunner().run(test_suite()) === Added File Zope3/lib/python/Zope/App/Security/Management/tests/testMementoPrincipalPermissions.py === # Copyright (c) 2001 Zope Coporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. """Test handler for MementoPrincipalPermissionsManager module.""" import sys import unittest from Zope.App.OFS.Memento.IAttributeMementoStorable \ import IAttributeMementoStorable from Zope.ComponentArchitecture import provideAdapter from Zope.App.OFS.Memento.IMementoBag import IMementoBag from Zope.App.OFS.Memento.AttributeMementoBag import AttributeMementoBag from Zope.App.Security.PermissionRegistry \ import permissionRegistry as permregistry from Zope.App.Security.PrincipalRegistry \ import principalRegistry as prinregistry from Zope.App.Security.Management.MementoPrincipalPermissions \ import MementoPrincipalPermissionsManager from Zope.App.Security.Management.Settings import Allow, Deny, Unset from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup class Manageable: __implements__ = IAttributeMementoStorable class Test(CleanUp, unittest.TestCase): def setUp(self): CleanUp.setUp(self) provideAdapter(IAttributeMementoStorable, IMementoBag, AttributeMementoBag) def _make_principal(self, id=None, title=None): p = prinregistry.definePrincipal( id or 'APrincipal', title or 'A Principal', login = id or 'APrincipal') return p.getId() def testUnboundPrincipalPermission(self): manager = MementoPrincipalPermissionsManager(Manageable()) permission = permregistry.definePermission('APerm', 'title') permission = permission.getId() principal = self._make_principal() self.assertEqual(manager.getPrincipalsForPermission(permission), []) self.assertEqual(manager.getPermissionsForPrincipal(principal), []) def testPrincipalPermission(self): manager = MementoPrincipalPermissionsManager(Manageable()) permission = permregistry.definePermission('APerm', 'title') permission = permission.getId() principal = self._make_principal() # check that an allow permission is saved correctly manager.grantPermissionToPrincipal(permission, principal) self.assertEqual(manager.getPrincipalsForPermission(permission), [(principal, Allow)]) self.assertEqual(manager.getPermissionsForPrincipal(principal), [(permission, Allow)]) # check that the allow permission is removed. manager.unsetPermissionForPrincipal(permission, principal) self.assertEqual(manager.getPrincipalsForPermission(permission), []) self.assertEqual(manager.getPermissionsForPrincipal(principal), []) # now put a deny in there, check it's set. manager.denyPermissionToPrincipal(permission, principal) self.assertEqual(manager.getPrincipalsForPermission(permission), [(principal, Deny)]) self.assertEqual(manager.getPermissionsForPrincipal(principal), [(permission, Deny)]) # test for deny followed by allow . The latter should override. manager.grantPermissionToPrincipal(permission, principal) self.assertEqual(manager.getPrincipalsForPermission(permission), [(principal, Allow)]) self.assertEqual(manager.getPermissionsForPrincipal(principal), [(permission, Allow)]) # check that allow followed by allow is just a single allow. manager.grantPermissionToPrincipal(permission, principal) self.assertEqual(manager.getPrincipalsForPermission(permission), [(principal, Allow)]) self.assertEqual(manager.getPermissionsForPrincipal(principal), [(permission, Allow)]) # check that two unsets in a row quietly ignores the second one. manager.unsetPermissionForPrincipal(permission, principal) manager.unsetPermissionForPrincipal(permission, principal) self.assertEqual(manager.getPrincipalsForPermission(permission), []) self.assertEqual(manager.getPermissionsForPrincipal(principal), []) # check the result of getSetting() when it's empty. self.assertEqual(manager.getSetting(permission, principal), Unset) # check the result of getSetting() when it's allowed. manager.grantPermissionToPrincipal(permission, principal) self.assertEqual(manager.getSetting(permission, principal), Allow) # check the result of getSetting() when it's denied. manager.denyPermissionToPrincipal(permission, principal) self.assertEqual(manager.getSetting(permission, principal), Deny) def testManyPermissionsOnePrincipal(self): manager = MementoPrincipalPermissionsManager(Manageable()) perm1 = permregistry.definePermission('Perm One', 'title').getId() perm2 = permregistry.definePermission('Perm Two', 'title').getId() prin1 = self._make_principal() manager.grantPermissionToPrincipal(perm1, prin1) manager.grantPermissionToPrincipal(perm2, prin1) perms = manager.getPermissionsForPrincipal(prin1) self.assertEqual(len(perms), 2) self.failUnless((perm1,Allow) in perms) self.failUnless((perm2,Allow) in perms) manager.denyPermissionToPrincipal(perm2, prin1) perms = manager.getPermissionsForPrincipal(prin1) self.assertEqual(len(perms), 2) self.failUnless((perm1,Allow) in perms) self.failUnless((perm2,Deny) in perms) def testManyPrincipalsOnePermission(self): manager = MementoPrincipalPermissionsManager(Manageable()) perm1 = permregistry.definePermission('Perm One', 'title').getId() prin1 = self._make_principal() prin2 = self._make_principal('Principal 2', 'Principal Two') manager.grantPermissionToPrincipal(perm1, prin1) manager.denyPermissionToPrincipal(perm1, prin2) principals = manager.getPrincipalsForPermission(perm1) self.assertEqual(len(principals), 2) self.failUnless((prin1,Allow) in principals) self.failUnless((prin2,Deny) in principals) def test_suite(): loader=unittest.TestLoader() return loader.loadTestsFromTestCase(Test) if __name__=='__main__': unittest.TextTestRunner().run(test_suite()) === Added File Zope3/lib/python/Zope/App/Security/Management/tests/testMementoPrincipalRoles.py === # Copyright (c) 2001 Zope Coporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. """Test handler for PrincipalRoleManager module.""" import sys import unittest from Zope.App.OFS.Memento.IAttributeMementoStorable \ import IAttributeMementoStorable from Zope.ComponentArchitecture import provideAdapter from Zope.App.OFS.Memento.IMementoBag import IMementoBag from Zope.App.OFS.Memento.AttributeMementoBag import AttributeMementoBag from Zope.App.Security.RoleRegistry import roleRegistry as rregistry from Zope.App.Security.PrincipalRegistry import principalRegistry as pregistry from Zope.App.Security.Management.MementoPrincipalRoles \ import MementoPrincipalRolesManager from Zope.App.Security.Management.Settings import Assign, Remove from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup class Manageable: __implements__ = IAttributeMementoStorable class Test(CleanUp, unittest.TestCase): def setUp(self): CleanUp.setUp(self) provideAdapter(IAttributeMementoStorable, IMementoBag, AttributeMementoBag) def _make_principal(self, id=None, title=None): p = pregistry.definePrincipal( id or 'APrincipal', title or 'A Principal', login = id or 'APrincipal') return p.getId() def testUnboundPrincipalRole(self): principalRoleManager = MementoPrincipalRolesManager(Manageable()) role = rregistry.defineRole('ARole', 'A Role').getId() principal = self._make_principal() self.assertEqual(principalRoleManager.getPrincipalsForRole(role), []) self.assertEqual(principalRoleManager.getRolesForPrincipal(principal), []) def testPrincipalRoleAssign(self): principalRoleManager = MementoPrincipalRolesManager(Manageable()) role = rregistry.defineRole('ARole', 'A Role').getId() principal = self._make_principal() principalRoleManager.assignRoleToPrincipal(role, principal) self.assertEqual(principalRoleManager.getPrincipalsForRole(role), [(principal,Assign)]) self.assertEqual(principalRoleManager.getRolesForPrincipal(principal), [(role,Assign)]) def testPrincipalRoleRemove(self): principalRoleManager = MementoPrincipalRolesManager(Manageable()) role = rregistry.defineRole('ARole', 'A Role').getId() principal = self._make_principal() principalRoleManager.removeRoleFromPrincipal(role, principal) self.assertEqual(principalRoleManager.getPrincipalsForRole(role), [(principal,Remove)]) self.assertEqual(principalRoleManager.getRolesForPrincipal(principal), [(role,Remove)]) def testPrincipalRoleUnset(self): principalRoleManager = MementoPrincipalRolesManager(Manageable()) role = rregistry.defineRole('ARole', 'A Role').getId() principal = self._make_principal() principalRoleManager.removeRoleFromPrincipal(role, principal) principalRoleManager.unsetRoleForPrincipal(role, principal) self.assertEqual(principalRoleManager.getPrincipalsForRole(role), []) self.assertEqual(principalRoleManager.getRolesForPrincipal(principal), []) def testManyRolesOnePrincipal(self): principalRoleManager = MementoPrincipalRolesManager(Manageable()) role1 = rregistry.defineRole('Role One', 'Role #1').getId() role2 = rregistry.defineRole('Role Two', 'Role #2').getId() prin1 = self._make_principal() principalRoleManager.assignRoleToPrincipal(role1, prin1) principalRoleManager.assignRoleToPrincipal(role2, prin1) roles = principalRoleManager.getRolesForPrincipal(prin1) self.assertEqual(len(roles), 2) self.failUnless((role1,Assign) in roles) self.failUnless((role2,Assign) in roles) def testManyPrincipalsOneRole(self): principalRoleManager = MementoPrincipalRolesManager(Manageable()) role1 = rregistry.defineRole('Role One', 'Role #1').getId() prin1 = self._make_principal() prin2 = self._make_principal('Principal 2', 'Principal Two') principalRoleManager.assignRoleToPrincipal(role1, prin1) principalRoleManager.assignRoleToPrincipal(role1, prin2) principals = principalRoleManager.getPrincipalsForRole(role1) self.assertEqual(len(principals), 2) self.failUnless((prin1,Assign) in principals) self.failUnless((prin2,Assign) in principals) def testPrincipalsAndRoles(self): principalRoleManager = MementoPrincipalRolesManager(Manageable()) principalsAndRoles = principalRoleManager.getPrincipalsAndRoles() self.assertEqual(len(principalsAndRoles), 0) role1 = rregistry.defineRole('Role One', 'Role #1').getId() role2 = rregistry.defineRole('Role Two', 'Role #2').getId() prin1 = self._make_principal() prin2 = self._make_principal('Principal 2', 'Principal Two') principalRoleManager.assignRoleToPrincipal(role1, prin1) principalRoleManager.assignRoleToPrincipal(role1, prin2) principalRoleManager.assignRoleToPrincipal(role2, prin1) principalsAndRoles = principalRoleManager.getPrincipalsAndRoles() self.assertEqual(len(principalsAndRoles), 3) self.failUnless((role1,prin1,Assign) in principalsAndRoles) self.failUnless((role1,prin2,Assign) in principalsAndRoles) self.failUnless((role2,prin1,Assign) in principalsAndRoles) def test_suite(): loader=unittest.TestLoader() return loader.loadTestsFromTestCase(Test) if __name__=='__main__': unittest.TextTestRunner().run(test_suite()) === Added File Zope3/lib/python/Zope/App/Security/Management/tests/testMementoRolePermissions.py === ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## from Zope.App.Security.Management.MementoRolePermissions \ import MementoRolePermissionsManager from Zope.App.OFS.Memento.IAttributeMementoStorable \ import IAttributeMementoStorable from Zope.App.OFS.Memento.IMementoBag import IMementoBag from Zope.App.OFS.Memento.AttributeMementoBag import AttributeMementoBag from Zope.ComponentArchitecture \ import defineService, provideService, provideAdapter from Zope.App.Security.IRoleService import IRoleService from Zope.App.Security.IPermissionService import IPermissionService from Zope.App.Security.RoleRegistry import roleRegistry from Zope.App.Security.PermissionRegistry import permissionRegistry from Zope.App.Security.Management.Settings import Allow, Deny from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup import unittest, sys class Manageable: __implements__ = IAttributeMementoStorable class Test(CleanUp, unittest.TestCase): def setUp(self): CleanUp.setUp(self) defineService('RoleService', IRoleService) defineService('PermissionService', IPermissionService) provideService('RoleService', roleRegistry) provideService('PermissionService', permissionRegistry) provideAdapter(IAttributeMementoStorable, IMementoBag, AttributeMementoBag) read = permissionRegistry.definePermission('read', 'Read Something') self.read = read.getId() write = permissionRegistry.definePermission('write', 'Write Something') self.write = write.getId() peon = roleRegistry.defineRole('peon', 'Poor Slob') self.peon = peon.getId() manager = roleRegistry.defineRole('manager', 'Supreme Being') self.manager = manager.getId() def testNormal(self): obj = Manageable() mgr = MementoRolePermissionsManager(obj) mgr.grantPermissionToRole(self.read,self.manager) mgr.grantPermissionToRole(self.write,self.manager) mgr.grantPermissionToRole(self.write,self.manager) mgr.grantPermissionToRole(self.read,self.peon) l = list(mgr.getPermissionsForRole(self.manager)) self.failUnless( (self.read, Allow) in l ) self.failUnless( (self.write, Allow) in l ) l = list(mgr.getPermissionsForRole(self.peon)) self.failUnless( [(self.read, Allow)] == l ) l = list(mgr.getRolesForPermission(self.read)) self.failUnless( (self.manager, Allow) in l ) self.failUnless( (self.peon, Allow) in l ) l = list(mgr.getRolesForPermission(self.write)) self.assertEqual(l, [ (self.manager, Allow) ] ) mgr.denyPermissionToRole(self.read, self.peon) l = list(mgr.getPermissionsForRole(self.peon)) self.assertEqual(l, [(self.read, Deny)] ) mgr.unsetPermissionFromRole(self.read, self.peon) l = list(mgr.getRolesForPermission(self.read)) self.assertEqual(l, [ (self.manager, Allow) ] ) def test_suite(): loader=unittest.TestLoader() return loader.loadTestsFromTestCase(Test) if __name__=='__main__': unittest.TextTestRunner().run(test_suite()) === Added File Zope3/lib/python/Zope/App/Security/Management/tests/testPrincipalPermissionsView.py === ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ $Id: testPrincipalPermissionsView.py,v 1.1.2.1 2002/04/09 16:36:44 caseman Exp $ """ import unittest from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup from Zope.ComponentArchitecture import defineService, provideService from Zope.ComponentArchitecture import provideAdapter from Zope.App.OFS.Memento.IAttributeMementoStorable \ import IAttributeMementoStorable from Zope.App.OFS.Memento.IMementoBag import IMementoBag from Zope.App.OFS.Memento.AttributeMementoBag import AttributeMementoBag from Zope.App.Security.IPermissionService import IPermissionService from Zope.App.Security.IAuthenticationService import IAuthenticationService from Zope.App.Security.Management.IPrincipalPermissions \ import IPrincipalPermissionsManager from Zope.App.Security.Management.Settings import Allow, Deny, Unset class DummyContext: __implements__ = IAttributeMementoStorable class DummyPermissionService: __implements__ = IPermissionService def __init__(self, perm_objs): perms = {} for perm_obj in perm_objs: perms[perm_obj.getId()] = perm_obj self.perms = perms def getPermission(self,pr_id): return self.perms[pr_id] def getPermissions(self): return self.perms.keys() class DummyAuthenticationService: __implements__ = IAuthenticationService def __init__(self, principals): pr = {} for principal in principals: pr[principal.getId()] = principal self.principals = pr def getPrincipal(self, principal_id): return self.principals[principal_id] class DummyAdapter: __implements__ = IPrincipalPermissionsManager def __init__(self, context): self._context = context if not hasattr(self._context,'principals'): self._context.principals = {} def grantPermissionToPrincipal(self, permission, principal): if not self._context.principals.has_key(principal): self._context.principals[principal]={} self._context.principals[principal][permission]=Allow def denyPermissionToPrincipal(self, permission, principal): if not self._context.principals.has_key(principal): self._context.principals[principal]={} self._context.principals[principal][permission]=Deny def unsetPermissionForPrincipal(self, permission, principal): if not self._context.principals.has_key(principal): return try: del self._context.principals[principal][permission] except KeyError: pass def getSetting(self, permission, principal): try: setting = self._context.principals[principal][permission] except KeyError: setting = Unset return setting def getPrincipalsForPermission(self, permission): ret = [] for principal, permissions in self._context.principals.items(): if permissions.has_key(permission): ret.append((principal, permissions[permission])) return ret def getPermissionsForPrincipal(self, principal): try: return self._context.principals[principal].items() except KeyError: return [] class DummyObject: def __init__(self, id, title): self._id = id self._title = title def getId(self): return self._id def getTitle(self): return self._title class Test(CleanUp, unittest.TestCase): def setUp(self): self._permissions = [] self._permissions.append(DummyObject('qux', 'Qux')) self._permissions.append(DummyObject('baz', 'Baz')) defineService('PermissionService', IPermissionService) provideService('PermissionService', DummyPermissionService( self._permissions)) defineService('AuthenticationService', IAuthenticationService) self._principals = [] self._principals.append(DummyObject('foo', 'Foo')) self._principals.append(DummyObject('bar', 'Bar')) provideService('AuthenticationService', DummyAuthenticationService(principals = self._principals)) provideAdapter(IAttributeMementoStorable, IPrincipalPermissionsManager, DummyAdapter) provideAdapter(IAttributeMementoStorable, IMementoBag, AttributeMementoBag) def _makeOne(self): from Zope.App.Security.Management.PrincipalPermissionsView \ import PrincipalPermissionsView return PrincipalPermissionsView(DummyContext()) def testGrantPermissions(self): view = self._makeOne() allowed_perms = view.getPermissionsForPrincipal( self._principals[0].getId(), 'Allow') denied_perms = view.getPermissionsForPrincipal( self._principals[0].getId(), 'Deny') self.assertEqual(len(allowed_perms), 0, 'List not empty') self.assertEqual(len(denied_perms), 0, 'List not empty') view.grantPermissions(self._principals[0].getId(), [self._permissions[0].getId()]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[0].getId(),'Allow'), [self._permissions[0]]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[0].getId(),'Deny'), []) view.grantPermissions(self._principals[0].getId(), [self._permissions[1].getId()]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[0].getId(),'Allow').sort(), self._permissions.sort()) self.assertEqual(view.getPermissionsForPrincipal( self._principals[0].getId(),'Deny'), []) view.grantPermissions(self._principals[1].getId(), [self._permissions[0].getId()]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[1].getId(),'Allow'), [self._permissions[0]]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[1].getId(),'Deny'), []) view.grantPermissions(self._principals[1].getId(), [self._permissions[1].getId()]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[1].getId(),'Allow').sort(), self._permissions.sort()) self.assertEqual(view.getPermissionsForPrincipal( self._principals[1].getId(),'Deny'), []) def testDenyPermissions(self): view = self._makeOne() allowed_perms = view.getPermissionsForPrincipal( self._principals[0].getId(), 'Allow') denied_perms = view.getPermissionsForPrincipal( self._principals[0].getId(), 'Deny') self.assertEqual(len(allowed_perms), 0, 'List not empty') self.assertEqual(len(denied_perms), 0, 'List not empty') view.denyPermissions(self._principals[0].getId(), [self._permissions[0].getId()]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[0].getId(),'Deny'), [self._permissions[0]]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[0].getId(),'Allow'), []) view.denyPermissions(self._principals[0].getId(), [self._permissions[1].getId()]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[0].getId(),'Deny').sort(), self._permissions.sort()) self.assertEqual(view.getPermissionsForPrincipal( self._principals[0].getId(),'Allow'), []) view.denyPermissions(self._principals[1].getId(), [ self._permissions[0].getId()]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[1].getId(),'Deny'), [self._permissions[0]]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[1].getId(),'Allow'), []) view.denyPermissions(self._principals[1].getId(), [self._permissions[1].getId()]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[1].getId(),'Deny').sort(), self._permissions.sort()) self.assertEqual(view.getPermissionsForPrincipal( self._principals[1].getId(),'Allow'), []) def testAllowDenyPermissions(self): view = self._makeOne() allowed_perms = view.getPermissionsForPrincipal( self._principals[0].getId(), 'Allow') denied_perms = view.getPermissionsForPrincipal( self._principals[0].getId(), 'Deny') self.assertEqual(len(allowed_perms), 0, 'List not empty') self.assertEqual(len(denied_perms), 0, 'List not empty') view.grantPermissions(self._principals[0].getId(), [self._permissions[0].getId()]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[0].getId(),'Allow'), [self._permissions[0]]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[0].getId(),'Deny'), []) allowed_perms = view.getPermissionsForPrincipal( self._principals[0].getId(), 'Allow') self.assertEqual(len(allowed_perms), 1, 'List has wrong length') # Now change it to deny view.denyPermissions(self._principals[0].getId(), [self._permissions[0].getId()]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[0].getId(),'Deny'), [self._permissions[0]]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[0].getId(),'Allow'), []) view.grantPermissions(self._principals[0].getId(), [self._permissions[1].getId()]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[0].getId(),'Deny'), [self._permissions[0]]) self.assertEqual(view.getPermissionsForPrincipal( self._principals[0].getId(),'Allow'), [self._permissions[1]]) def testUnsetPermissions(self): view = self._makeOne() view.grantPermissions(self._principals[0].getId(), [self._permissions[0].getId()]) allowed_perms = view.getPermissionsForPrincipal( self._principals[0].getId(), 'Allow') self.assertEqual(len(allowed_perms), 1, 'List has wrong length') view.unsetPermissions(self._principals[0].getId(), [self._permissions[0].getId()]) allowed_perms = view.getPermissionsForPrincipal( self._principals[0].getId(), 'Allow') self.assertEqual(len(allowed_perms), 0, 'Permission not unset') # Deleting mutiple in one step view.grantPermissions(self._principals[0].getId(), [self._permissions[0].getId(), self._permissions[1].getId()]) allowed_perms = view.getPermissionsForPrincipal( self._principals[0].getId(), 'Allow') self.assertEqual(len(allowed_perms), 2, 'List has wrong length') view.unsetPermissions(self._principals[0].getId(), [self._permissions[0].getId(), self._permissions[1].getId()]) allowed_perms = view.getPermissionsForPrincipal( self._principals[0].getId(), 'Allow') self.assertEqual(len(allowed_perms), 0, 'Some permissions not unset') # Deleting in a row view.grantPermissions(self._principals[0].getId(), [self._permissions[0].getId(), self._permissions[1].getId()]) allowed_perms = view.getPermissionsForPrincipal( self._principals[0].getId(), 'Allow') self.assertEqual(len(allowed_perms), 2, 'List has wrong length') view.unsetPermissions(self._principals[0].getId(), [self._permissions[0].getId()]) allowed_perms = view.getPermissionsForPrincipal( self._principals[0].getId(), 'Allow') self.assertEqual(len(allowed_perms), 1, 'Some permissions not unset') view.unsetPermissions(self._principals[0].getId(), [self._permissions[1].getId()]) allowed_perms = view.getPermissionsForPrincipal( self._principals[0].getId(), 'Allow') self.assertEqual(len(allowed_perms), 0, 'Not all permissions unset') # Ask for an other way of getting the unset permisssions unset_perms = view.getUnsetPermissionsForPrincipal( self._principals[0].getId()) self.assertEqual(len(unset_perms), 2, 'Not all permissions unset') def test_suite(): loader=unittest.TestLoader() return loader.loadTestsFromTestCase(Test) if __name__=='__main__': unittest.TextTestRunner().run(test_suite()) === Added File Zope3/lib/python/Zope/App/Security/Management/tests/testPrincipalRolesView.py === ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ $Id: testPrincipalRolesView.py,v 1.1.2.1 2002/04/09 16:36:44 caseman Exp $ """ import unittest from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup from Zope.ComponentArchitecture import defineService, provideService from Zope.App.Security.IRoleService import IRoleService from Zope.App.Security.IAuthenticationService import IAuthenticationService from Zope.App.Security.Management.IPrincipalRoles \ import IPrincipalRolesManager class DummyManager: __implements__ = IPrincipalRolesManager def getSetting(self, role, principal): return '%r:%r' % (role, principal) class DummyRoleService: __implements__ = IRoleService def __init__( self, roles ): self._roles = roles def getRoles( self ): return self._roles class DummyObject: def __init__( self, id, title ): self._id = id self._title = title def getId( self ): return self._id def getTitle( self ): return self._title class DummyAuthenticationService: __implements__ = IAuthenticationService def __init__( self, principals ): self._principals = principals def getPrincipals( self ): return self._principals class Test(CleanUp, unittest.TestCase ): def setUp(self): self._roles = [] self._roles.append( DummyObject( 'qux', 'Qux' ) ) self._roles.append( DummyObject( 'baz', 'Baz' ) ) defineService( 'RoleService', IRoleService ) provideService( 'RoleService' , DummyRoleService( roles = self._roles ) ) defineService( 'AuthenticationService', IAuthenticationService ) self._principals = [] self._principals.append( DummyObject( 'foo', 'Foo' ) ) self._principals.append( DummyObject( 'bar', 'Bar' ) ) provideService( 'AuthenticationService', DummyAuthenticationService( principals = self._principals ) ) def _makeOne( self ): from Zope.App.Security.Management.PrincipalRolesView \ import PrincipalRolesView return PrincipalRolesView( DummyManager() ) def testRoles(self): view = self._makeOne() roles = list(view.getAllRoles()) self.assertEqual( len( roles ), 2 ) ids = map( lambda x: x.getId(), self._roles ) titles = map( lambda x: x.getTitle(), self._roles ) for role in roles: self.failUnless( role.getId() in ids ) self.failUnless( role.getTitle() in titles ) def testPrincipals(self): view = self._makeOne() principals = list(view.getAllPrincipals()) self.assertEqual( len( principals ), 2 ) ids = map( lambda x: x.getId(), self._principals ) titles = map( lambda x: x.getTitle(), self._principals ) for principal in principals: self.failUnless( principal.getId() in ids ) self.failUnless( principal.getTitle() in titles ) def testPrincipalRoleGrid(self): view = self._makeOne() grid = view.createGrid() p_ids = [p.getId() for p in view.getAllPrincipals()] r_ids = [r.getId() for r in view.getAllRoles()] self.failUnless( grid.listAvailableValues()) for id in [p.getId() for p in grid.principals()]: self.failUnless(id in p_ids) for id in [r.getId() for r in grid.roles()]: self.failUnless(id in r_ids) map = DummyManager() grid_entries = [(r, p, map.getSetting(r, p)) for r in grid.roles() for p in grid.principals()] for r, p, setting in grid_entries: self.assertEquals(setting, grid.getValue(r, p)) def test_suite(): loader=unittest.TestLoader() return loader.loadTestsFromTestCase(Test) if __name__=='__main__': unittest.TextTestRunner().run(test_suite()) === Added File Zope3/lib/python/Zope/App/Security/Management/tests/testRolePermissionsView.py === ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## import unittest, sys from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup from Zope.ComponentArchitecture import defineService, provideService from Zope.App.Security.IRoleService import IRoleService from Zope.App.Security.tests.RoleService import RoleService from Zope.App.Security.tests.PermissionService import PermissionService from RolePermissionsManager import RolePermissionsManager from Zope.App.Security.Management.RolePermissionsView import RolePermissionsView from Zope.App.Security.IPermissionService import IPermissionService class Test(CleanUp, unittest.TestCase): def setUp(self): defineService('RoleService', IRoleService) provideService('RoleService', RoleService( manager='Manager', member='Member')) defineService('PermissionService', IPermissionService) provideService('PermissionService', PermissionService( read='Read', write='Write')) self.view = RolePermissionsView(RolePermissionsManager()) def testRoles(self): roles = list(self.view.roles()) ids = ['manager', 'member'] titles = ['Manager', 'Member'] for role in roles: i=ids.index(role.getId()) self.failIf(i < 0) self.assertEqual(role.getTitle(), titles[i]) del ids[i] del titles[i] def testPermisssions(self): permissions = list(self.view.permissions()) ids = ['read', 'write'] titles = ['Read', 'Write'] for permission in permissions: i=ids.index(permission.getId()) self.failIf(i < 0) self.assertEqual(permission.getTitle(), titles[i]) del ids[i] del titles[i] def testGrant(self): roles = self.view.roles() permissions = self.view.permissions() self.view.action({ 'p0': 'read', 'p1': 'write', 'r0': 'manager', 'r1': 'member', 'p0r0': '1', 'p0r1': '1', 'p1r0': '1', }, testing=1) permissionRoles = self.view.permissionRoles() for ip in range(len(permissionRoles)): permissionRole = permissionRoles[ip] rset = permissionRole.roles() for ir in range(len(rset)): setting = rset[ir] if setting is None: self.failIf( roles[ir].getId() == 'manager' or permissions[ip].getId() == 'read' ) else: self.failUnless( roles[ir].getId() == 'manager' or permissions[ip].getId() == 'read' ) self.view.action({ 'p0': 'read', 'p1': 'write', 'r0': 'manager', 'r1': 'member', 'p0r0': '1', }, testing=1) permissionRoles = self.view.permissionRoles() for ip in range(len(permissionRoles)): permissionRole = permissionRoles[ip] rset = permissionRole.roles() for ir in range(len(rset)): setting = rset[ir] if setting is None: self.failIf( roles[ir].getId() == 'manager' and permissions[ip].getId() == 'read' ) else: self.failUnless( roles[ir].getId() == 'manager' and permissions[ip].getId() == 'read' ) self.view.update_permission(REQUEST=None, permission_id='write', roles=['member'], testing=1) permission = self.view.permissionForID('write') self.assertEquals( [r['id'] for r in permission.rolesInfo() if r['checked']], ['member']) self.view.update_permission(REQUEST=None, permission_id='write', # roles=[], roles attr omitted testing=1) permission = self.view.permissionForID('write') self.assertEquals( [r['id'] for r in permission.rolesInfo() if r['checked']], []) self.view.update_permission(REQUEST=None, permission_id='write', roles=['manager','member'], testing=1) permission = self.view.permissionForID('write') result = [r['id'] for r in permission.rolesInfo() if r['checked']] what_result_should_be = ['manager','member'] result.sort() what_result_should_be.sort() self.assertEquals( result, what_result_should_be ) self.view.update_role(REQUEST=None, role_id='member', permissions=['write','read'], testing=1) role = self.view.roleForID('member') result = [r['id'] for r in role.permissionsInfo() if r['checked']] what_result_should_be = ['write','read'] result.sort() what_result_should_be.sort() self.assertEquals( result, what_result_should_be ) self.view.update_role(REQUEST=None, role_id='member', # omitted attribute permissions, testing=1) role = self.view.roleForID('member') result = [r['id'] for r in role.permissionsInfo() if r['checked']] what_result_should_be = [] result.sort() what_result_should_be.sort() self.assertEquals( result, what_result_should_be ) def test_suite(): loader=unittest.TestLoader() return loader.loadTestsFromTestCase(Test) if __name__=='__main__': unittest.TextTestRunner().run(test_suite()) === Added File Zope3/lib/python/Zope/App/Security/Management/tests/testSettings.py === ############################################################################## # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. ############################################################################## import unittest, sys from Zope.App.Security.Management.Settings import Allow from cPickle import Pickler, Unpickler from StringIO import StringIO class Test(unittest.TestCase): def testPickleUnpickle(self): s = StringIO() p = Pickler(s) p.dump(Allow) s.seek(0) u = Unpickler(s) newAllow = u.load() self.failUnless(newAllow is Allow) def test_suite(): loader=unittest.TestLoader() return loader.loadTestsFromTestCase(Test) if __name__=='__main__': unittest.TextTestRunner().run(test_suite()) From casey@zope.com Tue Apr 9 17:37:13 2002 From: casey@zope.com (Casey Duncan) Date: Tue, 9 Apr 2002 12:37:13 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Memento - IMementoStorable.py:1.1.2.1 AttributeMementoBag.py:1.1.2.4.2.1 IAttributeMementoStorable.py:1.1.2.2.2.1 memento.zcml:1.1.2.1.2.1 Message-ID: <200204091637.g39GbDn13058@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Memento In directory cvs.zope.org:/tmp/cvs-serv11768/Zope/App/OFS/Memento Modified Files: Tag: casey-security-reorg-branch AttributeMementoBag.py IAttributeMementoStorable.py memento.zcml Added Files: Tag: casey-security-reorg-branch IMementoStorable.py Log Message: Mass checkin for security reorganization branch. I will retest this and merge upon BDFL approval... === Added File Zope3/lib/python/Zope/App/OFS/Memento/IMementoStorable.py === ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ $Id: IMementoStorable.py,v 1.1.2.1 2002/04/09 16:36:43 caseman Exp $ """ from Interface import Interface from Interface.Attribute import Attribute class IMementoStorable(Interface): """ Marker interfaces for objects that support memento storage. Classes should not implement this interface directly. Instead they should implement a derived interface that details how the memento is to be stored, such as IAttributeMementoStorable. """ === Zope3/lib/python/Zope/App/OFS/Memento/AttributeMementoBag.py 1.1.2.4 => 1.1.2.4.2.1 === def __init__(self,obj): - if not hasattr(obj,'__memobag__'): obj.__memobag__ = OOBTree() self.obj = obj + + def __getitem__(self, key): + memobag = getattr(self.obj, '__memobag__', {}) + return memobag[key] + + def get(self, key, default=None): + try: + return self.obj.__memobag__.get(key, default) + except AttributeError: + return default def __getattr__(self,attr): - return getattr(self.obj.__memobag__,attr) + try: + return getattr(self.obj.__memobag__,attr) + except AttributeError: + if not hasattr(self.obj, '__memobag__'): + memobag = self.obj.__memobag__ = OOBTree() + return getattr(memobag, attr) + raise + === Zope3/lib/python/Zope/App/OFS/Memento/IAttributeMementoStorable.py 1.1.2.2 => 1.1.2.2.2.1 === $Id$ """ -from Interface import Interface +from IMementoStorable import IMementoStorable from Interface.Attribute import Attribute -class IAttributeMementoStorable(Interface): +class IAttributeMementoStorable(IMementoStorable): """ Marker interfaces giving permission for an IMementoBag adapter to store data in an an attribute named __memobag__. === Zope3/lib/python/Zope/App/OFS/Memento/memento.zcml 1.1.2.1 => 1.1.2.1.2.1 === > + + provides="Zope.App.OFS.Memento.IMementoBag." /> From casey@zope.com Tue Apr 9 17:37:14 2002 From: casey@zope.com (Casey Duncan) Date: Tue, 9 Apr 2002 12:37:14 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security - ZopeSecurityPolicy.py:1.1.2.22.4.1 metaConfigure.py:1.1.2.24.2.1 security.zcml:1.1.2.3.2.1 AttributePrincipalPermissionManager.py:NONE AttributePrincipalRoleManager.py:NONE AttributeRolePermissionManager.py:NONE IPrincipalPermissionManager.py:NONE IPrincipalPermissionMap.py:NONE IPrincipalRoleManager.py:NONE IPrincipalRoleMap.py:NONE IRolePermissionManager.py:NONE IRolePermissionMap.py:NONE PrincipalPermissionManager.py:NONE PrincipalPermissionView.py:NONE PrincipalRoleManager.py:NONE PrincipalRoleView.py:NONE RolePermissionManager.py:NONE RolePermissionView.py:NONE Settings.py:NONE Message-ID: <200204091637.g39GbEH13063@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Security In directory cvs.zope.org:/tmp/cvs-serv11768/Zope/App/Security Modified Files: Tag: casey-security-reorg-branch ZopeSecurityPolicy.py metaConfigure.py security.zcml Removed Files: Tag: casey-security-reorg-branch AttributePrincipalPermissionManager.py AttributePrincipalRoleManager.py AttributeRolePermissionManager.py IPrincipalPermissionManager.py IPrincipalPermissionMap.py IPrincipalRoleManager.py IPrincipalRoleMap.py IRolePermissionManager.py IRolePermissionMap.py PrincipalPermissionManager.py PrincipalPermissionView.py PrincipalRoleManager.py PrincipalRoleView.py RolePermissionManager.py RolePermissionView.py Settings.py Log Message: Mass checkin for security reorganization branch. I will retest this and merge upon BDFL approval... === Zope3/lib/python/Zope/App/Security/ZopeSecurityPolicy.py 1.1.2.22 => 1.1.2.22.4.1 === from Zope.Exceptions import Unauthorized, Forbidden -from Zope.App.Security.IRolePermissionManager import IRolePermissionManager -from Zope.App.Security.IPrincipalPermissionManager \ - import IPrincipalPermissionManager -from Zope.App.Security.IPrincipalRoleManager \ - import IPrincipalRoleManager -from Zope.App.Security.IRolePermissionManager import IRolePermissionManager +from Zope.App.Security.Management.IRolePermissions \ + import IRolePermissionsManager +from Zope.App.Security.Management.IPrincipalPermissions \ + import IPrincipalPermissionsManager +from Zope.App.Security.Management.IPrincipalRoles \ + import IPrincipalRolesManager +from Zope.App.Security.Management.IRolePermissions \ + import IRolePermissionsManager from Zope.App.Security.PermissionRegistry import permissionRegistry from Zope.App.Security.PrincipalRegistry import principalRegistry from Zope.App.Security.RoleRegistry import roleRegistry -from Zope.App.Security.PrincipalPermissionManager \ - import principalPermissionManager -from Zope.App.Security.RolePermissionManager import rolePermissionManager -from Zope.App.Security.PrincipalRoleManager import principalRoleManager -from Zope.App.Security.Settings import Allow, Deny, Assign, Remove, Unset +from Zope.App.Security.Management.GlobalPrincipalPermissions \ + import principalPermissionsManager +from Zope.App.Security.Management.GlobalRolePermissions \ + import rolePermissionsManager +from Zope.App.Security.Management.GlobalPrincipalRoles \ + import principalRolesManager +from Zope.App.Security.Management.Settings \ + import Allow, Deny, Assign, Remove, Unset from types import StringTypes, ListType, IntType, MethodType, NoneType @@ -43,9 +48,9 @@ from Zope.ContextWrapper import getbaseobject getPermissionsForPrincipal = \ - principalPermissionManager.getPermissionsForPrincipal -getPermissionsForRole = rolePermissionManager.getPermissionsForRole -getRolesForPrincipal = principalRoleManager.getRolesForPrincipal + principalPermissionsManager.getPermissionsForPrincipal +getPermissionsForRole = rolePermissionsManager.getPermissionsForRole +getRolesForPrincipal = principalRolesManager.getRolesForPrincipal class ZopeSecurityPolicy: @@ -128,7 +133,7 @@ # Check the placeful principal permissions and aggregate the # Roles in this context for c in ContainmentIterator(object): - ppm = getAdapter(c, IPrincipalPermissionManager, None) + ppm = getAdapter(c, IPrincipalPermissionsManager, None) if ppm is not None: for principal in principals.keys(): setting = ppm.getSetting(permission, principal) @@ -137,7 +142,7 @@ elif setting is Allow: return 1 # Explicit allow on principal - prm = getAdapter(c, IPrincipalRoleManager, None) + prm = getAdapter(c, IPrincipalRolesManager, None) if prm is not None: for principal in principals.keys(): for role, setting in prm.getRolesForPrincipal(principal): @@ -147,7 +152,7 @@ assigned_roles[role] = 1 # now check the global principal permissions - getSetting = principalPermissionManager.getSetting + getSetting = principalPermissionsManager.getSetting for principal in principals.keys(): setting = getSetting(permission, principal) if setting is Allow: @@ -156,7 +161,7 @@ return 0 # Explicit deny on global principal # aggregate global roles - global_roles = principalRoleManager.getRolesForPrincipal(principal) + global_roles = principalRolesManager.getRolesForPrincipal(principal) for principal in principals.keys(): for role, setting in global_roles: if not roles.has_key(role): @@ -166,7 +171,7 @@ # Check the placeful role permissions, checking anonymous first for c in ContainmentIterator(object): - rpm = getAdapter(c, IRolePermissionManager, None) + rpm = getAdapter(c, IRolePermissionsManager, None) if rpm is not None: for role in ['Anonymous'] + assigned_roles.keys(): setting = rpm.getSetting(permission, role) @@ -178,7 +183,7 @@ return 1 # Allow on placeful role permission # Last, check if there are any global role settings - getSetting = rolePermissionManager.getSetting + getSetting = rolePermissionsManager.getSetting for principal in principals.keys(): for role, role_setting in [('Anonymous', Assign)] + global_roles: if role_setting is Assign: === Zope3/lib/python/Zope/App/Security/metaConfigure.py 1.1.2.24 => 1.1.2.24.2.1 === from SecurityManager import setSecurityPolicy from PrincipalRegistry import principalRegistry -from RolePermissionManager import rolePermissionManager as role_perm_mgr -from PrincipalPermissionManager import principalPermissionManager \ - as principal_perm_mgr -from PrincipalRoleManager import principalRoleManager as principal_role_mgr +from Management.GlobalRolePermissions \ + import rolePermissionsManager as role_perm_mgr +from Management.GlobalPrincipalPermissions \ + import principalPermissionsManager as principal_perm_mgr +from Management.GlobalPrincipalRoles \ + import principalRolesManager as principal_role_mgr from Zope.Configuration.Action import Action def defaultPolicy(_context, name): === Zope3/lib/python/Zope/App/Security/security.zcml 1.1.2.3 => 1.1.2.3.2.1 === xmlns:browser='http://namespaces.zope.org/browser' > + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + === Removed File Zope3/lib/python/Zope/App/Security/AttributePrincipalPermissionManager.py === === Removed File Zope3/lib/python/Zope/App/Security/AttributePrincipalRoleManager.py === === Removed File Zope3/lib/python/Zope/App/Security/AttributeRolePermissionManager.py === === Removed File Zope3/lib/python/Zope/App/Security/IPrincipalPermissionManager.py === === Removed File Zope3/lib/python/Zope/App/Security/IPrincipalPermissionMap.py === === Removed File Zope3/lib/python/Zope/App/Security/IPrincipalRoleManager.py === === Removed File Zope3/lib/python/Zope/App/Security/IPrincipalRoleMap.py === === Removed File Zope3/lib/python/Zope/App/Security/IRolePermissionManager.py === === Removed File Zope3/lib/python/Zope/App/Security/IRolePermissionMap.py === === Removed File Zope3/lib/python/Zope/App/Security/PrincipalPermissionManager.py === === Removed File Zope3/lib/python/Zope/App/Security/PrincipalPermissionView.py === === Removed File Zope3/lib/python/Zope/App/Security/PrincipalRoleManager.py === === Removed File Zope3/lib/python/Zope/App/Security/PrincipalRoleView.py === === Removed File Zope3/lib/python/Zope/App/Security/RolePermissionManager.py === === Removed File Zope3/lib/python/Zope/App/Security/RolePermissionView.py === === Removed File Zope3/lib/python/Zope/App/Security/Settings.py === From casey@zope.com Tue Apr 9 17:37:15 2002 From: casey@zope.com (Casey Duncan) Date: Tue, 9 Apr 2002 12:37:15 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security/tests - testProtectClass.py:1.1.2.10.6.1 testSecurityDirectives.py:1.1.2.13.6.1 testZSP.py:1.1.2.11.2.1 RolePermissionManager.py:NONE testAttributePrincipalPermissionManager.py:NONE testAttributePrincipalRoleManager.py:NONE testAttributeRolePermissionManager.py:NONE testPrincipalPermissionManager.py:NONE testPrincipalPermissionView.py:NONE testPrincipalRoleManager.py:NONE testPrincipalRoleView.py:NONE testRolePermissionManager.py:NONE testRolePermissionView.py:NONE testSettings.py:NONE Message-ID: <200204091637.g39GbFF13068@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Security/tests In directory cvs.zope.org:/tmp/cvs-serv11768/Zope/App/Security/tests Modified Files: Tag: casey-security-reorg-branch testProtectClass.py testSecurityDirectives.py testZSP.py Removed Files: Tag: casey-security-reorg-branch RolePermissionManager.py testAttributePrincipalPermissionManager.py testAttributePrincipalRoleManager.py testAttributeRolePermissionManager.py testPrincipalPermissionManager.py testPrincipalPermissionView.py testPrincipalRoleManager.py testPrincipalRoleView.py testRolePermissionManager.py testRolePermissionView.py testSettings.py Log Message: Mass checkin for security reorganization branch. I will retest this and merge upon BDFL approval... === Zope3/lib/python/Zope/App/Security/tests/testProtectClass.py 1.1.2.10 => 1.1.2.10.6.1 === def defineDirectives(): xmlconfig(StringIO(""" - + 1.1.2.13.6.1 === from Zope.App.Security.PrincipalRegistry import principalRegistry from Zope.App.Security.PermissionRegistry \ - import permissionRegistry as pregistry + import permissionRegistry as pregistry from Zope.App.Security.RoleRegistry import roleRegistry as rregistry -from Zope.App.Security.RolePermissionManager \ - import rolePermissionManager as role_perm_mgr -from Zope.App.Security.PrincipalPermissionManager \ - import principalPermissionManager as principal_perm_mgr -from Zope.App.Security.PrincipalRoleManager \ - import principalRoleManager as principal_role_mgr -from Zope.App.Security.Settings import Allow, Deny, Unset, Remove, Assign +from Zope.App.Security.Management.GlobalRolePermissions \ + import rolePermissionsManager as role_perm_mgr +from Zope.App.Security.Management.GlobalPrincipalPermissions \ + import principalPermissionsManager as principal_perm_mgr +from Zope.App.Security.Management.GlobalPrincipalRoles \ + import principalRolesManager as principal_role_mgr +from Zope.App.Security.Management.Settings import Allow, Deny, Unset, Remove, Assign def configfile(s): return StringIO(""" 1.1.2.11.2.1 === from Zope.ContextWrapper import Wrapper from Zope.ComponentArchitecture import provideAdapter -from Zope.App.Security.IRolePermissionManager import IRolePermissionManager +from Zope.App.Security.Management.IRolePermissions \ + import IRolePermissionsManager from Zope.App.Security.PermissionRegistry import permissionRegistry from Zope.App.Security.PrincipalRegistry import principalRegistry from Zope.App.Security.RoleRegistry import roleRegistry -from Zope.App.Security.PrincipalPermissionManager \ - import principalPermissionManager -from Zope.App.Security.RolePermissionManager import rolePermissionManager -from Zope.App.Security.PrincipalRoleManager import principalRoleManager -from Zope.App.Security.AttributePrincipalPermissionManager \ - import AttributePrincipalPermissionManager -from Zope.App.Security.PrincipalPermissionManager \ - import PrincipalPermissionManager -from Zope.App.Security.IPrincipalPermissionManager \ - import IPrincipalPermissionManager -from Zope.App.Security.AttributePrincipalRoleManager \ - import AttributePrincipalRoleManager -from Zope.App.Security.PrincipalRoleManager \ - import PrincipalRoleManager -from Zope.App.Security.AttributeRolePermissionManager \ - import AttributeRolePermissionManager -from Zope.App.Security.IPrincipalRoleManager import IPrincipalRoleManager +from Zope.App.Security.Management.GlobalPrincipalPermissions \ + import principalPermissionsManager +from Zope.App.Security.Management.GlobalRolePermissions \ + import rolePermissionsManager +from Zope.App.Security.Management.GlobalPrincipalRoles \ + import principalRolesManager +from Zope.App.Security.Management.MementoPrincipalPermissions \ + import MementoPrincipalPermissionsManager +from Zope.App.Security.Management.GlobalPrincipalPermissions \ + import principalPermissionsManager +from Zope.App.Security.Management.IPrincipalPermissions \ + import IPrincipalPermissionsManager +from Zope.App.Security.Management.MementoPrincipalRoles \ + import MementoPrincipalRolesManager +from Zope.App.Security.Management.MementoRolePermissions \ + import MementoRolePermissionsManager +from Zope.App.Security.Management.IPrincipalRoles \ + import IPrincipalRolesManager from Zope.Exceptions import Unauthorized, Forbidden from Zope.App.OFS.Memento.IAttributeMementoStorable \ import IAttributeMementoStorable @@ -95,13 +97,13 @@ arole = roleRegistry.defineRole('Another', 'Another Role') self.arole = arole.getId() - rolePermissionManager.grantPermissionToRole(self.read, self.peon) + rolePermissionsManager.grantPermissionToRole(self.read, self.peon) - rolePermissionManager.grantPermissionToRole(self.read, self.manager) - rolePermissionManager.grantPermissionToRole(self.write, self.manager) + rolePermissionsManager.grantPermissionToRole(self.read, self.manager) + rolePermissionsManager.grantPermissionToRole(self.write, self.manager) - principalRoleManager.assignRoleToPrincipal(self.peon, self.jim) - principalRoleManager.assignRoleToPrincipal(self.manager, self.tim) + principalRolesManager.assignRoleToPrincipal(self.peon, self.jim) + principalRolesManager.assignRoleToPrincipal(self.manager, self.tim) self.policy = self._makePolicy() @@ -131,21 +133,21 @@ self.policy.checkPermission( self.read, None, Context(self.unknown))) - rolePermissionManager.grantPermissionToRole(self.read, 'Anonymous') + rolePermissionsManager.grantPermissionToRole(self.read, 'Anonymous') self.failUnless( self.policy.checkPermission( self.read, None, Context(self.unknown))) - principalPermissionManager.grantPermissionToPrincipal( + principalPermissionsManager.grantPermissionToPrincipal( self.write, self.jim) self.failUnless( self.policy.checkPermission(self.write, None, Context(self.jim))) def testPlayfulRolePermissions(self): - ARPM = AttributeRolePermissionManager - provideAdapter(ITest, IRolePermissionManager, ARPM) + ARPM = MementoRolePermissionsManager + provideAdapter(ITest, IRolePermissionsManager, ARPM) test = permissionRegistry.definePermission('test', 'Test', '') test = test.getId() @@ -165,11 +167,11 @@ self.failUnless(self.policy.checkPermission( test, ob, Context(self.jim))) # Make sure global principal permissions override placeful role perms - principalPermissionManager.denyPermissionToPrincipal( + principalPermissionsManager.denyPermissionToPrincipal( test, self.jim) self.failIf(self.policy.checkPermission( test, ob, Context(self.jim))) - principalPermissionManager.unsetPermissionForPrincipal( + principalPermissionsManager.unsetPermissionForPrincipal( test, self.jim) # Make sure multiple conflicting role permissions resolve correctly ARPM(ob2).grantPermissionToRole(test, 'Anonymous') @@ -179,14 +181,14 @@ new = principalRegistry.definePrincipal('new', 'Newbie', 'Newbie User', 'new', '098') new = new.getId() - principalRoleManager.assignRoleToPrincipal(self.arole, new) + principalRolesManager.assignRoleToPrincipal(self.arole, new) self.failUnless(self.policy.checkPermission(test, ob, Context(new))) - principalRoleManager.assignRoleToPrincipal(self.peon, new) + principalRolesManager.assignRoleToPrincipal(self.peon, new) self.failIf(self.policy.checkPermission(test, ob, Context(new))) def testPlayfulPrinciplePermissions(self): - APPM = AttributePrincipalPermissionManager - provideAdapter(ITest, IPrincipalPermissionManager, APPM) + APPM = MementoPrincipalPermissionsManager + provideAdapter(ITest, IPrincipalPermissionsManager, APPM) ob1 = TestClass() ob2 = TestClass() @@ -212,11 +214,11 @@ Context(self.jim))) # make sure placeful principal permissions override global ones APPM(ob).grantPermissionToPrincipal(test, self.tim) - principalPermissionManager.denyPermissionToPrincipal( + principalPermissionsManager.denyPermissionToPrincipal( test, self.tim) self.failUnless(self.policy.checkPermission(test, ob, Context(self.tim))) - principalPermissionManager.unsetPermissionForPrincipal( + principalPermissionsManager.unsetPermissionForPrincipal( test, self.tim) @@ -234,11 +236,11 @@ self.policy.validate, 'x', Protected(self.write), Context(self.unknown)) - rolePermissionManager.grantPermissionToRole(self.read, 'Anonymous') + rolePermissionsManager.grantPermissionToRole(self.read, 'Anonymous') self.policy.validate('_', Protected(self.read), Context(self.unknown)) - principalPermissionManager.grantPermissionToPrincipal(self.write, + principalPermissionsManager.grantPermissionToPrincipal(self.write, self.jim) self.policy.validate('_', Protected(self.write), Context(self.jim)) === Removed File Zope3/lib/python/Zope/App/Security/tests/RolePermissionManager.py === === Removed File Zope3/lib/python/Zope/App/Security/tests/testAttributePrincipalPermissionManager.py === === Removed File Zope3/lib/python/Zope/App/Security/tests/testAttributePrincipalRoleManager.py === === Removed File Zope3/lib/python/Zope/App/Security/tests/testAttributeRolePermissionManager.py === === Removed File Zope3/lib/python/Zope/App/Security/tests/testPrincipalPermissionManager.py === === Removed File Zope3/lib/python/Zope/App/Security/tests/testPrincipalPermissionView.py === === Removed File Zope3/lib/python/Zope/App/Security/tests/testPrincipalRoleManager.py === === Removed File Zope3/lib/python/Zope/App/Security/tests/testPrincipalRoleView.py === === Removed File Zope3/lib/python/Zope/App/Security/tests/testRolePermissionManager.py === === Removed File Zope3/lib/python/Zope/App/Security/tests/testRolePermissionView.py === === Removed File Zope3/lib/python/Zope/App/Security/tests/testSettings.py === From casey@zope.com Tue Apr 9 17:38:55 2002 From: casey@zope.com (Casey Duncan) Date: Tue, 9 Apr 2002 12:38:55 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security/Management/pt Zope3/lib/python/Zope/App/Security/Management/pt - New directory Message-ID: <200204091638.g39Gctr13172@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Security/Management/pt In directory cvs.zope.org:/tmp/cvs-serv13166/pt Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/Security/Management/pt added to the repository --> Using per-directory sticky tag `casey-security-reorg-branch' === Added directory Zope3/lib/python/Zope/App/Security/Management/pt === From m.faassen@vet.uu.nl Tue Apr 9 17:39:43 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Tue, 9 Apr 2002 12:39:43 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/Find - FindAdapter.py:1.1.2.2 Message-ID: <200204091639.g39GdhB13668@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Find In directory cvs.zope.org:/tmp/cvs-serv13256/App/OFS/Container/Find Modified Files: Tag: Zope-3x-branch FindAdapter.py Log Message: Use new 'url' view to get absolute_url so you can actually click on links now. === Zope3/lib/python/Zope/App/OFS/Container/Find/FindAdapter.py 1.1.2.1 => 1.1.2.2 === container = self._context for id, object in container.objectItems(): + object = Wrapper(object, container, name=id) _find_helper(id, object, container, id_filters, object_filters, result) @@ -61,8 +62,6 @@ if not object_filter.matches(object): break else: - # XXX wrap object - object = Wrapper(object, container, name=id) # if we didn't break out of the loop, all filters matched result.append(object) @@ -71,6 +70,7 @@ container = object for id, object in container.objectItems(): + object = Wrapper(object, container, name=id) _find_helper(id, object, container, id_filters, object_filters, result) class SimpleIdFindFilter(object): From m.faassen@vet.uu.nl Tue Apr 9 17:39:43 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Tue, 9 Apr 2002 12:39:43 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/Find/Views/Browser - Find.py:1.1.2.2 find.pt:1.1.2.2 Message-ID: <200204091639.g39Gdh913671@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Find/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv13256/App/OFS/Container/Find/Views/Browser Modified Files: Tag: Zope-3x-branch Find.py find.pt Log Message: Use new 'url' view to get absolute_url so you can actually click on links now. === Zope3/lib/python/Zope/App/OFS/Container/Find/Views/Browser/Find.py 1.1.2.1 => 1.1.2.2 === from Zope.App.OFS.Container.Find.FindAdapter import SimpleIdFindFilter -from Zope.ComponentArchitecture import getAdapter +from Zope.ComponentArchitecture import getAdapter, getRequestView # XXX very simple implementation right now class Find(AttributePublisher): @@ -35,6 +35,9 @@ index = PageTemplateFile('find.pt') + def setViewRequest(self, request): + self._request = request + def findByIds(self, ids): """Do a find for the ids listed in ids, which is a string. """ @@ -43,9 +46,14 @@ # if we don't have any ids listed, don't search at all if not ids: return [] - found = finder.find([SimpleIdFindFilter(ids)]) - return [getId(object) for object in found] - + request = self._request + result = [] + for object in finder.find([SimpleIdFindFilter(ids)]): + id = getId(object) + url = str(getRequestView(object, 'url', request)) + result.append({ 'id': id, 'url': url}) + return result + from Zope.ContextWrapper import getdict # XXX get the id of an object (should be imported from somewhere) === Zope3/lib/python/Zope/App/OFS/Container/Find/Views/Browser/find.pt 1.1.2.1 => 1.1.2.2 === - - + +
id
id
From casey@zope.com Tue Apr 9 17:43:30 2002 From: casey@zope.com (Casey Duncan) Date: Tue, 9 Apr 2002 12:43:30 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security/pt - manage_access.pt:NONE manage_permissionForm.pt:NONE manage_roleForm.pt:NONE principal_permission_edit.pt:NONE principal_role_association.pt:NONE Message-ID: <200204091643.g39GhUA14589@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Security/pt In directory cvs.zope.org:/tmp/cvs-serv14482/pt Removed Files: Tag: casey-security-reorg-branch manage_access.pt manage_permissionForm.pt manage_roleForm.pt principal_permission_edit.pt principal_role_association.pt Log Message: Moved page templates for security management under Management pkg === Removed File Zope3/lib/python/Zope/App/Security/pt/manage_access.pt === === Removed File Zope3/lib/python/Zope/App/Security/pt/manage_permissionForm.pt === === Removed File Zope3/lib/python/Zope/App/Security/pt/manage_roleForm.pt === === Removed File Zope3/lib/python/Zope/App/Security/pt/principal_permission_edit.pt === === Removed File Zope3/lib/python/Zope/App/Security/pt/principal_role_association.pt === From casey@zope.com Tue Apr 9 17:43:30 2002 From: casey@zope.com (Casey Duncan) Date: Tue, 9 Apr 2002 12:43:30 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security/Management/pt - manage_access.pt:1.1.2.1 manage_permissionForm.pt:1.1.2.1 manage_roleForm.pt:1.1.2.1 principal_permission_edit.pt:1.1.2.1 principal_role_association.pt:1.1.2.1 Message-ID: <200204091643.g39GhUa14590@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Security/Management/pt In directory cvs.zope.org:/tmp/cvs-serv14482/Management/pt Added Files: Tag: casey-security-reorg-branch manage_access.pt manage_permissionForm.pt manage_roleForm.pt principal_permission_edit.pt principal_role_association.pt Log Message: Moved page templates for security management under Management pkg === Added File Zope3/lib/python/Zope/App/Security/Management/pt/manage_access.pt ===

a helpful message jim was here

another helpful message

Permission
Roles
=== Added File Zope3/lib/python/Zope/App/Security/Management/pt/manage_permissionForm.pt ===

jim hasn't been here (yet!)

Roles assigned to the permission Change DTML Methods (id: Zope.Some.Permission)

=== Added File Zope3/lib/python/Zope/App/Security/Management/pt/manage_roleForm.pt ===

jim hasn't been here to set specific roles (yet!)

Permissions assigned to the role Great Master Guru (id: Zope.Some.Role)

=== Added File Zope3/lib/python/Zope/App/Security/Management/pt/principal_permission_edit.pt ===

Permission settings for PrincipalName

Permission Settings

Allowed Permissions
Permission1
Permission2
Permission3
Permission5
Denied Permissions
Permission1
Permission2

 

Add permission settings

=== Added File Zope3/lib/python/Zope/App/Security/Management/pt/principal_role_association.pt ===
Apply filter
Principal(s): Role(s):
  role id
Principal Id
From srichter@cbu.edu Tue Apr 9 17:44:18 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 09 Apr 2002 11:44:18 -0500 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZMI - ZMIViewService.py:1.1.2.8.6.1 In-Reply-To: <200204091636.g39GajE12961@cvs.baymountain.com> Message-ID: <5.1.0.14.2.20020409114345.01337d80@mercury-1.cbu.edu> At 12:36 PM 4/9/2002 -0400, Casey Duncan wrote: >Mass checkin for security reorganization branch. I will retest this and merge >upon BDFL approval... Casey, you used old headers. Could you please change that? There is a script in utilities. Regards, Stephan -- Stephan Richter CBU - Physics and Chemistry Student Web2k - Web Design/Development & Technical Project Management From casey@zope.com Tue Apr 9 17:45:51 2002 From: casey@zope.com (Casey Duncan) Date: Tue, 9 Apr 2002 12:45:51 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZMI - ZMIViewService.py:1.1.2.8.6.2 Message-ID: <200204091645.g39Gjpn15594@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZMI In directory cvs.zope.org:/tmp/cvs-serv15587 Modified Files: Tag: casey-security-reorg-branch ZMIViewService.py Log Message: Removed debug code === Zope3/lib/python/Zope/App/ZMI/ZMIViewService.py 1.1.2.8.6.1 => 1.1.2.8.6.2 === res.append( view_value ) - print res + return res def _createContext(self, object): From srichter@cbu.edu Tue Apr 9 17:49:18 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 12:49:18 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - PublisherFileSystem.py:1.1.2.5 Message-ID: <200204091649.g39GnIU15961@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv15777/Server/VFS Modified Files: Tag: Zope3-Server-Branch PublisherFileSystem.py Log Message: Okay, I cleaned up some stuff. Could someone look at PublisherFileSystem._execute() and tell me why the Request looses the response during the publish process! Any ideas? === Zope3/lib/python/Zope/Server/VFS/PublisherFileSystem.py 1.1.2.4 => 1.1.2.5 === - def __init__ (self, root, persona): + def __init__ (self, root, username, password): self.root = root + self.username + self.password def _execute(self, path, command, env=None): @@ -51,7 +53,10 @@ env['command'] = command env['path'] = path + # XXX integrate security somehow into the request + request = self.request_factory(StringIO(''), StringIO(), env) + # XXX **** WHY IS THE REQUEST LOOSING ITS RESPONSE DURING PUBLISH? *** resp = request._response publish(request) print resp.getResult() From srichter@cbu.edu Tue Apr 9 17:49:18 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 12:49:18 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/StartUp - startup-registry.zcml:1.1.2.1.4.3 Message-ID: <200204091649.g39GnIV15962@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/StartUp In directory cvs.zope.org:/tmp/cvs-serv15777/StartUp Modified Files: Tag: Zope3-Server-Branch startup-registry.zcml Log Message: Okay, I cleaned up some stuff. Could someone look at PublisherFileSystem._execute() and tell me why the Request looses the response during the publish process! Any ideas? === Zope3/lib/python/Zope/StartUp/startup-registry.zcml 1.1.2.1.4.2 => 1.1.2.1.4.3 === /> + Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv15777/Server/FTP Modified Files: Tag: Zope3-Server-Branch FTPServerChannel.py PublisherFTPServer.py Log Message: Okay, I cleaned up some stuff. Could someone look at PublisherFileSystem._execute() and tell me why the Request looses the response during the publish process! Any ideas? === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.17 => 1.1.2.18 === + def _getFileSystem(self): + """Open the filesystem using the username and password.""" + return self.server.openFileSystem(self.username, self.password) + + ############################################################ # Implementation methods for interface # Zope.Server.FTP.IFTPCommandHandler @@ -110,7 +115,7 @@ def cmd_cdup(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' path = self._generatePath('../') - if self.server.openFilesystem(self.username).exists(path): + if self._getFilesystem().exists(path): self.cwd = path self.reply('SUCCESS_250', 'CDUP') else: @@ -120,7 +125,7 @@ def cmd_cwd(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' path = self._generatePath(args) - if self.server.openFilesystem(self.username).exists(path): + if self._getFilesystem().exists(path): self.cwd = path self.reply('SUCCESS_250', 'CWD') else: @@ -135,7 +140,7 @@ path = self._generatePath(args) try: - self.server.openFilesystem(self.username).remove(path) + self._getFilesystem().remove(path) except OSError, err: self.reply('ERR_DELETE_FILE', str(err)) else: @@ -170,7 +175,7 @@ def cmd_mdtm(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' path = self._generatePath(args) - if not self.server.openFilesystem(self.username).isfile(path): + if not self._getFilesystem().isfile(path): self.reply('ERR_IS_NOT_FILE', path) else: mtime = time.gmtime( @@ -188,7 +193,7 @@ return path = self._generatePath(args) try: - self.server.openFilesystem(self.username).mkdir(path) + self._getFilesystem().mkdir(path) except OSError, err: self.reply('ERR_CREATE_DIR', str(err)) else: @@ -268,7 +273,7 @@ self.reply('CMD_UNKNOWN', 'RETR') path = self._generatePath(args) - if not self.server.openFilesystem(self.username).isfile(path): + if not self._getFilesystem().isfile(path): self.reply('ERR_IS_NOT_FILE', path) return @@ -285,7 +290,7 @@ outstream = ApplicationXmitStream(cdc) try: - self.server.openFilesystem(self.username).readfile( + self._getFilesystem().readfile( path, mode, outstream, start) cdc.close_when_done() except OSError, err: @@ -312,7 +317,7 @@ return path = self._generatePath(args) try: - self.server.openFilesystem(self.username).rmdir(path) + self._getFilesystem().rmdir(path) except OSError, err: self.reply('ERR_DELETE_DIR', str(err)) else: @@ -322,7 +327,7 @@ def cmd_rnfr(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' path = self._generatePath(args) - if self.server.openFilesystem(self.username).exists(path): + if self._getFilesystem().exists(path): self._rnfr = path self.reply('READY_FOR_DEST') else: @@ -335,7 +340,7 @@ if self._rnfr is None: self.reply('ERR_RENAME') try: - self.server.openFilesystem(self.username).rename(self._rnfr, path) + self._getFilesystem().rename(self._rnfr, path) except OSError, err: self.reply('ERR_RENAME', (self._rnfr, rnto, str(err))) else: @@ -346,7 +351,7 @@ def cmd_size(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' path = self._generatePath(args) - if not self.server.openFilesystem(self.username).isfile(path): + if not self._getFilesystem().isfile(path): self.reply('ERR_NO_FILE', path) else: self.reply('FILE_SIZE', self.server.openFilesystem( @@ -390,8 +395,7 @@ try: infile = buffer.getfile() infile.seek(0) - self.server.openFilesystem(self.username).writefile(path, mode, - infile, start) + self._getFilesystem().writefile(path, mode, infile, start) except OSError, err: self.reply('ERR_OPEN_WRITE', str(err)) except IOError, err: @@ -466,8 +470,7 @@ def listdir (self, path, long=0): """returns a string""" path = self._generatePath(path) - file_list = self.server.openFilesystem(self.username).listdir(path, - long) + file_list = self._getFilesystem().listdir(path, long) if long: file_list = map(longify, file_list) return '\r\n'.join(file_list) + '\r\n' === Zope3/lib/python/Zope/Server/FTP/PublisherFTPServer.py 1.1.2.3 => 1.1.2.4 === $Id$ """ -import asyncore -import pwd from FTPServerChannel import FTPServerChannel from Zope.Server.ServerBase import ServerBase -from Zope.StartUp.RequestFactory import RequestFactory from Zope.Server.VFS.PublisherFileSystem import PublisherFileSystem -from Zope.Server.Authentication.DictionaryAuthentication import \ - DictionaryAuthentication -from ZODB import DB -from ZODB.FileStorage import FileStorage -from Zope.Publisher.VFS.VFSRequest import VFSRequest -from Zope.App.ZopePublication.VFS.Publication import VFSPublication -class FileSystemOpener: +class PublisherFileSystemOpener: + """ """ + + filesystem_factory = PublisherFileSystem def __init__(self, root_dir, request_factory): self.root_dir = root_dir - self.filesystem_class = PublisherFileSystem - self.filesystem_class.request_factory = request_factory + self.filesystem_factory.request_factory = request_factory + + + def __call__(self, username, password): + return PublisherFileSystem(self.root_dir, username, password) - def __call__(self, username): - persona = pwd.getpwnam(username)[2:4] - return self.filesystem_class(self.root_dir, persona) class PublisherFTPServer(ServerBase): @@ -50,55 +44,13 @@ SERVER_IDENT = 'Zope.Server.FTPServer' - def __init__(self, request_factory, ip, port, task_dispatcher=None, - adj=None, start=1, hit_log=None, verbose=0, socket_map=None, - fs_opener=None, auth_source=None): + def __init__(self, request_factory, name='FTP', ip, port, + task_dispatcher=None, adj=None, start=1, hit_log=None, + verbose=0, socket_map=None): self.request_factory = request_factory - self.openFilesystem = fs_opener - self.auth_source = auth_source + self.openFilesystem = PublisherFileSystemOpener('/', request_factory) super(PublisherFTPServer, self).__init__(ip, port, task_dispatcher, adj, start, hit_log, verbose, socket_map) - - -if __name__ == '__main__': - from Zope.Server.TaskThreads import ThreadedTaskDispatcher - td = ThreadedTaskDispatcher() - td.setThreadCount(4) - - auth_source = DictionaryAuthentication({'root': 'bar'}) - req = RequestFactory(VFSPublication, VFSRequest) - db = DB(FileStorage('/opt/Zope3-Branches/Zope-3x-Server/Data.fs')) - req = req.realize(db) - fs_opener = FileSystemOpener(dir, req) - - - from Zope.App.OFS.Container.Views.VFS.VFSContainerView import \ - VFSContainerView - from Zope.App.OFS.Container.ContainerTraverser import ContainerTraverser - from Zope.Publisher.VFS.IVFSPublisher import IVFSPublisher - from Zope.App.OFS.Container.IContainer import IContainer - from Zope.App.OFS.Folder.RootFolder import IRootFolder - from Zope.ComponentArchitecture import provideView, setDefaultViewName - setDefaultViewName(IContainer, IVFSPublisher, 'vfs') - provideView(IContainer, 'vfs', IVFSPublisher, VFSContainerView, '') - provideView(IContainer, '_traverse', IVFSPublisher, ContainerTraverser, '') - - from Zope.App.Security.PrincipalRoleManager import \ - principalRoleManager as principal_role_mgr - from Zope.App.Security.PrincipalRegistry import principalRegistry - - principalRegistry.defineDefaultPrincipal('anybody', 'anybody', 'All') - principal_role_mgr.assignRoleToPrincipal('Manager', 'anybody') - - PublisherFTPServer(req, '', 8021, task_dispatcher=td, fs_opener=fs_opener, - auth_source=auth_source) - try: - while 1: - asyncore.poll(5) - print 'active channels:', FTPServerChannel.active_channels - except KeyboardInterrupt: - print 'shutting down...' - td.shutdown() From casey@zope.com Tue Apr 9 19:51:04 2002 From: casey@zope.com (Casey Duncan) Date: Tue, 09 Apr 2002 12:51:04 -0600 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZMI - ZMIViewService.py:1.1.2.8.6.1 References: <5.1.0.14.2.20020409114345.01337d80@mercury-1.cbu.edu> Message-ID: <3CB33818.3090007@zope.com> Ok, these "new" files are really just old ones that got merged, modified and moved. I'll look at the headers utility. So much to remember.... ;^) -Casey Stephan Richter wrote: > At 12:36 PM 4/9/2002 -0400, Casey Duncan wrote: > >> Mass checkin for security reorganization branch. I will retest this >> and merge >> upon BDFL approval... > > > Casey, > > you used old headers. Could you please change that? There is a script in > utilities. > > Regards, > Stephan > > -- > Stephan Richter > CBU - Physics and Chemistry Student > Web2k - Web Design/Development & Technical Project Management > From srichter@cbu.edu Tue Apr 9 17:58:18 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 12:58:18 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Folder/Views/VFS Zope3/lib/python/Zope/App/OFS/Folder/Views/VFS - New directory Message-ID: <200204091658.g39GwIW18518@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Folder/Views/VFS In directory cvs.zope.org:/tmp/cvs-serv18512/App/OFS/Folder/Views/VFS Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/Folder/Views/VFS added to the repository --> Using per-directory sticky tag `Zope3-Server-Branch' === Added directory Zope3/lib/python/Zope/App/OFS/Folder/Views/VFS === From srichter@cbu.edu Tue Apr 9 18:02:57 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 13:02:57 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Folder/Views/VFS - __init__.py:1.1.2.1 vfs.zcml:1.1.2.1 Message-ID: <200204091702.g39H2vh19825@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Folder/Views/VFS In directory cvs.zope.org:/tmp/cvs-serv19629/App/OFS/Folder/Views/VFS Added Files: Tag: Zope3-Server-Branch __init__.py vfs.zcml Log Message: Hihi, without these files my checkins won't make much sense. :) === Added File Zope3/lib/python/Zope/App/OFS/Folder/Views/VFS/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.2.1 2002/04/09 17:02:56 srichter Exp $ """ === Added File Zope3/lib/python/Zope/App/OFS/Folder/Views/VFS/vfs.zcml === From srichter@cbu.edu Tue Apr 9 18:02:57 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 13:02:57 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/Views/VFS - VFSContainerView.py:1.1.2.1 Message-ID: <200204091702.g39H2vG19822@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Views/VFS In directory cvs.zope.org:/tmp/cvs-serv19629/App/OFS/Container/Views/VFS Added Files: Tag: Zope3-Server-Branch VFSContainerView.py Log Message: Hihi, without these files my checkins won't make much sense. :) === Added File Zope3/lib/python/Zope/App/OFS/Container/Views/VFS/VFSContainerView.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: VFSContainerView.py,v 1.1.2.1 2002/04/09 17:02:56 srichter Exp $ """ import fnmatch from Zope.Publisher.VFS.IVFSDirectoryPublisher import IVFSDirectoryPublisher class VFSContainerView: __implements__ = IVFSDirectoryPublisher def __init__(self, context): """ """ self._container = context ############################################################ # Implementation methods for interface # Zope.Publisher.VFS.IVFSDirectoryPublisher def exists(self, name): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' return self._container.hasObject(name) def listdir(self, with_stats=0, pattern='*'): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' ld = self._container.objectIds() # filter them using the pattern ld = filter(lambda f, p=pattern, fnm=fnmatch.fnmatch: fnm(f, p), ld) # sort them alphabetically ld.sort() if not with_stats: result = ld else: result = [] for file in ld: stat = (16893, 0, 0, 0, 0, 0, 0, 0, 0, 0) if stat is not None: result.append((file, stat)) return result def mkdir(self, name, mode=777): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' pass def remove(self, name): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' return self._container.delObject(name) def rmdir(self, name): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' return self._container.delObject(name) def rename(self, old, new): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' obj = self._container.getObject(old) self._container.delObject(old) self._container.setObject(new, obj) ###################################### # from: Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher def isdir(self): 'See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher' return 1 def isfile(self): 'See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher' return 0 def stat(self): 'See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher' return (16893, 0, 0, 0, 0, 0, 0, 0, 0, 0) ###################################### # from: Zope.Publisher.VFS.IVFSPublisher.IVFSPublisher def publishTraverse(self, request, name): 'See Zope.Publisher.VFS.IVFSPublisher.IVFSPublisher' return getattr(self, name) # ############################################################ def getContext(self): """ """ return self._container From srichter@cbu.edu Tue Apr 9 18:02:57 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 13:02:57 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - IPosixFileSystem.py:1.1.2.1 Message-ID: <200204091702.g39H2vM19829@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv19629/Server/VFS Added Files: Tag: Zope3-Server-Branch IPosixFileSystem.py Log Message: Hihi, without these files my checkins won't make much sense. :) === Added File Zope3/lib/python/Zope/Server/VFS/IPosixFileSystem.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IPosixFileSystem.py,v 1.1.2.1 2002/04/09 17:02:56 srichter Exp $ """ from IWriteFileSystem import IWriteFileSystem from IReadFileSystem import IReadFileSystem class IPosixFileSystem(IWriteFileSystem, IReadFileSystem): """ """ def chmod(path, mode): """Change the access permissions of a file. """ def chown(path, uid, gid): """Change the owner and group id of path to numeric uid and gid. """ def link(src, dst): """Create a heard link to a file. """ def mkfifo(path, mode=777): """Create a FIFO (a POSIX named pipe). """ def symlink(src, dst): """Create a symbolic link at dst pointing to src. """ From srichter@cbu.edu Wed Apr 10 01:23:04 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 20:23:04 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - PublisherFileSystem.py:1.1.2.6 Message-ID: <200204100023.g3A0N4117989@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv17043/lib/python/Zope/Server/VFS Modified Files: Tag: Zope3-Server-Branch PublisherFileSystem.py Log Message: This check-in makes the Publisher FTP Server finally work. Yipee! Everything worked out much better than I hope and my protyping turned out to be an overkill. Now it is time to clean up some things and complete the code. Things that need to be done: 1. Finish File view, so that read and write can be supported. 2. Implement security. Right now it allows any username/password pair. 3. Fix bugs and remove debugging statements. 4. Write tests. === Zope3/lib/python/Zope/Server/VFS/PublisherFileSystem.py 1.1.2.5 => 1.1.2.6 === def __init__ (self, root, username, password): self.root = root - self.username - self.password + self.username = username + self.password = password def _execute(self, path, command, env=None): From srichter@cbu.edu Wed Apr 10 01:23:04 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 20:23:04 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - OSEmulators.py:1.1.2.1 PublisherFTPServerChannel.py:1.1.2.1 FTPServerChannel.py:1.1.2.19 PublisherFTPServer.py:1.1.2.5 Message-ID: <200204100023.g3A0N4217988@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv17043/lib/python/Zope/Server/FTP Modified Files: Tag: Zope3-Server-Branch FTPServerChannel.py PublisherFTPServer.py Added Files: Tag: Zope3-Server-Branch OSEmulators.py PublisherFTPServerChannel.py Log Message: This check-in makes the Publisher FTP Server finally work. Yipee! Everything worked out much better than I hope and my protyping turned out to be an overkill. Now it is time to clean up some things and complete the code. Things that need to be done: 1. Finish File view, so that read and write can be supported. 2. Implement security. Right now it allows any username/password pair. 3. Fix bugs and remove debugging statements. 4. Write tests. === Added File Zope3/lib/python/Zope/Server/FTP/OSEmulators.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: OSEmulators.py,v 1.1.2.1 2002/04/10 00:23:02 srichter Exp $ """ import stat import time import pwd, grp months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] mode_table = { '0':'---', '1':'--x', '2':'-w-', '3':'-wx', '4':'r--', '5':'r-x', '6':'rw-', '7':'rwx' } def unix_longify((file, stat_info)): # for now, only pay attention to the lower bits try: username = pwd.getpwuid(int(stat_info[stat.ST_UID]))[0] except: username = stat_info[stat.ST_UID] try: grpname = grp.getgrgid(int(stat_info[stat.ST_GID]))[0] except: grpname = stat_info[stat.ST_GID] mode = ('%o' % stat_info[stat.ST_MODE])[-3:] mode = ''.join(map (lambda x: mode_table[x], mode)) if stat.S_ISDIR (stat_info[stat.ST_MODE]): dirchar = 'd' else: dirchar = '-' date = ls_date (long(time.time()), stat_info[stat.ST_MTIME]) return '%s%s %3d %-8s %-8s %8d %s %s' % ( dirchar, mode, stat_info[stat.ST_NLINK], username, grpname, stat_info[stat.ST_SIZE], date, file ) def ls_date (now, t): """Emulate the unix 'ls' command's date field. it has two formats - if the date is more than 180 days in the past, then it's like this: Oct 19 1995 otherwise, it looks like this: Oct 19 17:33 """ try: info = time.gmtime(t) except: info = time.gmtime(0) # 15,600,000 == 86,400 * 180 if (now - t) > 15600000: return '%s %2d %d' % ( months[info[1]-1], info[2], info[0] ) else: return '%s %2d %02d:%02d' % ( months[info[1]-1], info[2], info[3], info[4] ) def msdos_longify((file, stat_info)): """This matches the output of NT's ftp server (when in MSDOS mode) exactly. """ if stat.S_ISDIR(stat_info[stat.ST_MODE]): dir = '' else: dir = ' ' date = msdos_date(stat_info[stat.ST_MTIME]) return '%s %s %8d %s' % (date, dir, stat_info[stat.ST_SIZE], file) def msdos_date(t): try: info = time.gmtime(t) except: info = time.gmtime(0) # year, month, day, hour, minute, second, ... if info[3] > 11: merid = 'PM' info[3] = info[3] - 12 else: merid = 'AM' return '%02d-%02d-%02d %02d:%02d%s' % ( info[1], info[2], info[0]%100, info[3], info[4], merid ) === Added File Zope3/lib/python/Zope/Server/FTP/PublisherFTPServerChannel.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: PublisherFTPServerChannel.py,v 1.1.2.1 2002/04/10 00:23:02 srichter Exp $ """ from FTPServerChannel import FTPServerChannel class PublisherFTPServerChannel(FTPServerChannel): """The FTP Server Channel represents a connection to a particular client. We can therefore store information here.""" __implements__ = FTPServerChannel.__implements__ def authenticate(self): # XXX We need to hook this up to the Zope security mechanism return 1, 'All cool' === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.18 => 1.1.2.19 === - def _getFileSystem(self): + def _getFilesystem(self): """Open the filesystem using the username and password.""" - return self.server.openFileSystem(self.username, self.password) + return self.server.openFilesystem(self.username, self.password) ############################################################ @@ -179,9 +179,7 @@ self.reply('ERR_IS_NOT_FILE', path) else: mtime = time.gmtime( - self.server.openFilesystem( - self.username).stat(path)[stat.ST_MTIME] - ) + self._getFilesystem().stat(path)[stat.ST_MTIME]) self.reply('FILE_DATE', (mtime[0], mtime[1], mtime[2], mtime[3], mtime[4], mtime[5]) ) @@ -221,9 +219,7 @@ def cmd_pass(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' self.password = args - auth = self.server.auth_source - self.authenticated, message = auth.authenticate(self.username, - self.password) + self.authenticated, message = self.authenticate() if self.authenticated: self.reply('LOGIN_SUCCESS') else: @@ -457,6 +453,11 @@ path = os.path.normpath(path) return path + + def authenticate(self): + auth = self.server.auth_source + return auth.authenticate(self.username, self.password) + def newPassiveAcceptor(self): # ensure that only one of these exists at a time. === Zope3/lib/python/Zope/Server/FTP/PublisherFTPServer.py 1.1.2.4 => 1.1.2.5 === $Id$ """ -from FTPServerChannel import FTPServerChannel +from PublisherFTPServerChannel import PublisherFTPServerChannel from Zope.Server.ServerBase import ServerBase from Zope.Server.VFS.PublisherFileSystem import PublisherFileSystem @@ -40,11 +40,11 @@ class PublisherFTPServer(ServerBase): """Generic FTP Server""" - channel_class = FTPServerChannel + channel_class = PublisherFTPServerChannel SERVER_IDENT = 'Zope.Server.FTPServer' - def __init__(self, request_factory, name='FTP', ip, port, + def __init__(self, request_factory, name, ip, port, task_dispatcher=None, adj=None, start=1, hit_log=None, verbose=0, socket_map=None): From srichter@cbu.edu Wed Apr 10 01:23:31 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 20:23:31 -0400 Subject: [Zope-Checkins] CVS: Zope3 - startup.zcml:1.1.2.3.4.2 Message-ID: <200204100023.g3A0NVb18110@cvs.baymountain.com> Update of /cvs-repository/Zope3 In directory cvs.zope.org:/tmp/cvs-serv17043 Modified Files: Tag: Zope3-Server-Branch startup.zcml Log Message: This check-in makes the Publisher FTP Server finally work. Yipee! Everything worked out much better than I hope and my protyping turned out to be an overkill. Now it is time to clean up some things and complete the code. Things that need to be done: 1. Finish File view, so that read and write can be supported. 2. Implement security. Right now it allows any username/password pair. 3. Fix bugs and remove debugging statements. 4. Write tests. === Zope3/startup.zcml 1.1.2.3.4.1 => 1.1.2.3.4.2 === set to false, nothing is reported. --> - - + + From srichter@cbu.edu Wed Apr 10 01:23:31 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 20:23:31 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS - ofs.zcml:1.1.2.12.6.1 Message-ID: <200204100023.g3A0NV318113@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS In directory cvs.zope.org:/tmp/cvs-serv17043/lib/python/Zope/App/OFS Modified Files: Tag: Zope3-Server-Branch ofs.zcml Log Message: This check-in makes the Publisher FTP Server finally work. Yipee! Everything worked out much better than I hope and my protyping turned out to be an overkill. Now it is time to clean up some things and complete the code. Things that need to be done: 1. Finish File view, so that read and write can be supported. 2. Implement security. Right now it allows any username/password pair. 3. Fix bugs and remove debugging statements. 4. Write tests. === Zope3/lib/python/Zope/App/OFS/ofs.zcml 1.1.2.12 => 1.1.2.12.6.1 === xmlns:browser='http://namespaces.zope.org/browser' xmlns:xmlrpc='http://namespaces.zope.org/xmlrpc' + xmlns:vfs='http://namespaces.zope.org/vfs' > @@ -21,6 +22,10 @@ factory=".Container.ContainerTraverser." /> + + From srichter@cbu.edu Wed Apr 10 01:23:32 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 20:23:32 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/Views/VFS - VFSContainerView.py:1.1.2.2 Message-ID: <200204100023.g3A0NWK18116@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Views/VFS In directory cvs.zope.org:/tmp/cvs-serv17043/lib/python/Zope/App/OFS/Container/Views/VFS Modified Files: Tag: Zope3-Server-Branch VFSContainerView.py Log Message: This check-in makes the Publisher FTP Server finally work. Yipee! Everything worked out much better than I hope and my protyping turned out to be an overkill. Now it is time to clean up some things and complete the code. Things that need to be done: 1. Finish File view, so that read and write can be supported. 2. Implement security. Right now it allows any username/password pair. 3. Fix bugs and remove debugging statements. 4. Write tests. === Zope3/lib/python/Zope/App/OFS/Container/Views/VFS/VFSContainerView.py 1.1.2.1 => 1.1.2.2 === def listdir(self, with_stats=0, pattern='*'): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' - ld = self._container.objectIds() + file_list = self._container.objectIds() # filter them using the pattern - ld = filter(lambda f, p=pattern, fnm=fnmatch.fnmatch: fnm(f, p), ld) + file_list = list( + filter(lambda f, p=pattern, fnm=fnmatch.fnmatch: fnm(f, p), + file_list)) # sort them alphabetically - ld.sort() + file_list.sort() if not with_stats: result = ld else: result = [] - for file in ld: + for file in file_list: stat = (16893, 0, 0, 0, 0, 0, 0, 0, 0, 0) if stat is not None: result.append((file, stat)) From srichter@cbu.edu Wed Apr 10 01:23:32 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 20:23:32 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Folder/Views - views.zcml:1.1.4.1.6.2 Message-ID: <200204100023.g3A0NWY18119@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Folder/Views In directory cvs.zope.org:/tmp/cvs-serv17043/lib/python/Zope/App/OFS/Folder/Views Modified Files: Tag: Zope3-Server-Branch views.zcml Log Message: This check-in makes the Publisher FTP Server finally work. Yipee! Everything worked out much better than I hope and my protyping turned out to be an overkill. Now it is time to clean up some things and complete the code. Things that need to be done: 1. Finish File view, so that read and write can be supported. 2. Implement security. Right now it allows any username/password pair. 3. Fix bugs and remove debugging statements. 4. Write tests. === Zope3/lib/python/Zope/App/OFS/Folder/Views/views.zcml 1.1.4.1.6.1 => 1.1.4.1.6.2 === - + From srichter@cbu.edu Wed Apr 10 01:23:33 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 20:23:33 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher - publisher-meta.zcml:1.1.4.1.6.3 Message-ID: <200204100023.g3A0NXK18129@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher In directory cvs.zope.org:/tmp/cvs-serv17043/lib/python/Zope/Publisher Modified Files: Tag: Zope3-Server-Branch publisher-meta.zcml Log Message: This check-in makes the Publisher FTP Server finally work. Yipee! Everything worked out much better than I hope and my protyping turned out to be an overkill. Now it is time to clean up some things and complete the code. Things that need to be done: 1. Finish File view, so that read and write can be supported. 2. Implement security. Right now it allows any username/password pair. 3. Fix bugs and remove debugging statements. 4. Write tests. === Zope3/lib/python/Zope/Publisher/publisher-meta.zcml 1.1.4.1.6.2 => 1.1.4.1.6.3 === > - - - - + + + + From srichter@cbu.edu Wed Apr 10 01:23:33 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 20:23:33 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/VFS - metaConfigure.py:1.1.2.3 vfs-meta.zcml:1.1.2.2 vfs-meta.py:NONE Message-ID: <200204100023.g3A0NX218134@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/VFS In directory cvs.zope.org:/tmp/cvs-serv17043/lib/python/Zope/Publisher/VFS Modified Files: Tag: Zope3-Server-Branch metaConfigure.py vfs-meta.zcml Removed Files: Tag: Zope3-Server-Branch vfs-meta.py Log Message: This check-in makes the Publisher FTP Server finally work. Yipee! Everything worked out much better than I hope and my protyping turned out to be an overkill. Now it is time to clean up some things and complete the code. Things that need to be done: 1. Finish File view, so that read and write can be supported. 2. Implement security. Right now it allows any username/password pair. 3. Fix bugs and remove debugging statements. 4. Write tests. === Zope3/lib/python/Zope/Publisher/VFS/metaConfigure.py 1.1.2.2 => 1.1.2.3 === callable = setDefaultViewName, args = (for_, IVFSPublisher, name), - ) + ), Action( discriminator = ('view', for_, name, IVFSPublisher, layer), callable = provideView, === Zope3/lib/python/Zope/Publisher/VFS/vfs-meta.zcml 1.1.2.1 => 1.1.2.2 === + - + handler=".metaConfigure.view" /> === Removed File Zope3/lib/python/Zope/Publisher/VFS/vfs-meta.py === From srichter@cbu.edu Wed Apr 10 01:23:32 2002 From: srichter@cbu.edu (Stephan Richter) Date: Tue, 9 Apr 2002 20:23:32 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Folder/Views/VFS - vfs.zcml:1.1.2.2 Message-ID: <200204100023.g3A0NWN18125@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Folder/Views/VFS In directory cvs.zope.org:/tmp/cvs-serv17043/lib/python/Zope/App/OFS/Folder/Views/VFS Modified Files: Tag: Zope3-Server-Branch vfs.zcml Log Message: This check-in makes the Publisher FTP Server finally work. Yipee! Everything worked out much better than I hope and my protyping turned out to be an overkill. Now it is time to clean up some things and complete the code. Things that need to be done: 1. Finish File view, so that read and write can be supported. 2. Implement security. Right now it allows any username/password pair. 3. Fix bugs and remove debugging statements. 4. Write tests. === Zope3/lib/python/Zope/App/OFS/Folder/Views/VFS/vfs.zcml 1.1.2.1 => 1.1.2.2 === - xmlns='http://namespaces.zope.org/zope' - xmlns:security='http://namespaces.zope.org/security' - xmlns:vfs='http://namespaces.zope.org/vfs' + xmlns="http://namespaces.zope.org/zope" + xmlns:security="http://namespaces.zope.org/security" + xmlns:vfs="http://namespaces.zope.org/vfs" > - + factory="Zope.App.OFS.Container.Views.VFS.VFSContainerView." /> + interface="Zope.Publisher.VFS.IVFSDirectoryPublisher." /> From philikon@gmx.net Wed Apr 10 08:50:24 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 03:50:24 -0400 Subject: [Zope-Checkins] CVS: Zope3 - site.zcml:1.1.2.7 Message-ID: <200204100750.g3A7oO915828@cvs.baymountain.com> Update of /cvs-repository/Zope3 In directory cvs.zope.org:/tmp/cvs-serv15740 Modified Files: Tag: Zope-3x-branch site.zcml Log Message: Added Zope.ManageApplication permission for use with ApplicationController === Zope3/site.zcml 1.1.2.6 => 1.1.2.7 === role_id="Manager" /> + + From philikon@gmx.net Wed Apr 10 08:52:53 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 03:52:53 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views - New directory Message-ID: <200204100752.g3A7qrK17553@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views In directory cvs.zope.org:/tmp/cvs-serv17547/Views Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views added to the repository --> Using per-directory sticky tag `Zope-3x-branch' === Added directory Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views === From philikon@gmx.net Wed Apr 10 08:53:13 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 03:53:13 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser - New directory Message-ID: <200204100753.g3A7rDH17689@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv17677/Browser Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser added to the repository --> Using per-directory sticky tag `Zope-3x-branch' === Added directory Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser === From philikon@gmx.net Wed Apr 10 08:53:47 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 03:53:47 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/tests Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/tests - New directory Message-ID: <200204100753.g3A7rlT17979@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/tests In directory cvs.zope.org:/tmp/cvs-serv17971/tests Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/tests added to the repository --> Using per-directory sticky tag `Zope-3x-branch' === Added directory Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/tests === From philikon@gmx.net Wed Apr 10 08:57:04 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 03:57:04 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl - ApplicationControl.py:1.1.2.4 IApplicationControl.py:1.1.2.3 ZopeVersion.py:1.1.2.2 Message-ID: <200204100757.g3A7v4A19495@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl In directory cvs.zope.org:/tmp/cvs-serv19261 Modified Files: Tag: Zope-3x-branch ApplicationControl.py IApplicationControl.py ZopeVersion.py Log Message: Fixed doc string according to style guide lines === Zope3/lib/python/Zope/App/OFS/ApplicationControl/ApplicationControl.py 1.1.2.3 => 1.1.2.4 === ############################################################################## __doc__ = """ Application Control + $Id$""" from IApplicationControl import IApplicationControl === Zope3/lib/python/Zope/App/OFS/ApplicationControl/IApplicationControl.py 1.1.2.2 => 1.1.2.3 === # ############################################################################## -__doc__ = """ Application Control +__doc__ = """ Application Control Interface + $Id$""" from Interface import Interface === Zope3/lib/python/Zope/App/OFS/ApplicationControl/ZopeVersion.py 1.1.2.1 => 1.1.2.2 === +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +__doc__ = """Zope version + +$Id$""" + from Zope.App.OFS.ApplicationControl.IZopeVersion import IZopeVersion import os @@ -36,7 +53,7 @@ versionfile = os.path.join(zopedir, "version.txt") if os.path.isfile(versionfile) and not is_cvs: f = open(versionfile) - version_id = f.read().split("\n")[0] + version_id = f.read().split("\n")[0] or version_id version = "%s%s" % (version_id, version_tag) return version @@ -44,3 +61,5 @@ # ############################################################ + +ZopeVersionUtility = ZopeVersion() From philikon@gmx.net Wed Apr 10 09:00:51 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 04:00:51 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests - testRuntimeInfo.py:1.1.2.2 Message-ID: <200204100800.g3A80pf21480@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests In directory cvs.zope.org:/tmp/cvs-serv20943/tests Modified Files: Tag: Zope-3x-branch testRuntimeInfo.py Log Message: Runtime does not return the whole environment anymore but just the PYTHONPATH instead === Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests/testRuntimeInfo.py 1.1.2.1 => 1.1.2.2 === self.failUnless(abs(asserted_uptime - test_uptime) < time_tolerance) - def test_Environment(self): - runtime_info = self._Test__new() - - self.assertEqual(runtime_info.getEnvironment(), os.environ) - def test_suite(): return TestSuite(( makeSuite(Test), From philikon@gmx.net Wed Apr 10 09:00:51 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 04:00:51 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl - IRuntimeInfo.py:1.1.2.2 RuntimeInfo.py:1.1.2.2 Message-ID: <200204100800.g3A80pG21479@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl In directory cvs.zope.org:/tmp/cvs-serv20943 Modified Files: Tag: Zope-3x-branch IRuntimeInfo.py RuntimeInfo.py Log Message: Runtime does not return the whole environment anymore but just the PYTHONPATH instead === Zope3/lib/python/Zope/App/OFS/ApplicationControl/IRuntimeInfo.py 1.1.2.1 => 1.1.2.2 === # ############################################################################## -__doc__ = """ Runtime Information +__doc__ = """ Runtime Information Interface + $Id$""" from Interface import Interface @@ -26,6 +27,10 @@ def getPythonVersion(): """Return a string containing verbose description of the python interpreter""" + + def getPythonPath(): + """Return a tuple containing the lookup paths of the python interpreter + """ def getSystemPlatform(): """Return the system platform name in a 5 tuple of @@ -35,12 +40,10 @@ """Return the command line string Zope was invoked with""" def getProcessId(): - """Return the process id number currently serving the request""" + """Return the process id number currently serving the request + """ def getUptime(): """Return a string containing the Zope server uptime in unix uptime format with seconds ([NN days, ]HH:MM:SS)""" - def getEnvironment(): - """Return a dictionary with the environment variables - of the python interpreter""" === Zope3/lib/python/Zope/App/OFS/ApplicationControl/RuntimeInfo.py 1.1.2.1 => 1.1.2.2 === +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +__doc__ = """ Runtime Information + +$Id$""" + from Zope.App.OFS.ApplicationControl.IRuntimeInfo import IRuntimeInfo from Zope.App.OFS.ApplicationControl.IApplicationControl import IApplicationControl from Zope.ComponentArchitecture import getUtility @@ -30,6 +47,10 @@ 'See Zope.App.OFS.ApplicationControl.IRuntimeInfo.IRuntimeInfo' return sys.version + def getPythonPath(self): + 'See Zope.App.OFS.ApplicationControl.IRuntimeInfo.IRuntimeInfo' + return tuple(sys.path) + def getSystemPlatform(self): 'See Zope.App.OFS.ApplicationControl.IRuntimeInfo.IRuntimeInfo' return os.uname() @@ -45,10 +66,6 @@ def getUptime(self): 'See Zope.App.OFS.ApplicationControl.IRuntimeInfo.IRuntimeInfo' return time.time() - self.getContext().getStartTime() - - def getEnvironment(self): - 'See Zope.App.OFS.ApplicationControl.IRuntimeInfo.IRuntimeInfo' - return os.environ # ############################################################ From philikon@gmx.net Wed Apr 10 09:01:52 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 04:01:52 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl - IZopeVersion.py:1.1.2.2 Message-ID: <200204100801.g3A81qC21681@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl In directory cvs.zope.org:/tmp/cvs-serv21655 Modified Files: Tag: Zope-3x-branch IZopeVersion.py Log Message: Fixed doc string === Zope3/lib/python/Zope/App/OFS/ApplicationControl/IZopeVersion.py 1.1.2.1 => 1.1.2.2 === # ############################################################################## -__doc__ = """Zope version +__doc__ = """Zope version interface + $Id$""" from Interface import Interface From philikon@gmx.net Wed Apr 10 09:08:44 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 04:08:44 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security - ZopeSecurityPolicy.py:1.1.2.24 Message-ID: <200204100808.g3A88it23845@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Security In directory cvs.zope.org:/tmp/cvs-serv23664 Modified Files: Tag: Zope-3x-branch ZopeSecurityPolicy.py Log Message: Do not permission checks on tuples anymore === Zope3/lib/python/Zope/App/Security/ZopeSecurityPolicy.py 1.1.2.23 => 1.1.2.24 === __version__='$Revision$'[11:-2] -from types import StringType, TupleType - from Zope.ComponentArchitecture import getAdapter from Zope.ContextWrapper.ContainmentIterator import ContainmentIterator @@ -39,7 +37,7 @@ from Zope.App.Security.PrincipalRoleManager import principalRoleManager from Zope.App.Security.Settings import Allow, Deny, Assign, Remove, Unset -from types import StringTypes, ListType, IntType, MethodType, NoneType +from types import StringType, StringTypes, TupleType, ListType, IntType, MethodType, NoneType # XXX: hack alert from Zope.ContextWrapper import getbaseobject @@ -100,7 +98,7 @@ unwrapped_value = getbaseobject(value) - if (isinstance(unwrapped_value, (ListType, StringTypes, IntType, NoneType)) + if (isinstance(unwrapped_value, (ListType, TupleType, StringTypes, IntType, NoneType)) or getattr(value,'__allow_access_to_unprotected_subobjects__',0)): permission = 'Zope.Public' From srichter@cbu.edu Wed Apr 10 10:08:23 2002 From: srichter@cbu.edu (Stephan Richter) Date: Wed, 10 Apr 2002 05:08:23 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/Image/Views/VFS Zope3/lib/python/Zope/App/OFS/Content/Image/Views/VFS - New directory Message-ID: <200204100908.g3A98NR15052@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/Image/Views/VFS In directory cvs.zope.org:/tmp/cvs-serv15046/lib/python/Zope/App/OFS/Content/Image/Views/VFS Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/Image/Views/VFS added to the repository --> Using per-directory sticky tag `Zope3-Server-Branch' === Added directory Zope3/lib/python/Zope/App/OFS/Content/Image/Views/VFS === From srichter@cbu.edu Wed Apr 10 10:09:25 2002 From: srichter@cbu.edu (Stephan Richter) Date: Wed, 10 Apr 2002 05:09:25 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/File/Views/VFS Zope3/lib/python/Zope/App/OFS/Content/File/Views/VFS - New directory Message-ID: <200204100909.g3A99PJ15260@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File/Views/VFS In directory cvs.zope.org:/tmp/cvs-serv15254/lib/python/Zope/App/OFS/Content/File/Views/VFS Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File/Views/VFS added to the repository --> Using per-directory sticky tag `Zope3-Server-Branch' === Added directory Zope3/lib/python/Zope/App/OFS/Content/File/Views/VFS === From philikon@gmx.net Wed Apr 10 10:15:18 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 05:15:18 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views - __init__.py:1.1.2.1 views.zcml:1.1.2.1 Message-ID: <200204100915.g3A9FIA18238@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views In directory cvs.zope.org:/tmp/cvs-serv17624/Views Added Files: Tag: Zope-3x-branch __init__.py views.zcml Log Message: Added default view for ApplicationController showing runtime information, accessible through /ApplicationController;etc === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/__init__.py === === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/views.zcml === From philikon@gmx.net Wed Apr 10 10:15:18 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 05:15:18 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser - RuntimeInfoView.py:1.1.2.1 __init__.py:1.1.2.1 browser.zcml:1.1.2.1 runtimeinfo.pt:1.1.2.1 Message-ID: <200204100915.g3A9FIK18242@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv17624/Views/Browser Added Files: Tag: Zope-3x-branch RuntimeInfoView.py __init__.py browser.zcml runtimeinfo.pt Log Message: Added default view for ApplicationController showing runtime information, accessible through /ApplicationController;etc === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/RuntimeInfoView.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Define runtime information view component for Application Control $Id: RuntimeInfoView.py,v 1.1.2.1 2002/04/10 09:15:17 philikon Exp $ """ from Zope.Publisher.Browser.AttributePublisher import AttributePublisher from Zope.App.OFS.ApplicationControl.IRuntimeInfo import IRuntimeInfo from Zope.PageTemplate.PageTemplateFile import PageTemplateFile from Zope.ComponentArchitecture import getAdapter class RuntimeInfoView(AttributePublisher): def __init__(self, context): self._context = context def getContext(self): return self._context def runtimeInfo(self): runtime_info = getAdapter(self.getContext(), IRuntimeInfo) # XXX what are we going to do if this fails??? formatted = {} # contains formatted runtime information formatted['ZopeVersion'] = runtime_info.getZopeVersion() formatted['PythonVersion'] = runtime_info.getPythonVersion() formatted['PythonPath'] = runtime_info.getPythonPath() formatted['SystemPlatform'] = " ".join(runtime_info.getSystemPlatform()) formatted['CommandLine'] = " ".join(runtime_info.getCommandLine()) formatted['ProcessId'] = runtime_info.getProcessId() # make a unix "uptime" uptime format uptime = runtime_info.getUptime() days = int(uptime / (60*60*24)) uptime = uptime - days * (60*60*24) hours = int(uptime / (60*60)) uptime = uptime - hours * (60*60) minutes = int(uptime / 60) uptime = uptime - minutes * 60 seconds = uptime formatted['Uptime'] = "%s%02d:%02d:%02d" % (((days or "") and "%d days, " % days), hours, minutes, seconds) return formatted index = PageTemplateFile('runtimeinfo.pt') === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/__init__.py === === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/browser.zcml === === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/runtimeinfo.pt === Zope Runtime Information
  • Zope version:
  • Python version:
  • System platform:
  • Command line:
  • Process id:
  • Uptime:
  • Python path:
    • path
From philikon@gmx.net Wed Apr 10 10:15:18 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 05:15:18 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/tests - __init__.py:1.1.2.1 testRuntimeInfoView.py:1.1.2.1 Message-ID: <200204100915.g3A9FIc18247@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/tests In directory cvs.zope.org:/tmp/cvs-serv17624/Views/Browser/tests Added Files: Tag: Zope-3x-branch __init__.py testRuntimeInfoView.py Log Message: Added default view for ApplicationController showing runtime information, accessible through /ApplicationController;etc === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/tests/__init__.py === === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/tests/testRuntimeInfoView.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## from unittest import TestCase, TestSuite, main, makeSuite from Zope.App.OFS.ApplicationControl.ApplicationControl import ApplicationController from Zope.App.OFS.ApplicationControl.IApplicationControl import IApplicationControl from Zope.App.OFS.ApplicationControl.IRuntimeInfo import IRuntimeInfo from Zope.App.OFS.ApplicationControl.RuntimeInfo import RuntimeInfo from Zope.App.OFS.ApplicationControl.Views.Browser.RuntimeInfoView import RuntimeInfoView from Zope.ComponentArchitecture import provideAdapter from types import DictType class Test(TestCase): def _TestView__newView(self, container): return RuntimeInfoView(container) def test_RuntimeInfoView(self): provideAdapter(IApplicationControl, IRuntimeInfo, RuntimeInfo) test_runtimeinfoview = self._TestView__newView(ApplicationController) test_format = test_runtimeinfoview.runtimeInfo() self.assertEquals(type(test_format), DictType) assert_keys = ['ZopeVersion', 'PythonVersion', 'PythonPath', 'SystemPlatform', 'CommandLine', 'ProcessId', 'Uptime' ] test_keys = test_format.keys() self.failUnless(min([key in assert_keys for key in test_keys])) def test_suite(): return TestSuite(( makeSuite(Test), )) if __name__=='__main__': main(defaultTest='test_suite') From philikon@gmx.net Wed Apr 10 10:16:06 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 05:16:06 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS - ofs.zcml:1.1.2.14 Message-ID: <200204100916.g3A9G6f18930@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS In directory cvs.zope.org:/tmp/cvs-serv18820 Modified Files: Tag: Zope-3x-branch ofs.zcml Log Message: Added configuration for Application Controller === Zope3/lib/python/Zope/App/OFS/ofs.zcml 1.1.2.13 => 1.1.2.14 === + From philikon@gmx.net Wed Apr 10 10:16:06 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 05:16:06 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl - application-control.zcml:1.1.2.1 Message-ID: <200204100916.g3A9G6518931@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl In directory cvs.zope.org:/tmp/cvs-serv18820/ApplicationControl Added Files: Tag: Zope-3x-branch application-control.zcml Log Message: Added configuration for Application Controller === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/application-control.zcml === From srichter@cbu.edu Wed Apr 10 10:30:54 2002 From: srichter@cbu.edu (Stephan Richter) Date: Wed, 10 Apr 2002 05:30:54 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/File/Views/VFS - VFSFileView.py:1.1.2.1 __init__.py:1.1.2.1 vfs.zcml:1.1.2.1 Message-ID: <200204100930.g3A9Us325098@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File/Views/VFS In directory cvs.zope.org:/tmp/cvs-serv23463/lib/python/Zope/App/OFS/Content/File/Views/VFS Added Files: Tag: Zope3-Server-Branch VFSFileView.py __init__.py vfs.zcml Log Message: Okay, it finally works! We have a Publisher FTP server again. All the basic functionalitry is there, from dir listing, file transfer to security. I punted for now on recognizing file endings, since Jim wants to write a proposal for that next week. Also, I did not solve the statistical file information problem, since this takes some more research. === Added File Zope3/lib/python/Zope/App/OFS/Content/File/Views/VFS/VFSFileView.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: VFSFileView.py,v 1.1.2.1 2002/04/10 09:30:53 srichter Exp $ """ import time from Zope.Publisher.VFS.IVFSFilePublisher import IVFSFilePublisher class VFSFileView: __implements__ = IVFSFilePublisher def __init__(self, context): """ """ self._object = context ############################################################ # Implementation methods for interface # Zope.Publisher.VFS.IVFSFilePublisher. def read(self, mode, outstream, start = 0, end = -1): """See Zope.Publisher.VFS.IVFSFilePublisher.IVFSFilePublisher""" data = self._object.getData() try: if start != 0: data = data[start:] if end != -1: data = data[:end] except TypeError: pass outstream.write(data) def write(self, mode, instream, start = 0): """See Zope.Publisher.VFS.IVFSFilePublisher.IVFSFilePublisher""" try: instream.seek(start) except: pass self._object.setData(instream.read()) def check_writable(self, mode): """See Zope.Publisher.VFS.IVFSFilePublisher.IVFSFilePublisher""" return 1 ###################################### # from: Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher def isdir(self): """See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher""" return 0 def isfile(self): """See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher""" return 1 def stat(self): """See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher""" t = time.time() size = 0 if hasattr(self._object, 'getSize'): size = self._object.getSize() uid = 0 gid = 0 return (0, 0, 0, 0, uid, gid, size, t, t, t) ###################################### # from: Zope.Publisher.VFS.IVFSPublisher.IVFSPublisher def publishTraverse(self, request, name): """See Zope.Publisher.VFS.IVFSPublisher.IVFSPublisher""" return getattr(self, name) # ############################################################ === Added File Zope3/lib/python/Zope/App/OFS/Content/File/Views/VFS/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.2.1 2002/04/10 09:30:53 srichter Exp $ """ === Added File Zope3/lib/python/Zope/App/OFS/Content/File/Views/VFS/vfs.zcml === From srichter@cbu.edu Wed Apr 10 10:30:58 2002 From: srichter@cbu.edu (Stephan Richter) Date: Wed, 10 Apr 2002 05:30:58 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - CommonFTPActivityLogger.py:1.1.2.4 FTPServerChannel.py:1.1.2.20 IFTPCommandHandler.py:1.1.2.4 PublisherFTPServerChannel.py:1.1.2.2 Message-ID: <200204100930.g3A9UwX25156@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv23463/lib/python/Zope/Server/FTP Modified Files: Tag: Zope3-Server-Branch CommonFTPActivityLogger.py FTPServerChannel.py IFTPCommandHandler.py PublisherFTPServerChannel.py Log Message: Okay, it finally works! We have a Publisher FTP server again. All the basic functionalitry is there, from dir listing, file transfer to security. I punted for now on recognizing file endings, since Jim wants to write a proposal for that next week. Also, I did not solve the statistical file information problem, since this takes some more research. === Zope3/lib/python/Zope/Server/FTP/CommonFTPActivityLogger.py 1.1.2.3 => 1.1.2.4 === now = time.localtime(time.time()) - print now - self.output.log('127.0.0.1', time.strftime('%Y/%m/%d %H:%M', now)) + message = '%s [%s] "%s %s"' %(task.channel.username, + time.strftime('%Y/%m/%d %H:%M', now), + task.m_name[4:].upper(), + task.channel.cwd, + ) + + self.output.log('127.0.0.1', message) === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.19 => 1.1.2.20 === def cmd_mdtm(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' + # We simply do not understand this non-standard extension to MDTM + if len(args.split()) > 1: + self.reply('ERR_ARGS') + return path = self._generatePath(args) if not self._getFilesystem().isfile(path): self.reply('ERR_IS_NOT_FILE', path) @@ -347,11 +351,11 @@ def cmd_size(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' path = self._generatePath(args) - if not self._getFilesystem().isfile(path): + fs = self._getFilesystem() + if not fs.isfile(path): self.reply('ERR_NO_FILE', path) else: - self.reply('FILE_SIZE', self.server.openFilesystem( - self.username).stat(path)[stat.ST_SIZE]) + self.reply('FILE_SIZE', fs.stat(path)[stat.ST_SIZE]) def cmd_stor(self, args, write_mode='w'): @@ -371,7 +375,7 @@ # Verify the file can be opened, but don't open it yet. # The actually write should be transactional without # holding up the application. - fs = self.server.openFilesystem(self.username) + fs = self._getFilesystem() fs.check_writable(path, mode) except OSError, err: self.reply('ERR_OPEN_WRITE', str(err)) === Zope3/lib/python/Zope/Server/FTP/IFTPCommandHandler.py 1.1.2.3 => 1.1.2.4 === Example output: 213 19960301204320 + + Geez, there seems to be a second syntax for this fiel, where one + can also set the modification time using: + MDTM datestring pathname + """ def cmd_mkd(args): === Zope3/lib/python/Zope/Server/FTP/PublisherFTPServerChannel.py 1.1.2.1 => 1.1.2.2 === def authenticate(self): - # XXX We need to hook this up to the Zope security mechanism - return 1, 'All cool' + if self._getFilesystem()._authenticate(): + return 1, 'User successfully authenticated.' + else: + return 0, 'User could not be authenticated.' From srichter@cbu.edu Wed Apr 10 10:30:58 2002 From: srichter@cbu.edu (Stephan Richter) Date: Wed, 10 Apr 2002 05:30:58 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - PublisherFileSystem.py:1.1.2.7 PublisherVFSTask.py:NONE Message-ID: <200204100930.g3A9UwW25160@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv23463/lib/python/Zope/Server/VFS Modified Files: Tag: Zope3-Server-Branch PublisherFileSystem.py Removed Files: Tag: Zope3-Server-Branch PublisherVFSTask.py Log Message: Okay, it finally works! We have a Publisher FTP server again. All the basic functionalitry is there, from dir listing, file transfer to security. I punted for now on recognizing file endings, since Jim wants to write a proposal for that next week. Also, I did not solve the statistical file information problem, since this takes some more research. === Zope3/lib/python/Zope/Server/VFS/PublisherFileSystem.py 1.1.2.6 => 1.1.2.7 === from IWriteFileSystem import IWriteFileSystem +from Zope.App.Security.PrincipalRegistry import principalRegistry from Zope.Publisher.Publish import publish from ListProducer import ListProducer @@ -45,6 +46,13 @@ self.password = password + + def _create_request(self, env): + env['username'] = self.username + env['password'] = self.password + request = self.request_factory(StringIO(''), StringIO(), env) + return request + def _execute(self, path, command, env=None): if env is None: @@ -53,15 +61,23 @@ env['command'] = command env['path'] = path - # XXX integrate security somehow into the request - - request = self.request_factory(StringIO(''), StringIO(), env) - # XXX **** WHY IS THE REQUEST LOOSING ITS RESPONSE DURING PUBLISH? *** - resp = request._response + request = self._create_request(env) + # Note that publish() calls close() on request, which deletes the + # response from the request, so that we need to keep trakc of it. + response = request.getResponse() publish(request) - print resp.getResult() - return resp.getResult() + return response.getResult() + + def _authenticate(self): + request = self._create_request({}) + id = principalRegistry.authenticate(request) + if id is None: + return 0 + else: + return 1 + + ############################################################ # Implementation methods for interface @@ -70,6 +86,8 @@ def exists(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) + if path == '/': + return 1 path, file = os.path.split(path) env = {'name': file} return self._execute(path, 'exists', env) @@ -129,7 +147,7 @@ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' path = self.translate(path) path, name = os.path.split(path) - env = {'name': file} + env = {'name': name} return self._execute(path, 'remove', env) @@ -155,11 +173,12 @@ def writefile(self, path, mode, instream, start=0): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' path = self.translate(path) - env = {'mode' : mode, - 'outstream' : outstream, - 'start' : start, - 'end' : end} - return self._execute(path, 'write', env) + path, name = os.path.split(path) + env = {'name' : name, + 'mode' : mode, + 'instream' : instream, + 'start' : start} + return self._execute(path, 'writefile', env) def check_writable(self, path, mode): @@ -196,8 +215,8 @@ path = os.sep.join(path.split('/')) path = self.normalize(self.path_module.join(path)) # Prepare for joining with root - if path[0] == '/': - path = path[1:] + if not path.startswith('/'): + path = '/' + path return path === Removed File Zope3/lib/python/Zope/Server/VFS/PublisherVFSTask.py === From srichter@cbu.edu Wed Apr 10 10:31:22 2002 From: srichter@cbu.edu (Stephan Richter) Date: Wed, 10 Apr 2002 05:31:22 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/Views/VFS - VFSContainerView.py:1.1.2.3 Message-ID: <200204100931.g3A9VM825451@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Views/VFS In directory cvs.zope.org:/tmp/cvs-serv23463/lib/python/Zope/App/OFS/Container/Views/VFS Modified Files: Tag: Zope3-Server-Branch VFSContainerView.py Log Message: Okay, it finally works! We have a Publisher FTP server again. All the basic functionalitry is there, from dir listing, file transfer to security. I punted for now on recognizing file endings, since Jim wants to write a proposal for that next week. Also, I did not solve the statistical file information problem, since this takes some more research. === Zope3/lib/python/Zope/App/OFS/Container/Views/VFS/VFSContainerView.py 1.1.2.2 => 1.1.2.3 === """ import fnmatch +import time + +from Zope.ComponentArchitecture import getView +from Zope.Publisher.VFS.IVFSPublisher import IVFSPublisher + from Zope.Publisher.VFS.IVFSDirectoryPublisher import IVFSDirectoryPublisher +from Zope.App.OFS.Container.IContainer import IContainer +# XXX hard coded object types. +from Zope.App.OFS.Content.File.File import File +from Zope.App.OFS.Folder.Folder import Folder class VFSContainerView: @@ -40,6 +49,7 @@ def listdir(self, with_stats=0, pattern='*'): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' + t = time.time() file_list = self._container.objectIds() # filter them using the pattern file_list = list( @@ -48,19 +58,30 @@ # sort them alphabetically file_list.sort() if not with_stats: - result = ld + result = file_list else: result = [] for file in file_list: - stat = (16893, 0, 0, 0, 0, 0, 0, 0, 0, 0) + obj = self._container.getObject(file) + size = 0 + # XXX Should be much nicer + if IContainer.isImplementedBy(obj): + dir_mode = 16384 + else: + dir_mode = 0 + if hasattr(obj, 'getSize'): + size = obj.getSize() + stat = (dir_mode, 0, 0, 0, 0, 0, size, t, t, t) if stat is not None: result.append((file, stat)) return result - + def mkdir(self, name, mode=777): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' - pass + if not self._container.hasObject(name): + obj = Folder() + self._container.setObject(name, obj) def remove(self, name): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' @@ -77,6 +98,21 @@ self._container.setObject(new, obj) + def writefile(self, name, mode, instream, start=0): + 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' + # XXX This should become much, much smarter later. Based on the + # data and the file ending, it should pick the right object type. + # *** Waiting for Jim's file extension proposal and code to land *** + if not self._container.hasObject(name): + obj = File() + self._container.setObject(name, obj) + else: + obj = self._container.getObject(name) + + vfs_view = getView(obj, 'vfs', IVFSPublisher) + vfs_view.write(mode, instream, start) + + ###################################### # from: Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher @@ -90,7 +126,11 @@ def stat(self): 'See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher' - return (16893, 0, 0, 0, 0, 0, 0, 0, 0, 0) + dir_mode = 16384 + t = time.time() + uid = 0 + gid = 0 + return (dir_mode+0, 0, 0, 0, uid, gid, 4096, t, t, t) ###################################### @@ -102,8 +142,3 @@ # ############################################################ - - - def getContext(self): - """ """ - return self._container From srichter@cbu.edu Wed Apr 10 10:31:23 2002 From: srichter@cbu.edu (Stephan Richter) Date: Wed, 10 Apr 2002 05:31:23 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/File - File.py:1.1.2.5.2.1 NaiveFile.py:1.1.2.3.2.1 Message-ID: <200204100931.g3A9VNe25455@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File In directory cvs.zope.org:/tmp/cvs-serv23463/lib/python/Zope/App/OFS/Content/File Modified Files: Tag: Zope3-Server-Branch File.py NaiveFile.py Log Message: Okay, it finally works! We have a Publisher FTP server again. All the basic functionalitry is there, from dir listing, file transfer to security. I punted for now on recognizing file endings, since Jim wants to write a proposal for that next week. Also, I did not solve the statistical file information problem, since this takes some more research. === Zope3/lib/python/Zope/App/OFS/Content/File/File.py 1.1.2.5 => 1.1.2.5.2.1 === - def __init__(self, data=None, contentType=None): + def __init__(self, data='', contentType=None): """ """ self.setData(data) === Zope3/lib/python/Zope/App/OFS/Content/File/NaiveFile.py 1.1.2.3 => 1.1.2.3.2.1 === - def __init__(self, data=None, contentType=None): + def __init__(self, data='', contentType=None): """ """ self.setData(data) From srichter@cbu.edu Wed Apr 10 10:31:24 2002 From: srichter@cbu.edu (Stephan Richter) Date: Wed, 10 Apr 2002 05:31:24 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/File/Views - views.zcml:1.1.2.1.6.1 Message-ID: <200204100931.g3A9VOw25458@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File/Views In directory cvs.zope.org:/tmp/cvs-serv23463/lib/python/Zope/App/OFS/Content/File/Views Modified Files: Tag: Zope3-Server-Branch views.zcml Log Message: Okay, it finally works! We have a Publisher FTP server again. All the basic functionalitry is there, from dir listing, file transfer to security. I punted for now on recognizing file endings, since Jim wants to write a proposal for that next week. Also, I did not solve the statistical file information problem, since this takes some more research. === Zope3/lib/python/Zope/App/OFS/Content/File/Views/views.zcml 1.1.2.1 => 1.1.2.1.6.1 === - xmlns='http://namespaces.zope.org/zope' -> - - - - - \ No newline at end of file + + + + + + + From srichter@cbu.edu Wed Apr 10 10:31:25 2002 From: srichter@cbu.edu (Stephan Richter) Date: Wed, 10 Apr 2002 05:31:25 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security - BasicVFSAuthAdapter.py:1.1.2.1 security.zcml:1.1.2.3.6.1 Message-ID: <200204100931.g3A9VP625461@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Security In directory cvs.zope.org:/tmp/cvs-serv23463/lib/python/Zope/App/Security Modified Files: Tag: Zope3-Server-Branch security.zcml Added Files: Tag: Zope3-Server-Branch BasicVFSAuthAdapter.py Log Message: Okay, it finally works! We have a Publisher FTP server again. All the basic functionalitry is there, from dir listing, file transfer to security. I punted for now on recognizing file endings, since Jim wants to write a proposal for that next week. Also, I did not solve the statistical file information problem, since this takes some more research. === Added File Zope3/lib/python/Zope/App/Security/BasicVFSAuthAdapter.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## # HTTP Basic Authentication adapter from Zope.Publisher.VFS.IVFSCredentials import IVFSCredentials from LoginPassword import LoginPassword class BasicVFSAuthAdapter(LoginPassword): __used_for__ = IVFSCredentials __request = None def __init__(self, request): self.__request = request # XXX base64 decoding should be done here, not in request lpw = request._authUserPW() if lpw is None: login, password = None, None else: login, password = lpw LoginPassword.__init__(self, login, password) def needLogin(self, realm): self.__request.unauthorized("Did not work") === Zope3/lib/python/Zope/App/Security/security.zcml 1.1.2.3 => 1.1.2.3.6.1 === for="Zope.Publisher.HTTP.IHTTPCredentials." /> + From srichter@cbu.edu Wed Apr 10 10:31:27 2002 From: srichter@cbu.edu (Stephan Richter) Date: Wed, 10 Apr 2002 05:31:27 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/VFS - IVFSCredentials.py:1.1.2.1 IVFSDirectoryPublisher.py:1.1.2.3 VFSRequest.py:1.1.2.3 Message-ID: <200204100931.g3A9VRC25465@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/VFS In directory cvs.zope.org:/tmp/cvs-serv23463/lib/python/Zope/Publisher/VFS Modified Files: Tag: Zope3-Server-Branch IVFSDirectoryPublisher.py VFSRequest.py Added Files: Tag: Zope3-Server-Branch IVFSCredentials.py Log Message: Okay, it finally works! We have a Publisher FTP server again. All the basic functionalitry is there, from dir listing, file transfer to security. I punted for now on recognizing file endings, since Jim wants to write a proposal for that next week. Also, I did not solve the statistical file information problem, since this takes some more research. === Added File Zope3/lib/python/Zope/Publisher/VFS/IVFSCredentials.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IVFSCredentials.py,v 1.1.2.1 2002/04/10 09:30:54 srichter Exp $ """ from Interface import Interface class IVFSCredentials(Interface): # XXX Eventially this will be a different method def _authUserPW(): """Return (login, password) if there are basic credentials; return None if there aren't.""" def unauthorized(challenge): """Issue a 401 Unauthorized error (asking for login/password). The challenge is the value of the WWW-Authenticate header.""" === Zope3/lib/python/Zope/Publisher/VFS/IVFSDirectoryPublisher.py 1.1.2.2 => 1.1.2.3 === """Rename an object from old name to new name. """ + + def writefile(name, mode, instream, start=0): + """Write a file to the container. If the object does not exist, + inspect the content and the file name to create the right object + type. + """ === Zope3/lib/python/Zope/Publisher/VFS/VFSRequest.py 1.1.2.2 => 1.1.2.3 === from Zope.Publisher.BaseRequest import BaseRequest from IVFSPublisher import IVFSPublisher +from IVFSCredentials import IVFSCredentials from VFSResponse import VFSResponse class VFSRequest(BaseRequest): - __implements__ = BaseRequest.__implements__ + __implements__ = BaseRequest.__implements__, IVFSCredentials # _viewtype is overridden from the BaseRequest # to implement IVFSPublisher @@ -43,6 +44,21 @@ """Create a specific XML-RPC response object.""" return VFSResponse(outstream) + + ############################################################ + # Implementation methods for interface + # Zope.Publisher.VFS.IVFSCredentials. + + def _authUserPW(self): + 'See Zope.Publisher.VFS.IVFSCredentials.IVFSCredentials' + env = self._environ + return env['username'], env['password'] + + def unauthorized(self, challenge): + 'See Zope.Publisher.VFS.IVFSCredentials.IVFSCredentials' + pass + # + ############################################################ ###################################### # from: Zope.Publisher.IPublisherRequest.IPublisherRequest From philikon@gmx.net Wed Apr 10 12:09:17 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 07:09:17 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests - testRuntimeInfo.py:1.1.2.3 Message-ID: <200204101109.g3AB9Hm01167@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests In directory cvs.zope.org:/tmp/cvs-serv945/OFS/ApplicationControl/tests Modified Files: Tag: Zope-3x-branch testRuntimeInfo.py Log Message: Time may only differ by 2 seconds (still seems a _long_ period for computers, though) === Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests/testRuntimeInfo.py 1.1.2.2 => 1.1.2.3 === # seconds, time values may differ in order to be assumed equal -time_tolerance = 3 +time_tolerance = 2 stupid_version_string = "3085t0klvn93850voids" class TestZopeVersion: From philikon@gmx.net Wed Apr 10 12:10:16 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 07:10:16 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests - testZopeVersion.py:1.1.2.2 Message-ID: <200204101110.g3ABAGV01769@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests In directory cvs.zope.org:/tmp/cvs-serv1664/OFS/ApplicationControl/tests Modified Files: Tag: Zope-3x-branch testZopeVersion.py Log Message: Verify that class implements interface === Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests/testZopeVersion.py 1.1.2.1 => 1.1.2.2 === from unittest import TestCase, TestSuite, main, makeSuite +from Interface.Verify import verifyObject + from Zope.App.OFS.ApplicationControl.IZopeVersion import IZopeVersion from Zope.App.OFS.ApplicationControl.ZopeVersion import ZopeVersion import os @@ -38,7 +40,7 @@ def _Test__new(self): return ZopeVersion() - + def _getZopeVersion(self): """example zope version implementation """ @@ -70,6 +72,9 @@ version = "%s%s" % (version_id, version_tag) return version + + def test_IVerify(self): + verifyObject(IZopeVersion, self._Test__new()) def test_ZopeVersion(self): zope_version = self._Test__new() From philikon@gmx.net Wed Apr 10 12:19:00 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 07:19:00 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS - ofs-meta.zcml:1.1.2.1 Message-ID: <200204101119.g3ABJ0w05794@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS In directory cvs.zope.org:/tmp/cvs-serv5379/App/OFS Added Files: Tag: Zope-3x-branch ofs-meta.zcml Log Message: Made ApplicationControl pluggable; plugins are views for the ApplicationController instance === Added File Zope3/lib/python/Zope/App/OFS/ofs-meta.zcml === From philikon@gmx.net Wed Apr 10 12:19:01 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 07:19:01 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser - ApplicationControlView.py:1.1.2.1 index.pt:1.1.2.1 browser.zcml:1.1.2.2 Message-ID: <200204101119.g3ABJ1C05829@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv5379/App/OFS/ApplicationControl/Views/Browser Modified Files: Tag: Zope-3x-branch browser.zcml Added Files: Tag: Zope-3x-branch ApplicationControlView.py index.pt Log Message: Made ApplicationControl pluggable; plugins are views for the ApplicationController instance === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/ApplicationControlView.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: ApplicationControlView.py,v 1.1.2.1 2002/04/10 11:18:59 philikon Exp $ """ from Zope.PageTemplate import SimpleViewClass from Zope.App.OFS.ApplicationControl.IApplicationControl import IApplicationControl ApplicationControlView = SimpleViewClass('index.pt', used_for=IApplicationControl) === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/index.pt === Zope Application Controller === Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/browser.zcml 1.1.2.1 => 1.1.2.2 === xmlns:security='http://namespaces.zope.org/security' xmlns:browser='http://namespaces.zope.org/browser' + xmlns:application-control='http://namespaces.zope.org/application-control' > + + + + + + + + + + From philikon@gmx.net Wed Apr 10 12:19:01 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 07:19:01 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests - testApplicationControl.py:1.1.2.1 Message-ID: <200204101119.g3ABJ1C05834@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests In directory cvs.zope.org:/tmp/cvs-serv5379/App/OFS/ApplicationControl/tests Added Files: Tag: Zope-3x-branch testApplicationControl.py Log Message: Made ApplicationControl pluggable; plugins are views for the ApplicationController instance === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests/testApplicationControl.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. ############################################################################## """ $Id: testApplicationControl.py,v 1.1.2.1 2002/04/10 11:19:00 philikon Exp $ """ from unittest import TestCase, TestSuite, main, makeSuite from Interface.Verify import verifyObject import time from Zope.ComponentArchitecture import getUtility, provideUtility from Zope.App.OFS.ApplicationControl.ApplicationControl import ApplicationControl from Zope.App.OFS.ApplicationControl.IApplicationControl import IApplicationControl # seconds, time values may differ in order to be assumed equal time_tolerance = 2 ############################################################################# # If your tests change any global registries, then uncomment the # following import and include CleanUp as a base class of your # test. It provides a setUp and tearDown that clear global data that # has registered with the test cleanup framework. Don't use this # tests outside the Zope package. # from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup ############################################################################# class Test(TestCase): def _Test__new(self): return ApplicationControl() ############################################################ # Interface-driven tests: def test_IVerifIVerify(self): verifyObject(IApplicationControl, self._Test__new()) def test_startTime(self): assert_time = time.time() test_time = self._Test__new().getStartTime() self.failUnless(abs(assert_time - test_time) < time_tolerance) def test_plugins(self): test_appctrl = self._Test__new() assert_info = [ {'name':'foo', 'title':'I\'m a lumberjack'}, {'name':'bar', 'title':'and i feel fine.'}, {'name':'nudges', 'title':'The nudge'}, {'name':'dash', 'title':'The dash'}] for info in assert_info: test_appctrl.registerView(info['name'], info['title']) self.failUnless(min([info in assert_info for info in test_appctrl.getListOfViews()])) def test_suite(): return TestSuite(( makeSuite(Test), )) if __name__=='__main__': main(defaultTest='test_suite') From philikon@gmx.net Wed Apr 10 12:19:31 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 07:19:31 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl - application-control-meta.zcml:1.1.2.1 metaConfigure.py:1.1.2.1 ApplicationControl.py:1.1.2.5 IApplicationControl.py:1.1.2.4 Message-ID: <200204101119.g3ABJVE05982@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl In directory cvs.zope.org:/tmp/cvs-serv5379/App/OFS/ApplicationControl Modified Files: Tag: Zope-3x-branch ApplicationControl.py IApplicationControl.py Added Files: Tag: Zope-3x-branch application-control-meta.zcml metaConfigure.py Log Message: Made ApplicationControl pluggable; plugins are views for the ApplicationController instance === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/application-control-meta.zcml === === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/metaConfigure.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ Register Application Control configuration directives. $Id: metaConfigure.py,v 1.1.2.1 2002/04/10 11:18:59 philikon Exp $ """ from ApplicationControl import ApplicationController from Zope.Configuration.Action import Action def registerView(_context, name, title): return [ Action( discriminator = ('application-control:registerView', name), callable = ApplicationController.registerView, args = (name, title), ) ] === Zope3/lib/python/Zope/App/OFS/ApplicationControl/ApplicationControl.py 1.1.2.4 => 1.1.2.5 === def __init__(self): self.start_time = time.time() + self._views = [] ############################################################ # Implementation methods for interface @@ -34,6 +35,14 @@ def getStartTime(self): 'See Zope.App.OFS.ApplicationControl.IApplicationControl.IApplicationControl' return self.start_time + + def registerView(self, name, title): + 'See Zope.App.OFS.ApplicationControl.IApplicationControl.IApplicationControl' + self._views.append({'name': name, 'title': title}) + + def getListOfViews(self): + 'See Zope.App.OFS.ApplicationControl.IApplicationControl.IApplicationControl' + return tuple(self._views) # ############################################################ === Zope3/lib/python/Zope/App/OFS/ApplicationControl/IApplicationControl.py 1.1.2.3 => 1.1.2.4 === """Return the time when the ApplicationControl object has been instanciated in seconds since the epoch""" + + def registerView(name, title): + """Register a view called to be displayed in ApplicationControl + """ + + def getListOfViews(): + """Return a sequence containing dictionaries with the registered views' names + and titles mapped with the keys 'name' and 'title'""" From philikon@gmx.net Wed Apr 10 12:19:29 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 07:19:29 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App - app-meta.zcml:1.1.2.3 Message-ID: <200204101119.g3ABJTm05968@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App In directory cvs.zope.org:/tmp/cvs-serv5379/App Modified Files: Tag: Zope-3x-branch app-meta.zcml Log Message: Made ApplicationControl pluggable; plugins are views for the ApplicationController instance === Zope3/lib/python/Zope/App/app-meta.zcml 1.1.2.2 => 1.1.2.3 === + From philikon@gmx.net Wed Apr 10 12:27:07 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 07:27:07 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/tests - testRuntimeInfoView.py:1.1.2.2 Message-ID: <200204101127.g3ABR7G09507@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/tests In directory cvs.zope.org:/tmp/cvs-serv9362/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/tests Modified Files: Tag: Zope-3x-branch testRuntimeInfoView.py Log Message: Fixes to conform with style guides === Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/tests/testRuntimeInfoView.py 1.1.2.1 => 1.1.2.2 === provideAdapter(IApplicationControl, IRuntimeInfo, RuntimeInfo) test_runtimeinfoview = self._TestView__newView(ApplicationController) + test_format = test_runtimeinfoview.runtimeInfo() - self.assertEquals(type(test_format), DictType) + self.failUnless(isinstance(test_format, DictType)) + assert_keys = ['ZopeVersion', 'PythonVersion', 'PythonPath', 'SystemPlatform', 'CommandLine', 'ProcessId', 'Uptime' ] test_keys = test_format.keys() self.failUnless(min([key in assert_keys for key in test_keys])) From philikon@gmx.net Wed Apr 10 12:27:07 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 07:27:07 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests - testZopeVersion.py:1.1.2.3 Message-ID: <200204101127.g3ABR7Q09513@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests In directory cvs.zope.org:/tmp/cvs-serv9362/lib/python/Zope/App/OFS/ApplicationControl/tests Modified Files: Tag: Zope-3x-branch testZopeVersion.py Log Message: Fixes to conform with style guides === Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests/testZopeVersion.py 1.1.2.2 => 1.1.2.3 === f = open(tagfile) tag = f.read() - if tag[0] == "T": + if tag.startswith("T"): version_tag = " (%s)" % tag[1:-1] # try to get official Zope release information From philikon@gmx.net Wed Apr 10 12:27:37 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 07:27:37 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl - ZopeVersion.py:1.1.2.3 Message-ID: <200204101127.g3ABRbp09655@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl In directory cvs.zope.org:/tmp/cvs-serv9362/lib/python/Zope/App/OFS/ApplicationControl Modified Files: Tag: Zope-3x-branch ZopeVersion.py Log Message: Fixes to conform with style guides === Zope3/lib/python/Zope/App/OFS/ApplicationControl/ZopeVersion.py 1.1.2.2 => 1.1.2.3 === f = open(tagfile) tag = f.read() - if tag[0] == "T": + if tag.startswith("T"): version_tag = " (%s)" % tag[1:-1] # try to get official Zope release information From philikon@gmx.net Wed Apr 10 12:30:57 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 07:30:57 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser - browser.zcml:1.1.2.3 Message-ID: <200204101130.g3ABUvJ11231@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv10714 Modified Files: Tag: Zope-3x-branch browser.zcml Log Message: Just register one default view (the right one, of course) === Zope3/lib/python/Zope/App/OFS/ApplicationControl/Views/Browser/browser.zcml 1.1.2.2 => 1.1.2.3 === - From philikon@gmx.net Wed Apr 10 13:37:05 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 08:37:05 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests - testApplicationControl.py:1.1.2.2 Message-ID: <200204101237.g3ACb5i05663@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests In directory cvs.zope.org:/tmp/cvs-serv5583 Modified Files: Tag: Zope-3x-branch testApplicationControl.py Log Message: Fixed typo === Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests/testApplicationControl.py 1.1.2.1 => 1.1.2.2 === # Interface-driven tests: - def test_IVerifIVerify(self): + def test_IVerify(self): verifyObject(IApplicationControl, self._Test__new()) def test_startTime(self): From tdickenson@geminidataloggers.com Wed Apr 10 13:42:30 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Wed, 10 Apr 2002 08:42:30 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - ProductContext.py:1.38.36.2 Message-ID: <200204101242.g3ACgUZ07781@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv7772/lib/python/App Modified Files: Tag: toby-metatype-branch ProductContext.py Log Message: more precise comment === Zope/lib/python/App/ProductContext.py 1.38.36.1 => 1.38.36.2 === container_filter -- function that is called with an ObjectManager object as the only parameter, which should return a true object - if the object is happy to be created in that container. + if the object is happy to be created in that container. The + filter is called before showing ObjectManager's Add list, + and before pasting (after object copy or cut), but not + before calling an object's constructor. """ app=self.__app From philikon@gmx.net Wed Apr 10 14:54:05 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 09:54:05 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher - BaseRequest.py:1.1.2.27 RequestDataProperty.py:1.1.4.4 Message-ID: <200204101354.g3ADs5o06772@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher In directory cvs.zope.org:/tmp/cvs-serv6608/lib/python/Zope/Publisher Modified Files: Tag: Zope-3x-branch BaseRequest.py RequestDataProperty.py Log Message: Extended Interface IReadMapping with the has_key() method and updated the corresponding implementations and tests. === Zope3/lib/python/Zope/Publisher/BaseRequest.py 1.1.2.26 => 1.1.2.27 === return default - + + def has_key(self, key): + 'See Interface.Common.Mapping.IReadMapping' + lookup = self.get(key, self) + return lookup is not self + # ############################################################ === Zope3/lib/python/Zope/Publisher/RequestDataProperty.py 1.1.4.3 => 1.1.4.4 === """ +from Interface.Common.Mapping import IReadMapping, IEnumerableMapping + class RequestDataGetter(object): + __implements__ = IReadMapping + def __init__(self, request): self.__get = getattr(request, self._gettrname) @@ -27,9 +31,16 @@ def get(self, name, default=None): return self.__get(name, default) + + def has_key(self, key): + lookup = self.get(key, self) + return lookup is not self + class RequestDataMapper(object): + __implements__ = IEnumerableMapping + def __init__(self, request): self.__map = getattr(request, self._mapname) @@ -38,6 +49,10 @@ def get(self, name, default=None): return self.__map.get(name, default) + + def has_key(self, key): + lookup = self.get(key, self) + return lookup is not self def keys(self): return self.__map.keys() def items(self): return self.__map.items() From philikon@gmx.net Wed Apr 10 14:54:05 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 09:54:05 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Interface/Common/tests - BaseTestMapping.py:1.1.4.3 Message-ID: <200204101354.g3ADs5206763@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Interface/Common/tests In directory cvs.zope.org:/tmp/cvs-serv6608/lib/python/Interface/Common/tests Modified Files: Tag: Zope-3x-branch BaseTestMapping.py Log Message: Extended Interface IReadMapping with the has_key() method and updated the corresponding implementations and tests. === Zope3/lib/python/Interface/Common/tests/BaseTestMapping.py 1.1.4.2 => 1.1.4.3 === self.assertEqual(inst[key], state[key]) self.assertEqual(inst.get(key, None), state[key]) + self.failUnless(inst.has_key(key)) for key in absent: self.assertEqual(inst.get(key, None), None) @@ -73,6 +74,8 @@ absent = self._IReadMapping__absentKeys() testIReadMapping(self, inst, state, absent) + + class BaseTestIEnumerableMapping(BaseTestIReadMapping): From philikon@gmx.net Wed Apr 10 14:54:34 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 09:54:34 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Interface/Common - Mapping.py:1.1.2.5 Message-ID: <200204101354.g3ADsYt07184@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Interface/Common In directory cvs.zope.org:/tmp/cvs-serv6608/lib/python/Interface/Common Modified Files: Tag: Zope-3x-branch Mapping.py Log Message: Extended Interface IReadMapping with the has_key() method and updated the corresponding implementations and tests. === Zope3/lib/python/Interface/Common/Mapping.py 1.1.2.4 => 1.1.2.5 === """ + def has_key(key): + """Tell if a key exists in the mapping + """ + class IEnumerableMapping(IReadMapping): """Mapping objects whose items can be enumerated """ From casey@zope.com Wed Apr 10 15:22:25 2002 From: casey@zope.com (Casey Duncan) Date: Wed, 10 Apr 2002 10:22:25 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security/Management/Views Zope3/lib/python/Zope/App/Security/Management/Views - New directory Message-ID: <200204101422.g3AEMP527300@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Security/Management/Views In directory cvs.zope.org:/tmp/cvs-serv27283/Views Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/Security/Management/Views added to the repository --> Using per-directory sticky tag `casey-security-reorg-branch' === Added directory Zope3/lib/python/Zope/App/Security/Management/Views === From casey@zope.com Wed Apr 10 15:23:12 2002 From: casey@zope.com (Casey Duncan) Date: Wed, 10 Apr 2002 10:23:12 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security/Management/Views/Browser Zope3/lib/python/Zope/App/Security/Management/Views/Browser - New directory Message-ID: <200204101423.g3AENCb27560@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Security/Management/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv27552/Browser Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/Security/Management/Views/Browser added to the repository --> Using per-directory sticky tag `casey-security-reorg-branch' === Added directory Zope3/lib/python/Zope/App/Security/Management/Views/Browser === From philikon@gmx.net Wed Apr 10 15:33:59 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 10:33:59 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/tests Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/tests - New directory Message-ID: <200204101433.g3AEXxJ31829@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/tests In directory cvs.zope.org:/tmp/cvs-serv31803/ServerControl/tests Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/tests added to the repository --> Using per-directory sticky tag `Zope-3x-branch' === Added directory Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/tests === From philikon@gmx.net Wed Apr 10 15:33:59 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 10:33:59 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl - New directory Message-ID: <200204101433.g3AEXxD31824@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl In directory cvs.zope.org:/tmp/cvs-serv31803/ServerControl Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl added to the repository --> Using per-directory sticky tag `Zope-3x-branch' === Added directory Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl === From philikon@gmx.net Wed Apr 10 15:38:03 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 10:38:03 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser/tests Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser/tests - New directory Message-ID: <200204101438.g3AEc3901314@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser/tests In directory cvs.zope.org:/tmp/cvs-serv1251/Views/Browser/tests Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser/tests added to the repository --> Using per-directory sticky tag `Zope-3x-branch' === Added directory Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser/tests === From philikon@gmx.net Wed Apr 10 15:38:02 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 10:38:02 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views - New directory Message-ID: <200204101438.g3AEc2U01297@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views In directory cvs.zope.org:/tmp/cvs-serv1251/Views Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views added to the repository --> Using per-directory sticky tag `Zope-3x-branch' === Added directory Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views === From philikon@gmx.net Wed Apr 10 15:38:03 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 10:38:03 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser - New directory Message-ID: <200204101438.g3AEc3L01304@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv1251/Views/Browser Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser added to the repository --> Using per-directory sticky tag `Zope-3x-branch' === Added directory Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser === From philikon@gmx.net Wed Apr 10 15:41:56 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 10:41:56 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views - __init__.py:1.1.2.1 views.zcml:1.1.2.1 Message-ID: <200204101441.g3AEfuV02968@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views In directory cvs.zope.org:/tmp/cvs-serv2399/ServerControl/Views Added Files: Tag: Zope-3x-branch __init__.py views.zcml Log Message: Added a plugin for ApplicationControl for shutting down and restarting the server. There is no implementation available yet, though. === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/__init__.py === === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/views.zcml === From philikon@gmx.net Wed Apr 10 15:41:56 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 10:41:56 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl - IServerControl.py:1.1.2.1 StubServerControl.py:1.1.2.1 __init__.py:1.1.2.1 server-control.zcml:1.1.2.1 Message-ID: <200204101441.g3AEfuN02965@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl In directory cvs.zope.org:/tmp/cvs-serv2399/ServerControl Added Files: Tag: Zope-3x-branch IServerControl.py StubServerControl.py __init__.py server-control.zcml Log Message: Added a plugin for ApplicationControl for shutting down and restarting the server. There is no implementation available yet, though. === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/IServerControl.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## __doc__ = """ Revision information: $Id: IServerControl.py,v 1.1.2.1 2002/04/10 14:41:55 philikon Exp $ Server Control Interface """ from Interface import Interface class IServerControl(Interface): """Server Control Interface defines methods for shutting down and restarting the server.""" def shutdown(): """Shutdown the server gracefully """ def restart(): """Restart the server gracefully """ === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/StubServerControl.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## __doc__ = """ Revision information: $Id: StubServerControl.py,v 1.1.2.1 2002/04/10 14:41:55 philikon Exp $ Stupid Server Control """ from Zope.App.OFS.ApplicationControl.ServerControl.IServerControl import IServerControl class StubServerControl: __implements__ = IServerControl ############################################################ # Implementation methods for interface # Zope.App.OFS.ApplicationControl.ServerControl.IServerControl. def shutdown(self): 'See Zope.App.OFS.ApplicationControl.ServerControl.IServerControl.IServerControl' def restart(self): 'See Zope.App.OFS.ApplicationControl.ServerControl.IServerControl.IServerControl' # ############################################################ StubServerController = StubServerControl() === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/__init__.py === === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/server-control.zcml === From philikon@gmx.net Wed Apr 10 15:41:56 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 10:41:56 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser - ServerControlView.py:1.1.2.1 __init__.py:1.1.2.1 browser.zcml:1.1.2.1 server-control.pt:1.1.2.1 Message-ID: <200204101441.g3AEfuJ02984@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser In directory cvs.zope.org:/tmp/cvs-serv2399/ServerControl/Views/Browser Added Files: Tag: Zope-3x-branch ServerControlView.py __init__.py browser.zcml server-control.pt Log Message: Added a plugin for ApplicationControl for shutting down and restarting the server. There is no implementation available yet, though. === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser/ServerControlView.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Provides a view for IServerControl $Id: ServerControlView.py,v 1.1.2.1 2002/04/10 14:41:55 philikon Exp $ """ from Zope.Publisher.Browser.AttributePublisher import AttributePublisher from Zope.PageTemplate.PageTemplateFile import PageTemplateFile from Zope.App.OFS.ApplicationControl.ServerControl.IServerControl import IServerControl from Zope.ComponentArchitecture import getUtility class ServerControlView(AttributePublisher): def __init__(self, context): self._context = context def getContext(self): return self._context def serverControl(self): return getUtility(self.getContext(), IServerControl) # XXX what are we going to do if this fails??? def action(self, REQUEST=None): if REQUEST.has_key('restart'): self.serverControl().restart() elif REQUEST.has_key('shutdown'): self.serverControl().shutdown() index = PageTemplateFile('server-control.pt') === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser/__init__.py === === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser/browser.zcml === === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser/server-control.pt === Zope Stub Server Controller


From philikon@gmx.net Wed Apr 10 15:41:57 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 10:41:57 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/tests - __init__.py:1.1.2.1 testIServerControl.py:1.1.2.1 Message-ID: <200204101441.g3AEfvx02991@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/tests In directory cvs.zope.org:/tmp/cvs-serv2399/ServerControl/tests Added Files: Tag: Zope-3x-branch __init__.py testIServerControl.py Log Message: Added a plugin for ApplicationControl for shutting down and restarting the server. There is no implementation available yet, though. === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/tests/__init__.py === === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/tests/testIServerControl.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. ############################################################################## """ $Id: testIServerControl.py,v 1.1.2.1 2002/04/10 14:41:56 philikon Exp $ """ from unittest import TestCase, TestSuite, main, makeSuite from Interface.Verify import verifyObject from Zope.ComponentArchitecture import getUtility, provideUtility from Zope.App.OFS.ApplicationControl.ServerControl.IServerControl import IServerControl ############################################################################# # If your tests change any global registries, then uncomment the # following import and include CleanUp as a base class of your # test. It provides a setUp and tearDown that clear global data that # has registered with the test cleanup framework. Don't use this # tests outside the Zope package. # from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup ############################################################################# class BaseTestIServerControl: """Base test cases for ServerControllers. Subclasses need to define a method, '_Test__new', that takes no arguments and that returns a new empty test ServerController. """ ############################################################ # Interface-driven tests: def test_IVerify(self): verifyObject(IServerControl, self._Test__new()) class Test(BaseTestIServerControl, TestCase): def _Test__new(self): from Zope.App.OFS.ApplicationControl.ServerControl.StubServerControl import StubServerControl return StubServerControl() def test_suite(): return TestSuite(( makeSuite(Test), )) if __name__=='__main__': main(defaultTest='test_suite') From philikon@gmx.net Wed Apr 10 15:41:57 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 10:41:57 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser/tests - __init__.py:1.1.2.1 testServerControlView.py:1.1.2.1 Message-ID: <200204101441.g3AEfvE02987@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser/tests In directory cvs.zope.org:/tmp/cvs-serv2399/ServerControl/Views/Browser/tests Added Files: Tag: Zope-3x-branch __init__.py testServerControlView.py Log Message: Added a plugin for ApplicationControl for shutting down and restarting the server. There is no implementation available yet, though. === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser/tests/__init__.py === === Added File Zope3/lib/python/Zope/App/OFS/ApplicationControl/ServerControl/Views/Browser/tests/testServerControlView.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## from unittest import TestCase, TestSuite, main, makeSuite from Zope.App.OFS.ApplicationControl.ApplicationControl import ApplicationController from Zope.App.OFS.ApplicationControl.ServerControl.IServerControl import IServerControl from Zope.App.OFS.ApplicationControl.ServerControl.Views.Browser.ServerControlView import ServerControlView from Zope.App.OFS.ApplicationControl.ServerControl.StubServerControl import StubServerControl from Zope.ComponentArchitecture import provideUtility class Test(TestCase): def _TestView__newView(self, container): return ServerControlView(container) def test_ServerControlView(self): provideUtility(IServerControl, StubServerControl()) test_serverctrl = self._TestView__newView(ApplicationController) test_shutdown = {'shutdown': 1} test_restart = {'restart': 1} # Testing shutdown and restart is somewhat tricky ;), we only want to # see that the methods return None as we specified that they may not # return anything. # XXX May actual 'correct' implementations break this test as it tries # to restart zope ??? self.assertEqual(test_serverctrl.action(REQUEST=test_shutdown), None) self.assertEqual(test_serverctrl.action(REQUEST=test_restart), None) def test_suite(): return TestSuite(( makeSuite(Test), )) if __name__=='__main__': main(defaultTest='test_suite') From philikon@gmx.net Wed Apr 10 15:42:25 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Wed, 10 Apr 2002 10:42:25 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl - application-control.zcml:1.1.2.2 Message-ID: <200204101442.g3AEgPJ03075@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl In directory cvs.zope.org:/tmp/cvs-serv2399 Modified Files: Tag: Zope-3x-branch application-control.zcml Log Message: Added a plugin for ApplicationControl for shutting down and restarting the server. There is no implementation available yet, though. === Zope3/lib/python/Zope/App/OFS/ApplicationControl/application-control.zcml 1.1.2.1 => 1.1.2.2 === + From casey@zope.com Wed Apr 10 16:03:56 2002 From: casey@zope.com (Casey Duncan) Date: Wed, 10 Apr 2002 11:03:56 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Memento - IMementoStorable.py:1.1.4.1 AttributeMementoBag.py:1.1.2.6 IAttributeMementoStorable.py:1.1.2.4 memento.zcml:1.1.2.2 Message-ID: <200204101503.g3AF3uI12566@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Memento In directory cvs.zope.org:/tmp/cvs-serv12271 Modified Files: Tag: Zope-3x-branch AttributeMementoBag.py IAttributeMementoStorable.py memento.zcml Added Files: Tag: Zope-3x-branch IMementoStorable.py Log Message: Merge Memento changes from security-reorg branch. * There is a new interface IMementoStorable which is a base interface for all memento storage interfaces. It is not implemented directly, but used as a general interface for adapters or views to reference when they need memento storage. This abstracts the memento storage method from the adapter or view. * Fixed a bug in AttributeMementoBag where it would do a write on read when mementos were accessed from an object. === Added File Zope3/lib/python/Zope/App/OFS/Memento/IMementoStorable.py === ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ $Id: IMementoStorable.py,v 1.1.4.1 2002/04/10 15:03:55 caseman Exp $ """ from Interface import Interface from Interface.Attribute import Attribute class IMementoStorable(Interface): """ Marker interfaces for objects that support memento storage. Classes should not implement this interface directly. Instead they should implement a derived interface that details how the memento is to be stored, such as IAttributeMementoStorable. """ === Zope3/lib/python/Zope/App/OFS/Memento/AttributeMementoBag.py 1.1.2.5 => 1.1.2.6 === def __init__(self,obj): - if not hasattr(obj,'__memobag__'): obj.__memobag__ = OOBTree() self.obj = obj + + def __getitem__(self, key): + memobag = getattr(self.obj, '__memobag__', {}) + return memobag[key] + + def get(self, key, default=None): + try: + return self.obj.__memobag__.get(key, default) + except AttributeError: + return default def __getattr__(self,attr): - return getattr(self.obj.__memobag__,attr) + try: + return getattr(self.obj.__memobag__,attr) + except AttributeError: + if not hasattr(self.obj, '__memobag__'): + memobag = self.obj.__memobag__ = OOBTree() + return getattr(memobag, attr) + raise + === Zope3/lib/python/Zope/App/OFS/Memento/IAttributeMementoStorable.py 1.1.2.3 => 1.1.2.4 === $Id$ """ -from Interface import Interface +from IMementoStorable import IMementoStorable from Interface.Attribute import Attribute -class IAttributeMementoStorable(Interface): +class IAttributeMementoStorable(IMementoStorable): """ Marker interfaces giving permission for an IMementoBag adapter to store data in an an attribute named __memobag__. === Zope3/lib/python/Zope/App/OFS/Memento/memento.zcml 1.1.2.1 => 1.1.2.2 === > + + provides="Zope.App.OFS.Memento.IMementoBag." /> From andreas@digicool.com Wed Apr 10 16:44:31 2002 From: andreas@digicool.com (Andreas Jung) Date: Wed, 10 Apr 2002 11:44:31 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.406.2.39 Message-ID: <200204101544.g3AFiV028813@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv28782/doc Modified Files: Tag: Zope-2_5-branch CHANGES.txt Log Message: - Collector #373: content_type property for Image objects are no longer deletable to prevent malfunction. === Zope/doc/CHANGES.txt 1.406.2.38 => 1.406.2.39 === show nonsensical results. + - Collector #373: content_type property for Image objects + are no longer deletable to prevent malfunction. + Features Added - TextIndex/Splitters: the constructor of all three splitters From andreas@digicool.com Wed Apr 10 16:44:31 2002 From: andreas@digicool.com (Andreas Jung) Date: Wed, 10 Apr 2002 11:44:31 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - Image.py:1.134.12.1 Message-ID: <200204101544.g3AFiVj28814@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv28782/lib/python/OFS Modified Files: Tag: Zope-2_5-branch Image.py Log Message: - Collector #373: content_type property for Image objects are no longer deletable to prevent malfunction. === Zope/lib/python/OFS/Image.py 1.134 => 1.134.12.1 === _properties=({'id':'title', 'type': 'string'}, - {'id':'content_type', 'type':'string'}, - {'id':'height', 'type':'string'}, + {'id':'content_type', 'type':'string','mode':'w'}, + {'id':'height', 'type':'string' }, {'id':'width', 'type':'string'}, ) From andreas@digicool.com Wed Apr 10 16:45:31 2002 From: andreas@digicool.com (Andreas Jung) Date: Wed, 10 Apr 2002 11:45:31 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - Image.py:1.136 Message-ID: <200204101545.g3AFjVa29429@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv29404/lib/python/OFS Modified Files: Image.py Log Message: - Collector #373: content_type property for Image objects are no longer deletable to prevent malfunction. === Zope/lib/python/OFS/Image.py 1.135 => 1.136 === _properties=({'id':'title', 'type': 'string'}, - {'id':'content_type', 'type':'string'}, + {'id':'content_type', 'type':'string','mode':'w'}, {'id':'height', 'type':'string'}, {'id':'width', 'type':'string'}, ) From andreas@digicool.com Wed Apr 10 16:46:01 2002 From: andreas@digicool.com (Andreas Jung) Date: Wed, 10 Apr 2002 11:46:01 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.454 Message-ID: <200204101546.g3AFk1n29936@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv29404/doc Modified Files: CHANGES.txt Log Message: - Collector #373: content_type property for Image objects are no longer deletable to prevent malfunction. === Zope/doc/CHANGES.txt 1.453 => 1.454 === cleared the standard Vocabulary. + - Collector #373: content_type property for Image objects + are no longer deletable to prevent malfunction. + Zope 2.5.1 beta 1 Bugs Fixed From m.faassen@vet.uu.nl Wed Apr 10 17:07:57 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Wed, 10 Apr 2002 12:07:57 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Schema Zope3/lib/python/Zope/App/Schema - New directory Message-ID: <200204101607.g3AG7vD06562@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Schema In directory cvs.zope.org:/tmp/cvs-serv6552/Schema Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/Schema added to the repository --> Using per-directory sticky tag `Zope3-property-branch' === Added directory Zope3/lib/python/Zope/App/Schema === From m.faassen@vet.uu.nl Wed Apr 10 17:08:20 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Wed, 10 Apr 2002 12:08:20 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Schema/tests Zope3/lib/python/Zope/App/Schema/tests - New directory Message-ID: <200204101608.g3AG8Kc06708@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Schema/tests In directory cvs.zope.org:/tmp/cvs-serv6701/tests Log Message: Directory /cvs-repository/Zope3/lib/python/Zope/App/Schema/tests added to the repository --> Using per-directory sticky tag `Zope3-property-branch' === Added directory Zope3/lib/python/Zope/App/Schema/tests === From m.faassen@vet.uu.nl Wed Apr 10 17:10:32 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Wed, 10 Apr 2002 12:10:32 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Schema/tests - __init__.py:1.1.2.1 testDC.py:1.1.2.1 Message-ID: <200204101610.g3AGAWH07634@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Schema/tests In directory cvs.zope.org:/tmp/cvs-serv6926/Zope/App/Schema/tests Added Files: Tag: Zope3-property-branch __init__.py testDC.py Log Message: Added experimental schema stuff. Incidentally removed windows newlines from Formulator === Added File Zope3/lib/python/Zope/App/Schema/tests/__init__.py === === Added File Zope3/lib/python/Zope/App/Schema/tests/testDC.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ Revision information: $Id: testDC.py,v 1.1.2.1 2002/04/10 16:10:31 faassen Exp $ """ from unittest import TestCase, TestSuite, main, makeSuite from Zope.App.Schema.DC import DC ############################################################################# # If your tests change any global registries, then uncomment the # following import and include CleanUp as a base class of your # test. It provides a setUp and tearDown that clear global data that # has registered with the test cleanup framework. Don't use this # tests outside the Zope package. # from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup ############################################################################# class Test(TestCase): def test(self): adapter = DC({}) self.assertEquals('', adapter.title) self.assertEquals('', adapter.description) adapter.title = 'title' adapter.description = 'description' self.assertEquals('title', adapter.title) self.assertEquals('description', adapter.description) def test_suite(): return TestSuite(( makeSuite(Test), )) if __name__=='__main__': main(defaultTest='test_suite') From m.faassen@vet.uu.nl Wed Apr 10 17:10:32 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Wed, 10 Apr 2002 12:10:32 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Schema - DC.py:1.1.2.1 DCBrowserView.py:1.1.2.1 Field.py:1.1.2.1 IDC.py:1.1.2.1 IField.py:1.1.2.1 PropertySet.py:1.1.2.1 Widget.py:1.1.2.1 __init__.py:1.1.2.1 index.pt:1.1.2.1 metaConfigure.py:1.1.2.1 Message-ID: <200204101610.g3AGAWv07638@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Schema In directory cvs.zope.org:/tmp/cvs-serv6926/Zope/App/Schema Added Files: Tag: Zope3-property-branch DC.py DCBrowserView.py Field.py IDC.py IField.py PropertySet.py Widget.py __init__.py index.pt metaConfigure.py Log Message: Added experimental schema stuff. Incidentally removed windows newlines from Formulator === Added File Zope3/lib/python/Zope/App/Schema/DC.py === from IDC import IDC from PropertySet import PropertySetFactoryFactory DC = PropertySetFactoryFactory('MementoBagDCAdapter', IDC) === Added File Zope3/lib/python/Zope/App/Schema/DCBrowserView.py === from Zope.Publisher.Browser.AttributePublisher import AttributePublisher from Zope.ComponentArchitecture.ContextDependent import ContextDependent from Zope.PageTemplate.PageTemplateFile import PageTemplateFile from IDC import IDC class DCBrowserView(AttributePublisher, ContextDependent): index = PageTemplateFile('index.pt') __used_for__ = IDC def setViewRequest(self, request): self._request = request def titleView(self): field = IDC.getDescriptionFor('title') view_name = getRequestDefaultViewName(field, self._request) widget = getRequestView(field, view_name, self._request) widget.setDefault(self.getContext().title) return widget() def descriptionView(self): field = IDC.getDescriptionFor('description') view_name = getRequestDefaultViewName(field, self._request) widget = getRequestView(field, view_name, self._request) widget.setDefault(self.getContext().description) return widget() def submit(self, REQUEST): context = self.getContext() context.title = REQUEST['title'] context.description = REQUEST['description'] return self.index(REQUEST) === Added File Zope3/lib/python/Zope/App/Schema/Field.py === from Interface.Attribute import Attribute class Field(Attribute): title = None description = None def __init__(self, title, description): super(Field, self).__init__('%s\n\n%s' % (title, description)) self.title = title self.description = description class StringField(Field): default = None def __init__(self, title, description, default=""): super(StringField, self).__init__(title, description) self.default = default class TextField(Field): default = None def __init__(self, title, description, default=""): super(TextField, self).__init__(title, description) self.default = default from IField import IField, IStringField, ITextField from Interface.Implements import implements implements(Field, IField) implements(StringField, IStringField) implements(TextField, ITextField) === Added File Zope3/lib/python/Zope/App/Schema/IDC.py === from Interface import Interface from Field import StringField from Field import TextField class IDC(Interface): title = StringField( title="Title", description="The title.", ) description = TextField( title="Description", description="The description.", ) # class __tagged_values__: # # def validate(data): # "validate some data" # order = 'title', 'description' === Added File Zope3/lib/python/Zope/App/Schema/IField.py === from Interface import Interface from Field import StringField, TextField class IField(Interface): title = StringField( title="Title", description="The title.", ) description = TextField( title="Description", description="The description.", ) class IStringField(IField): default = StringField( title="Default", description="Default value.", ) class ITextField(IField): default = TextField( title="Default", description="Default value.", ) === Added File Zope3/lib/python/Zope/App/Schema/PropertySet.py === from IField import IField from Zope.ComponentArchitecture.ContextDependent import ContextDependent class MementoAdapterProperty(object): def __init__(self, schema, name): self._schema = schema self._name = name field = schema.getDescriptionFor(name) self._default = field.default def __get__(self, instance, klass=None): if instance is None: return self memento = instance.getContext().get(self._schema.__name__, {}) return memento.get(self._name, self._default) def __set__(self, instance, value): memento = instance.getContext().get(self._schema.__name__, None) if memento is None: memento = {} instance.getContext()[self._schema.__name__] = memento memento[self._name] = value def PropertySetFactoryFactory(klassname, schema): """Create PropertySetFactories out of the schema. """ klass = type(klassname, (ContextDependent,), {}) for name, field in schema.namesAndDescriptions(1): if not IField.isImplementedBy(field): raise TypeError, "Schema contains non-field attributes." # XXX we should check whether we overwrite getContext & co setattr(klass, name, MementoAdapterProperty(schema, name)) klass.__implements__ = schema return klass === Added File Zope3/lib/python/Zope/App/Schema/Widget.py === from Zope.ComponentArchitecture.ContextDependent import ContextDependent class StringWidget(ContextDependent): def setViewRequest(self, request): self._request = request def setDefault(self, default): self._default = default def __call__(self): field_name = self.getContext().getName() return '' % ( field_name, self._default) class TextWidget(object): def setViewRequest(self, request): self._request = request def setDefault(self, default): self._default = default def __call__(self): field_name = self.getContext().getName() return '' % ( field_name, self._default) === Added File Zope3/lib/python/Zope/App/Schema/__init__.py === # === Added File Zope3/lib/python/Zope/App/Schema/index.pt ===

titleView


descriptionView


=== Added File Zope3/lib/python/Zope/App/Schema/metaConfigure.py === from Zope.ComponentArchitecture.IToIRegistry import TypeRegistry _reg = {} def propertySetDirective(_context, provides, name, for_): provides = _context.resolve(provides) for_ = _context.resolve(for_) return [Action(discriminator=('propertySet', name, for_), callable=propertySet, args=(provides, name, for_))] def propertySet(provides, name, for_): treg = _reg.get(name) if treg is None: treg = TypeRegistry() _reg[name] = treg treg.register(for_, provides) From m.faassen@vet.uu.nl Wed Apr 10 17:11:02 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Wed, 10 Apr 2002 12:11:02 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/PropertySets - IPropertySetDef.py:1.1.2.2.4.1 Message-ID: <200204101611.g3AGB2E08183@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/PropertySets In directory cvs.zope.org:/tmp/cvs-serv6926/Zope/App/OFS/PropertySets Modified Files: Tag: Zope3-property-branch IPropertySetDef.py Log Message: Added experimental schema stuff. Incidentally removed windows newlines from Formulator === Zope3/lib/python/Zope/App/OFS/PropertySets/IPropertySetDef.py 1.1.2.2 => 1.1.2.2.4.1 === """ -$Id$" +$Id$ """ from Interface import Interface From m.faassen@vet.uu.nl Wed Apr 10 17:11:03 2002 From: m.faassen@vet.uu.nl (Martijn Faassen) Date: Wed, 10 Apr 2002 12:11:03 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Formulator - CompositeWidget.py:1.1.4.1.4.1 Field.py:1.1.4.1.4.1 FieldRegistry.py:1.1.4.1.4.1 Form.py:1.1.4.1.4.1 ICompositeWidget.py:1.1.4.1.4.1 IField.py:1.1.4.1.4.1 IInstanceFactory.py:1.1.4.1.4.1 IPropertyFieldAdapter.py:1.1.4.1.4.1 ISimpleRegistry.py:1.1.4.1.4.1 IValidator.py:1.1.4.1.4.1 IWidget.py:1.1.4.1.4.1 PropertyFieldAdapter.py:1.1.4.1.4.1 SimpleRegistry.py:1.1.4.1.4.1 ValidatorRegistry.py:1.1.4.1.4.1 Widget.py:1.1.4.1.4.1 __init__.py:1.1.4.1.4.1 Message-ID: <200204101611.g3AGB3n08208@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Formulator In directory cvs.zope.org:/tmp/cvs-serv6926/Zope/App/Formulator Modified Files: Tag: Zope3-property-branch CompositeWidget.py Field.py FieldRegistry.py Form.py ICompositeWidget.py IField.py IInstanceFactory.py IPropertyFieldAdapter.py ISimpleRegistry.py IValidator.py IWidget.py PropertyFieldAdapter.py SimpleRegistry.py ValidatorRegistry.py Widget.py __init__.py Log Message: Added experimental schema stuff. Incidentally removed windows newlines from Formulator === Zope3/lib/python/Zope/App/Formulator/CompositeWidget.py 1.1.4.1 => 1.1.4.1.4.1 === # ############################################################################## -""" - -$Id$ -""" - -from ICompositeWidget import ICompositeWidget -from Widget import Widget - - -class CompositeWidget(Widget): - """ """ - - __implements__ = Widget.__implements__, ICompositeWidget - - # Page template that is ised to lay out sub-widgets - template = None - - # List of Sub-Widgets - widgets = None - - - def render(self, REQUEST): - """ """ - return apply(self.template, (REQUEST,)) - - - def render_hidden(self, REQUEST): - """ """ - return apply(self.template, (REQUEST,), {'hidden': 1}) - - - def setWidget(self, name, widget): - """ """ - if self.widgets is None: - self.widgets = {} - - self.widgets[name] = widget - - - def getWidget(self, name, _default=None): - """ """ - if name in self.widgets.keys(): - return self.widgets[name] - else: - return _default - - - def getWidgets(self): - """ """ - return self.widgets +""" + +$Id$ +""" + +from ICompositeWidget import ICompositeWidget +from Widget import Widget + + +class CompositeWidget(Widget): + """ """ + + __implements__ = Widget.__implements__, ICompositeWidget + + # Page template that is ised to lay out sub-widgets + template = None + + # List of Sub-Widgets + widgets = None + + + def render(self, REQUEST): + """ """ + return apply(self.template, (REQUEST,)) + + + def render_hidden(self, REQUEST): + """ """ + return apply(self.template, (REQUEST,), {'hidden': 1}) + + + def setWidget(self, name, widget): + """ """ + if self.widgets is None: + self.widgets = {} + + self.widgets[name] = widget + + + def getWidget(self, name, _default=None): + """ """ + if name in self.widgets.keys(): + return self.widgets[name] + else: + return _default + + + def getWidgets(self): + """ """ + return self.widgets === Zope3/lib/python/Zope/App/Formulator/Field.py 1.1.4.1 => 1.1.4.1.4.1 === # ############################################################################## -""" - -$Id$ -""" - -from Persistence import Persistent -from IField import IField -from Zope.App.Formulator.Errors import ValidationError -from IInstanceFactory import IInstanceFactory - - -class Field(Persistent): - """Base class of all fields. - A field is an object consisting of a widget and a validator. - """ - - __implements__ = ( - IField, - IInstanceFactory - ) - - propertyNames = ('id', 'validator', 'default', 'title', 'description', - 'required') - - id = None - validator = None - default = None - title = 'Field Title' - description = 'Field Description' - required = 0 - - - def __init__(self, context=None, **kw): - self.realize(context) - - for name in self.propertyNames: - if name in kw.keys(): - setattr(self, name, kw[name]) - - - def getErrorMessage(self, name): - try: - return self.validator.getMessage(name) - except KeyError: - if name in self.validator.messageNames: - return getattr(self.validator, name) - else: - return "Unknown error: %s" % name - - - ############################################################ - # Implementation methods for interface - # Zope.App.Formulator.IField. - - def getValidator(self): - '''See interface IField''' - return self.validator - - - def hasValue(self, id): - '''See interface IField''' - if id in self.propertyNames: - return 1 - else: - return 0 - - - def getValue(self, id, _default=None): - '''See interface IField''' - if id in self.propertyNames: - return getattr(self, id) - else: - return _default - - - def isRequired(self): - '''See interface IField''' - return hasattr(self, 'required') and getattr(self, 'required') - - - def getErrorNames(self): - '''See interface IField''' - return self.validator.messageNames - - - def getTales(self, id): - '''See interface IField''' - raise NotImplemented - - - def isTALESAvailable(self): - '''See interface IField''' - raise NotImplemented - - - def getOverride(self, id): - '''See interface IField''' - raise NotImplemented - - # - ############################################################ - - - ############################################################ - # Implementation methods for interface - # Zope.App.Formulator.IInstanceFactory. - - def __call__(self, context): - '''See interface IInstanceFactory''' - self.realize(context) - return self - - - def getContext(self): - '''See interface IInstanceFactory''' - return self.context - - - def realize(self, context): - '''See interface IInstanceFactory''' - self.context = context - # - ############################################################ +""" + +$Id$ +""" + +from Persistence import Persistent +from IField import IField +from Zope.App.Formulator.Errors import ValidationError +from IInstanceFactory import IInstanceFactory + + +class Field(Persistent): + """Base class of all fields. + A field is an object consisting of a widget and a validator. + """ + + __implements__ = ( + IField, + IInstanceFactory + ) + + propertyNames = ('id', 'validator', 'default', 'title', 'description', + 'required') + + id = None + validator = None + default = None + title = 'Field Title' + description = 'Field Description' + required = 0 + + + def __init__(self, context=None, **kw): + self.realize(context) + + for name in self.propertyNames: + if name in kw.keys(): + setattr(self, name, kw[name]) + + + def getErrorMessage(self, name): + try: + return self.validator.getMessage(name) + except KeyError: + if name in self.validator.messageNames: + return getattr(self.validator, name) + else: + return "Unknown error: %s" % name + + + ############################################################ + # Implementation methods for interface + # Zope.App.Formulator.IField. + + def getValidator(self): + '''See interface IField''' + return self.validator + + + def hasValue(self, id): + '''See interface IField''' + if id in self.propertyNames: + return 1 + else: + return 0 + + + def getValue(self, id, _default=None): + '''See interface IField''' + if id in self.propertyNames: + return getattr(self, id) + else: + return _default + + + def isRequired(self): + '''See interface IField''' + return hasattr(self, 'required') and getattr(self, 'required') + + + def getErrorNames(self): + '''See interface IField''' + return self.validator.messageNames + + + def getTales(self, id): + '''See interface IField''' + raise NotImplemented + + + def isTALESAvailable(self): + '''See interface IField''' + raise NotImplemented + + + def getOverride(self, id): + '''See interface IField''' + raise NotImplemented + + # + ############################################################ + + + ############################################################ + # Implementation methods for interface + # Zope.App.Formulator.IInstanceFactory. + + def __call__(self, context): + '''See interface IInstanceFactory''' + self.realize(context) + return self + + + def getContext(self): + '''See interface IInstanceFactory''' + return self.context + + + def realize(self, context): + '''See interface IInstanceFactory''' + self.context = context + # + ############################################################ === Zope3/lib/python/Zope/App/Formulator/FieldRegistry.py 1.1.4.1 => 1.1.4.1.4.1 === # ############################################################################## -""" - -$Id$ -""" - - -from SimpleRegistry import SimpleRegistry -from ISimpleRegistry import ISimpleRegistry -from IField import IField - -class IFieldRegistry(ISimpleRegistry): - """ - The Field Registry manages a list of all the fields available in Zope. A - registry is useful at this point, since fields can be initialized and - registered by many places. - - Note that it does not matter whether we have classes or instances as - fields. If the fields are instances, they must implement - IInstanceFactory. - """ - pass - - -class FieldRegistry(SimpleRegistry): - """ """ - - __implements__ = (IFieldRegistry,) - - - -FieldRegistry = FieldRegistry(IField) -registerField = FieldRegistry.register -getField = FieldRegistry.get +""" + +$Id$ +""" + + +from SimpleRegistry import SimpleRegistry +from ISimpleRegistry import ISimpleRegistry +from IField import IField + +class IFieldRegistry(ISimpleRegistry): + """ + The Field Registry manages a list of all the fields available in Zope. A + registry is useful at this point, since fields can be initialized and + registered by many places. + + Note that it does not matter whether we have classes or instances as + fields. If the fields are instances, they must implement + IInstanceFactory. + """ + pass + + +class FieldRegistry(SimpleRegistry): + """ """ + + __implements__ = (IFieldRegistry,) + + + +FieldRegistry = FieldRegistry(IField) +registerField = FieldRegistry.register +getField = FieldRegistry.get === Zope3/lib/python/Zope/App/Formulator/Form.py 1.1.4.1 => 1.1.4.1.4.1 === # ############################################################################## -""" - -$Id$ -""" - -from Zope.Publisher.Browser.AttributePublisher \ - import AttributePublisher -#from IForm import IForm -from Zope.ComponentArchitecture import getRequestView -from Zope.App.Formulator.IPropertyFieldAdapter import IPropertyFieldAdapter -from Zope.App.Formulator.Errors import ValidationError -from Zope.ComponentArchitecture import getAdapter - - -class Form(AttributePublisher): - """Form base class. - """ - - __implements__ = AttributePublisher.__implements__#, IForm - - name = 'Form Name' # for use by javascript - title = 'This is a form' - description = '' - method = 'post' - enctype = '' - - _fieldViewNames = [] - template = None - - - def __init__(self, context): - """Initialize form. - """ - self._context = context - self._widgets = [] - - - def index(self, REQUEST, **kw): - """ """ - return apply(self.template, (REQUEST,), kw) - - - def action(self, REQUEST): - """ """ - errors = [] - values = {} - for widget in self.getFieldViews(REQUEST): - value = widget.getValueFromRequest(REQUEST) - field = widget.getContext() - try: - values[field.id] = field.getValidator().validate(field, value) - except ValidationError, err: - errors.append(err) - - if errors == []: - for widget in self.getFieldViews(REQUEST): - field = widget.getContext() - getAdapter(field, IPropertyFieldAdapter).setPropertyInContext(values[field.id]) - - return self.index(REQUEST, errors=errors) - - - def getFieldViews(self, REQUEST): - """ """ - views = [] - context = self.getContext() - for name in self._fieldViewNames: - views.append(getRequestView(context, name, REQUEST)) - return views - - - def getContext(self): - """ """ - return self._context +""" + +$Id$ +""" + +from Zope.Publisher.Browser.AttributePublisher \ + import AttributePublisher +#from IForm import IForm +from Zope.ComponentArchitecture import getRequestView +from Zope.App.Formulator.IPropertyFieldAdapter import IPropertyFieldAdapter +from Zope.App.Formulator.Errors import ValidationError +from Zope.ComponentArchitecture import getAdapter + + +class Form(AttributePublisher): + """Form base class. + """ + + __implements__ = AttributePublisher.__implements__#, IForm + + name = 'Form Name' # for use by javascript + title = 'This is a form' + description = '' + method = 'post' + enctype = '' + + _fieldViewNames = [] + template = None + + + def __init__(self, context): + """Initialize form. + """ + self._context = context + self._widgets = [] + + + def index(self, REQUEST, **kw): + """ """ + return apply(self.template, (REQUEST,), kw) + + + def action(self, REQUEST): + """ """ + errors = [] + values = {} + for widget in self.getFieldViews(REQUEST): + value = widget.getValueFromRequest(REQUEST) + field = widget.getContext() + try: + values[field.id] = field.getValidator().validate(field, value) + except ValidationError, err: + errors.append(err) + + if errors == []: + for widget in self.getFieldViews(REQUEST): + field = widget.getContext() + getAdapter(field, IPropertyFieldAdapter).setPropertyInContext(values[field.id]) + + return self.index(REQUEST, errors=errors) + + + def getFieldViews(self, REQUEST): + """ """ + views = [] + context = self.getContext() + for name in self._fieldViewNames: + views.append(getRequestView(context, name, REQUEST)) + return views + + + def getContext(self): + """ """ + return self._context === Zope3/lib/python/Zope/App/Formulator/ICompositeWidget.py 1.1.4.1 => 1.1.4.1.4.1 === # ############################################################################## -""" - -$Id$ -""" - -from IWidget import IWidget - - -class ICompositeWidget(IWidget): - """ """ +""" + +$Id$ +""" + +from IWidget import IWidget + + +class ICompositeWidget(IWidget): + """ """ === Zope3/lib/python/Zope/App/Formulator/IField.py 1.1.4.1 => 1.1.4.1.4.1 === # ############################################################################## -from Interface import Interface - - -class IField(Interface): - """ - """ - - def getValidator(): - """Return the validator of this field.""" - - - def getContext(): - """Return the context object of the field.""" - - - def hasValue(id): - """Return true if the field defines such a value. - """ - - - def getValue(id): - """Get value for id.""" - - - def getOverride(id): - """Get override method for id (not wrapped).""" - - - def getTales(id): - """Get tales expression method for id.""" - - - def isRequired(): - """Check whether this field is required (utility function) - """ - - - def getErrorNames(): - """Get error messages. - """ - - - def isTALESAvailable(): - """Return true only if TALES is available. - """ - +from Interface import Interface + + +class IField(Interface): + """ + """ + + def getValidator(): + """Return the validator of this field.""" + + + def getContext(): + """Return the context object of the field.""" + + + def hasValue(id): + """Return true if the field defines such a value. + """ + + + def getValue(id): + """Get value for id.""" + + + def getOverride(id): + """Get override method for id (not wrapped).""" + + + def getTales(id): + """Get tales expression method for id.""" + + + def isRequired(): + """Check whether this field is required (utility function) + """ + + + def getErrorNames(): + """Get error messages. + """ + + + def isTALESAvailable(): + """Return true only if TALES is available. + """ + === Zope3/lib/python/Zope/App/Formulator/IInstanceFactory.py 1.1.4.1 => 1.1.4.1.4.1 === # ############################################################################## -""" - -$Id$ -""" - - -from Interface import Interface - - -class IInstanceFactory(Interface): - """ - If the Instance Factory is implemented by an object, then this object - can be used as factory for other components, such as Views. - """ - - def realize(context): - """ - Relaizes an instance in a particular context/evironment. This - method basically replaces __init__(context) for class-based - factories. - """ - - - def __call__(context): - """ - Basically calls realize(context). However it must be implemented - too, so that the factory is callable This method has to return the - produced object. - """ - - def getContext(): - """ - Get the context of the realized instance. - """ +""" + +$Id$ +""" + + +from Interface import Interface + + +class IInstanceFactory(Interface): + """ + If the Instance Factory is implemented by an object, then this object + can be used as factory for other components, such as Views. + """ + + def realize(context): + """ + Relaizes an instance in a particular context/evironment. This + method basically replaces __init__(context) for class-based + factories. + """ + + + def __call__(context): + """ + Basically calls realize(context). However it must be implemented + too, so that the factory is callable This method has to return the + produced object. + """ + + def getContext(): + """ + Get the context of the realized instance. + """ === Zope3/lib/python/Zope/App/Formulator/IPropertyFieldAdapter.py 1.1.4.1 => 1.1.4.1.4.1 === # ############################################################################## -""" - -$Id$ -""" - - -from Interface import Interface - - -class IPropertyFieldAdapter(Interface): - """ - """ - - def setPropertyInContext(value): - """ """ - - - def getPropertyInContext(): - """ """ +""" + +$Id$ +""" + + +from Interface import Interface + + +class IPropertyFieldAdapter(Interface): + """ + """ + + def setPropertyInContext(value): + """ """ + + + def getPropertyInContext(): + """ """ === Zope3/lib/python/Zope/App/Formulator/ISimpleRegistry.py 1.1.4.1 => 1.1.4.1.4.1 === # ############################################################################## -""" - -$Id$ -""" - -from Interface import Interface - - -class ISimpleRegistry(Interface): - """ - The Simple Registry is minimal collection of registered objects. This can - be useful, when it is expected that objects of a particular type are added - from many places in the system (through 3rd party products for example). - - A good example for this are the Formulator fields. While the basic types - are defined inside the Formulator tree, other parties might add many - more later on in their products, so it is useful to provide a registry via - ZCML that allows to collect these items. - - There is only one constraint on the objects. They all must implement a - particular interface specified during the initialization of the registry. - - Note that it does not matter whether we have classes or instances as - objects. If the objects are instances, they must implement simply - IInstanceFactory. - """ - - def register(name, object): - """ - Registers the object under the id name. - """ - - - def getF(name): - """ - This returns the object with id name. - """ +""" + +$Id$ +""" + +from Interface import Interface + + +class ISimpleRegistry(Interface): + """ + The Simple Registry is minimal collection of registered objects. This can + be useful, when it is expected that objects of a particular type are added + from many places in the system (through 3rd party products for example). + + A good example for this are the Formulator fields. While the basic types + are defined inside the Formulator tree, other parties might add many + more later on in their products, so it is useful to provide a registry via + ZCML that allows to collect these items. + + There is only one constraint on the objects. They all must implement a + particular interface specified during the initialization of the registry. + + Note that it does not matter whether we have classes or instances as + objects. If the objects are instances, they must implement simply + IInstanceFactory. + """ + + def register(name, object): + """ + Registers the object under the id name. + """ + + + def getF(name): + """ + This returns the object with id name. + """ === Zope3/lib/python/Zope/App/Formulator/IValidator.py 1.1.4.1 => 1.1.4.1.4.1 === # ############################################################################## -""" - -$Id$ -""" - -from Interface import Interface - - -class IValidator(Interface): - """A field validator provides the functionality to verify the - input data on the server. - - This class will be initialized as a singleton. - """ - - def validate(field, value): - """Validate the value, knowing the field. - """ - - def raiseError(errorKey, field): - """Raises the error, if the validation fails. - """ +""" + +$Id$ +""" + +from Interface import Interface + + +class IValidator(Interface): + """A field validator provides the functionality to verify the + input data on the server. + + This class will be initialized as a singleton. + """ + + def validate(field, value): + """Validate the value, knowing the field. + """ + + def raiseError(errorKey, field): + """Raises the error, if the validation fails. + """ === Zope3/lib/python/Zope/App/Formulator/IWidget.py 1.1.4.1 => 1.1.4.1.4.1 === # ############################################################################## -""" - -$Id$ -""" - -from Interface import Interface - - -class IWidget(Interface): - """Generically describes the behavior of a widget. - - The widget defines a list of propertyNames, which describes - what properties of the widget are available to use for - constructing the widget render output. - - Note that this level must be still presentation independent. - """ - - def getValue(name): - """Look up a Widget setting (value) by name.""" - - - def getContext(): - """Get the context of the widget, namely the Field.""" - - - def render(): - """Render the widget. This will return the representation the - client will understand.""" - - def render_hidden(): - """Render the widget as a hidden field. This will return the - representation the client will understand.""" +""" + +$Id$ +""" + +from Interface import Interface + + +class IWidget(Interface): + """Generically describes the behavior of a widget. + + The widget defines a list of propertyNames, which describes + what properties of the widget are available to use for + constructing the widget render output. + + Note that this level must be still presentation independent. + """ + + def getValue(name): + """Look up a Widget setting (value) by name.""" + + + def getContext(): + """Get the context of the widget, namely the Field.""" + + + def render(): + """Render the widget. This will return the representation the + client will understand.""" + + def render_hidden(): + """Render the widget as a hidden field. This will return the + representation the client will understand.""" === Zope3/lib/python/Zope/App/Formulator/PropertyFieldAdapter.py 1.1.4.1 => 1.1.4.1.4.1 === # ############################################################################## -""" - -$Id$ -""" - -from IPropertyFieldAdapter import IPropertyFieldAdapter -from Zope.App.Formulator.Errors import ValidationError - - -class PropertyFieldAdapter: - """ """ - - __implements__ = IPropertyFieldAdapter - - - def __init__(self, context): - """ """ - self.context = context - - - def setPropertyInContext(self, value): - """ """ - field = self.getContext() - method = getattr(field.getContext(), - 'set'+field.id[0].capitalize()+field.id[1:], None) - apply(method, (value,)) - - - def getPropertyInContext(self): - """ """ - field = self.getContext() - method = getattr(field.getContext(), - 'get'+field.id[0].capitalize()+field.id[1:], None) - return apply(method, ()) - - - def getContext(self): - """ """ - return self.context +""" + +$Id$ +""" + +from IPropertyFieldAdapter import IPropertyFieldAdapter +from Zope.App.Formulator.Errors import ValidationError + + +class PropertyFieldAdapter: + """ """ + + __implements__ = IPropertyFieldAdapter + + + def __init__(self, context): + """ """ + self.context = context + + + def setPropertyInContext(self, value): + """ """ + field = self.getContext() + method = getattr(field.getContext(), + 'set'+field.id[0].capitalize()+field.id[1:], None) + apply(method, (value,)) + + + def getPropertyInContext(self): + """ """ + field = self.getContext() + method = getattr(field.getContext(), + 'get'+field.id[0].capitalize()+field.id[1:], None) + return apply(method, ()) + + + def getContext(self): + """ """ + return self.context === Zope3/lib/python/Zope/App/Formulator/SimpleRegistry.py 1.1.4.1 => 1.1.4.1.4.1 === # ############################################################################## -""" - -$Id$ -""" - -from Zope.Configuration.name import resolve -from ISimpleRegistry import ISimpleRegistry -from types import StringTypes, ListType, TupleType -ListTypes = (TupleType, ListType) - - -class ZopeDuplicateRegistryEntryError(Exception): - """ - This Error is raised when the user tries to add an object with - a name that already exists in the registry. Therefore, - overwriting is not allowed. - """ - - def __init__(self, name): - """Initializes Error""" - self.name = name - - - def __str__(self): - """Returns string representation of Error""" - return "The name '%s' is already defined in this registry." \ - %self.name - - - -class ZopeIllegalInterfaceError(Exception): - """ - This Error is thrown, when the passed object does not implement - the specified interface. - """ - - def __init__(self, name, interface): - """Initalize Error""" - self.name = name - self.interface = interface - - - def __str__(self): - """Returns string representation of Error""" - return ( "The object with name " + self.name + " does not implement " - "the interface " + self.interface.__name__ + "." ) - - - -class SimpleRegistry: - """ """ - - __implements__ = (ISimpleRegistry,) - - - def __init__(self, interface): - """Initialize registry""" - self.objects = {} - self.interface = interface - - - ############################################################ - # Implementation methods for interface - # Zope.App.Formulator.ISimpleRegistry - - def register(self, name, object): - '''See interface ISimpleRegistry''' - - if name in self.objects.keys(): - raise ZopeDuplicateRegistryEntryError(name) - - # XXX Find the right Interface tools to do that; unfortunately, - # I have not found them - # Check whether the object implements the right interface. - # Note, that we do *not* know whether the object is an instance - # or a class (or worse a Persistent class) - if hasattr(object, '__implements__') and \ - ( self.interface == object.__implements__ or \ - ( type(object.__implements__) in ListTypes and - self.interface in object.__implements__ ) ): - self.objects[name] = object - - else: - raise ZopeIllegalInterfaceError(name, self.interface) - - return [] - - - def get(self, name): - '''See interface ISimpleRegistry''' - if name in self.objects.keys(): - return self.objects[name] - else: - return None - - # - ############################################################ +""" + +$Id$ +""" + +from Zope.Configuration.name import resolve +from ISimpleRegistry import ISimpleRegistry +from types import StringTypes, ListType, TupleType +ListTypes = (TupleType, ListType) + + +class ZopeDuplicateRegistryEntryError(Exception): + """ + This Error is raised when the user tries to add an object with + a name that already exists in the registry. Therefore, + overwriting is not allowed. + """ + + def __init__(self, name): + """Initializes Error""" + self.name = name + + + def __str__(self): + """Returns string representation of Error""" + return "The name '%s' is already defined in this registry." \ + %self.name + + + +class ZopeIllegalInterfaceError(Exception): + """ + This Error is thrown, when the passed object does not implement + the specified interface. + """ + + def __init__(self, name, interface): + """Initalize Error""" + self.name = name + self.interface = interface + + + def __str__(self): + """Returns string representation of Error""" + return ( "The object with name " + self.name + " does not implement " + "the interface " + self.interface.__name__ + "." ) + + + +class SimpleRegistry: + """ """ + + __implements__ = (ISimpleRegistry,) + + + def __init__(self, interface): + """Initialize registry""" + self.objects = {} + self.interface = interface + + + ############################################################ + # Implementation methods for interface + # Zope.App.Formulator.ISimpleRegistry + + def register(self, name, object): + '''See interface ISimpleRegistry''' + + if name in self.objects.keys(): + raise ZopeDuplicateRegistryEntryError(name) + + # XXX Find the right Interface tools to do that; unfortunately, + # I have not found them + # Check whether the object implements the right interface. + # Note, that we do *not* know whether the object is an instance + # or a class (or worse a Persistent class) + if hasattr(object, '__implements__') and \ + ( self.interface == object.__implements__ or \ + ( type(object.__implements__) in ListTypes and + self.interface in object.__implements__ ) ): + self.objects[name] = object + + else: + raise ZopeIllegalInterfaceError(name, self.interface) + + return [] + + + def get(self, name): + '''See interface ISimpleRegistry''' + if name in self.objects.keys(): + return self.objects[name] + else: + return None + + # + ############################################################ === Zope3/lib/python/Zope/App/Formulator/ValidatorRegistry.py 1.1.4.1 => 1.1.4.1.4.1 === # ############################################################################## -""" - -$Id$ -""" - - -from SimpleRegistry import SimpleRegistry -from ISimpleRegistry import ISimpleRegistry -from IValidator import IValidator - -class IValidatorRegistry(ISimpleRegistry): - """ - - Note that it does not matter whether we have classes or instances as - validators. If the validaotrs are instances, they must implement - IInstanceFactory. - """ - pass - - -class ValidatorRegistry(SimpleRegistry): - """ """ - - __implements__ = (IValidatorRegistry,) - - - -ValidatorRegistry = ValidatorRegistry(IValidator) -registerValidator = ValidatorRegistry.register -getValidator = ValidatorRegistry.get +""" + +$Id$ +""" + + +from SimpleRegistry import SimpleRegistry +from ISimpleRegistry import ISimpleRegistry +from IValidator import IValidator + +class IValidatorRegistry(ISimpleRegistry): + """ + + Note that it does not matter whether we have classes or instances as + validators. If the validaotrs are instances, they must implement + IInstanceFactory. + """ + pass + + +class ValidatorRegistry(SimpleRegistry): + """ """ + + __implements__ = (IValidatorRegistry,) + + + +ValidatorRegistry = ValidatorRegistry(IValidator) +registerValidator = ValidatorRegistry.register +getValidator = ValidatorRegistry.get === Zope3/lib/python/Zope/App/Formulator/Widget.py 1.1.4.1 => 1.1.4.1.4.1 === # ############################################################################## -""" - -$Id$ -""" -from IWidget import IWidget - - -class Widget(object): - """I do not know what will be in this class, but it provides - an extra layer. - """ - - __implements__ = IWidget - - propertyNames = [] - - - def __init__(self, field): - """ """ - self._field = field - - - def getValue(self, name): - """ """ - if name in self.propertyNames: - return getattr(self, name, None) - - - def getContext(self): - """ """ - return self._field - - - def render(self): - """ """ - raise NotImplemented - - - def render_hidden(self): - """ """ - raise NotImplemented +""" + +$Id$ +""" +from IWidget import IWidget + + +class Widget(object): + """I do not know what will be in this class, but it provides + an extra layer. + """ + + __implements__ = IWidget + + propertyNames = [] + + + def __init__(self, field): + """ """ + self._field = field + + + def getValue(self, name): + """ """ + if name in self.propertyNames: + return getattr(self, name, None) + + + def getContext(self): + """ """ + return self._field + + + def render(self): + """ """ + raise NotImplemented + + + def render_hidden(self): + """ """ + raise NotImplemented === Zope3/lib/python/Zope/App/Formulator/__init__.py 1.1.4.1 => 1.1.4.1.4.1 === # ############################################################################## -""" - -$Id$ -""" - -from FieldRegistry import registerField, getField -from ValidatorRegistry import registerValidator, getValidator +""" + +$Id$ +""" + +from FieldRegistry import registerField, getField +from ValidatorRegistry import registerValidator, getValidator From shane@cvs.zope.org Wed Apr 10 22:59:23 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Wed, 10 Apr 2002 17:59:23 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - IFilesystemAccess.py:1.1.2.1 IUsernamePassword.py:1.1.2.1 Message-ID: <200204102159.g3ALxNN18384@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv18340/VFS Added Files: Tag: Zope3-Server-Branch IFilesystemAccess.py IUsernamePassword.py Log Message: - Removed AlternateSocketMapMixin. It was there to support multiple socket maps, but if we really need multiple socket maps, it would be better to change asyncore. Had to update a lot of __init__ methods. - Added IUsernamePassword and IFilesystemAccess, which provide a way to implement all kinds of authentication schemes without FTP knowing about any of the details. Modified FTPServerChannel to work based on an IFilesystemAccess object. - Added detection of the ZOPE_SERVER_DEBUG env var. - Added comments here and there. - Fixed CRs :-) === Added File Zope3/lib/python/Zope/Server/VFS/IFilesystemAccess.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IFilesystemAccess.py,v 1.1.2.1 2002/04/10 21:59:22 shane Exp $ """ from Interface import Interface # XXX This interface should be in a more central location. class IFilesystemAccess(Interface): """Provides authenticated access to a filesystem. """ def authenticate(credentials): """Verifies filesystem access based on the presented credentials. Should raise Unauthorized if the user can not be authenticated. This method only checks general access and is not used for each call to open(). Rather, open() should do its own verification. """ def open(credentials): """Returns an IReadFilesystem or IWriteFilesystem. Should raise Unauthorized if the user can not be authenticated. """ === Added File Zope3/lib/python/Zope/Server/VFS/IUsernamePassword.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IUsernamePassword.py,v 1.1.2.1 2002/04/10 21:59:22 shane Exp $ """ from Interface import Interface # XXX These interfaces should be located in a more central location. # (so I don't mind putting them together in one module for now ;-) ) class ICredentials(Interface): """Base interface for presentation of authentication credentials. Different kinds of credentials include username/password, client certificate, IP address and port, etc., including combinations. """ class IUsernamePassword(ICredentials): """A type of authentication credentials consisting of user name and password. The most recognized form of credentials. """ def getUserName(): """Returns the user name presented for authentication. """ def getPassword(): """Returns the password presented for authentication. """ From shane@cvs.zope.org Wed Apr 10 22:59:23 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Wed, 10 Apr 2002 17:59:23 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/SMTP - SMTPServer.py:1.1.2.3 SMTPServerChannel.py:1.1.2.4 Message-ID: <200204102159.g3ALxNq18383@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/SMTP In directory cvs.zope.org:/tmp/cvs-serv18340/SMTP Modified Files: Tag: Zope3-Server-Branch SMTPServer.py SMTPServerChannel.py Log Message: - Removed AlternateSocketMapMixin. It was there to support multiple socket maps, but if we really need multiple socket maps, it would be better to change asyncore. Had to update a lot of __init__ methods. - Added IUsernamePassword and IFilesystemAccess, which provide a way to implement all kinds of authentication schemes without FTP knowing about any of the details. Modified FTPServerChannel to work based on an IFilesystemAccess object. - Added detection of the ZOPE_SERVER_DEBUG env var. - Added comments here and there. - Fixed CRs :-) === Zope3/lib/python/Zope/Server/SMTP/SMTPServer.py 1.1.2.2 => 1.1.2.3 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" -import asyncore -from SMTPServerChannel import SMTPServerChannel -import SMTPConfigurations -from Zope.Server.ServerBase import ServerBase - -from Zope.Server.VFS.UnixFileSystem import UnixFileSystem -from Zope.Server.Authentication.DictionaryAuthentication import \ - DictionaryAuthentication - - -class SMTPServer(ServerBase): - """Generic FTP Server""" - - channel_class = SMTPServerChannel - SERVER_IDENT = 'Zope.Server.SMTPServer' - - storage = UnixFileSystem('/opt/ZopeMail') - auth_source = DictionaryAuthentication({'foo': 'bar'}) - config = SMTPConfigurations - - def __init__(self, ip, port, maildir, auth, task_dispatcher=None, - adj=None, start=1, hit_log=None, verbose=0, socket_map=None): - super(SMTPServer, self).__init__(ip, port, task_dispatcher, - adj, start, hit_log, - verbose, socket_map) - - self.auth_source = auth - self.maildir = UnixFileSystem(maildir) - - -if __name__ == '__main__': - from Zope.Server.TaskThreads import ThreadedTaskDispatcher - td = ThreadedTaskDispatcher() - td.setThreadCount(4) - auth_source = DictionaryAuthentication({'foo': 'bar'}) - SMTPServer('', 25, '/var/mail', auth_source, task_dispatcher=td) - try: - while 1: - asyncore.poll(5) - print 'active channels:', SMTPServerChannel.active_channels - except KeyboardInterrupt: - print 'shutting down...' - td.shutdown() +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" +import asyncore +from SMTPServerChannel import SMTPServerChannel +import SMTPConfigurations +from Zope.Server.ServerBase import ServerBase + +from Zope.Server.VFS.UnixFileSystem import UnixFileSystem +from Zope.Server.Authentication.DictionaryAuthentication import \ + DictionaryAuthentication + + +class SMTPServer(ServerBase): + """Generic FTP Server""" + + channel_class = SMTPServerChannel + SERVER_IDENT = 'Zope.Server.SMTPServer' + + storage = UnixFileSystem('/opt/ZopeMail') + auth_source = DictionaryAuthentication({'foo': 'bar'}) + config = SMTPConfigurations + + def __init__(self, ip, port, maildir, auth, *args, **kw): + + self.auth_source = auth + self.maildir = UnixFileSystem(maildir) + + super(SMTPServer, self).__init__(ip, port, *args, **kw) + +if __name__ == '__main__': + from Zope.Server.TaskThreads import ThreadedTaskDispatcher + td = ThreadedTaskDispatcher() + td.setThreadCount(4) + auth_source = DictionaryAuthentication({'foo': 'bar'}) + SMTPServer('', 25, '/var/mail', auth_source, task_dispatcher=td) + try: + while 1: + asyncore.poll(5) + print 'active channels:', SMTPServerChannel.active_channels + except KeyboardInterrupt: + print 'shutting down...' + td.shutdown() === Zope3/lib/python/Zope/Server/SMTP/SMTPServerChannel.py 1.1.2.3 => 1.1.2.4 === (718/818 lines abridged) -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -import time -import fnmatch -import socket - -from Zope.Server.LineReceiver.LineServerChannel import LineServerChannel -from SMTPStatusMessages import status_msgs - -from ISMTPCommandHandler import ISMTPCommandHandler - - -class SMTPServerChannel(LineServerChannel): - """The SMTP Server Channel represents a connection to a particular - client. We can therefore store information here.""" - - __implements__ = ISMTPCommandHandler - - # Commands that are run in a separate thread - # thread_commands = ('cmd_mail', 'cmd_vrfy', 'cmd_data') - - # Define the authentication status of the channel. Note that only the - # "special commands" can be executed without having authenticated. - authenticated = 1 - - # Define the reply code for an unrecognized command - unknown_reply = 'ERR_CMD_UNKNOWN' - - # Define the status messages - status_messages = status_msgs - - # Defines the message terminator (a string sequence that signalizes the - # end of a message) - message_terminator = '.\r\n' - [-=- -=- -=- 718 lines omitted -=- -=- -=-] + name = name[1:-1] + + try: + username, domain = address.split('@') + except: + username, domain = address, '' + + return '"%s" <%s@%s>' %(username, username, domain) + + + def isLocalConnection(self): + name = ip2hostname(self.addr[0]) + match = fnmatch.fnmatch(name, self.server.config.LOCAL_DOMAIN_NAME) + return match or name == 'localhost.localdomain' + + + def isLocalAddress(self, address): + # clean up the address + if address[0] == '<' or address[-1] == '>': + address = address[1:-1] + + # Split the address into it user and domain component + try: + username, domain = address.split('@') + except: + username, domain = address, '' + + if ( self.server.auth_source.hasUser(username) and + (domain.lower() == self.server.server_name or domain == '') ): + return 1 + + return 0 + + + +def ip2hostname(ip, default=None): + """Resolves an IP into a hostname""" + try: + return socket.gethostbyaddr(ip)[0] + except socket.herror: + return default + + + +def hostname2ip(hostname, default=None): + try: + return socket.gethostbyname(hostname) + except socket.gaierror: + return default + From shane@cvs.zope.org Wed Apr 10 22:59:51 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Wed, 10 Apr 2002 17:59:51 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server - Adjustments.py:1.1.2.4.2.5 DualModeChannel.py:1.1.2.4.2.6 ServerBase.py:1.1.2.4.2.4 ServerChannelBase.py:1.1.2.7 Message-ID: <200204102159.g3ALxps18429@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server In directory cvs.zope.org:/tmp/cvs-serv18340 Modified Files: Tag: Zope3-Server-Branch Adjustments.py DualModeChannel.py ServerBase.py ServerChannelBase.py Log Message: - Removed AlternateSocketMapMixin. It was there to support multiple socket maps, but if we really need multiple socket maps, it would be better to change asyncore. Had to update a lot of __init__ methods. - Added IUsernamePassword and IFilesystemAccess, which provide a way to implement all kinds of authentication schemes without FTP knowing about any of the details. Modified FTPServerChannel to work based on an IFilesystemAccess object. - Added detection of the ZOPE_SERVER_DEBUG env var. - Added comments here and there. - Fixed CRs :-) === Zope3/lib/python/Zope/Server/Adjustments.py 1.1.2.4.2.4 => 1.1.2.4.2.5 === class Adjustments: + """This class contains tunable communication parameters. + + You can either change default_adj to adjust parameters for + all sockets, or you can create a new instance of this class, + change its attributes, and pass it to the channel constructors. + """ # backlog is the argument to pass to socket.listen(). backlog = 1024 === Zope3/lib/python/Zope/Server/DualModeChannel.py 1.1.2.4.2.5 => 1.1.2.4.2.6 === -class AlternateSocketMapMixin: - """Mixin for asyncore.dispatcher to more easily support - alternate socket maps""" - - socket_map = None - - def add_channel(self, map=None): - if map is None: - map = self.socket_map - asyncore.dispatcher.add_channel(self, map) - - def del_channel(self, map=None): - if map is None: - map = self.socket_map - asyncore.dispatcher.del_channel(self, map) - def pull_trigger(self): - pull_trigger = getattr(self.socket_map, 'pull_trigger', None) - if pull_trigger is not None: - # Use the trigger from the socket map. - pull_trigger() - else: - SelectTrigger.the_trigger.pull_trigger() - - -class ASMTrigger(AlternateSocketMapMixin, SelectTrigger.Trigger): - """Trigger for an alternate socket map""" - - def __init__(self, socket_map): - self.socket_map = socket_map - select_trigger.trigger.__init__(self) - - pull_trigger = SelectTrigger.Trigger.pull_trigger - - -class SocketMapWithTrigger(UserDict): - - def __init__(self): - UserDict.__init__(self) - self.pull_trigger = ASMTrigger(self).pull_trigger +class DualModeChannel(asyncore.dispatcher): + """Channel that switches between asynchronous and synchronous mode. + Call set_sync() before using a channel in a thread other than + the thread handling the main loop. -class DualModeChannel(AlternateSocketMapMixin, asyncore.dispatcher): - """Channel that switches between asynchronous and synchronous mode. + Call set_async() to give the channel back to the thread handling + the main loop. """ __implements__ = asyncore.dispatcher.__implements__ @@ -85,12 +50,11 @@ # boolean: async or sync mode async_mode = 1 - def __init__(self, conn, addr, adj=None, socket_map=None): + def __init__(self, conn, addr, adj=None): self.addr = addr if adj is None: adj = default_adj self.adj = adj - self.socket_map = socket_map self.outbuf = OverflowableBuffer(adj.outbuf_overflow) self.creation_time = time() asyncore.dispatcher.__init__(self, conn) @@ -209,6 +173,11 @@ # METHODS USED IN BOTH MODES # + def pull_trigger(self): + """Wakes up the main loop. + """ + SelectTrigger.the_trigger.pull_trigger() + def _flush_some(self): """Flushes data. @@ -252,7 +221,7 @@ __implements__ = asyncore.dispatcher.__implements__ - def __init__(self, conn, addr, adj=None, socket_map=None): + def __init__(self, conn, addr, adj=None): global allocate_lock if allocate_lock is None: from thread import allocate_lock @@ -263,7 +232,7 @@ self._writelock_acquire = writelock.acquire self._writelock_release = writelock.release self._writelock_locked = writelock.locked - DualModeChannel.__init__(self, conn, addr, adj, socket_map) + DualModeChannel.__init__(self, conn, addr, adj) # # ASYNCHRONOUS METHODS === Zope3/lib/python/Zope/Server/ServerBase.py 1.1.2.4.2.3 => 1.1.2.4.2.4 === import socket -from DualModeChannel import AlternateSocketMapMixin from Adjustments import default_adj from IServer import IServer -class ServerBase(AlternateSocketMapMixin, asyncore.dispatcher, object): +class ServerBase(asyncore.dispatcher, object): """Async. server base for launching derivatives of ServerChannelBase. """ @@ -35,11 +34,10 @@ SERVER_IDENT = 'Zope.Server.ServerBase' # Override. def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1, - hit_log=None, verbose=0, socket_map=None): + hit_log=None, verbose=0): if adj is None: adj = default_adj self.adj = adj - self.socket_map = socket_map asyncore.dispatcher.__init__(self) self.port = port self.task_dispatcher = task_dispatcher @@ -133,7 +131,7 @@ self.log_info ('warning: server accept() threw an exception', 'warning') return - self.channel_class(self, conn, addr, self.adj, self.socket_map) + self.channel_class(self, conn, addr, self.adj) # ############################################################ === Zope3/lib/python/Zope/Server/ServerChannelBase.py 1.1.2.6 => 1.1.2.7 === # - def __init__(self, server, conn, addr, adj=None, socket_map=None): - ChannelBaseClass.__init__(self, conn, addr, adj, socket_map) + def __init__(self, server, conn, addr, adj=None): + ChannelBaseClass.__init__(self, conn, addr, adj) self.server = server self.last_activity = t = self.creation_time self.check_maintenance(t) From shane@cvs.zope.org Wed Apr 10 22:59:52 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Wed, 10 Apr 2002 17:59:52 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - TestFilesystemAccess.py:1.1.2.1 UsernamePassword.py:1.1.2.1 FTPServer.py:1.1.2.11 FTPServerChannel.py:1.1.2.21 PublisherFTPServer.py:1.1.2.6 RecvChannel.py:1.1.2.7 XmitChannel.py:1.1.2.6 Message-ID: <200204102159.g3ALxqx18436@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv18340/FTP Modified Files: Tag: Zope3-Server-Branch FTPServer.py FTPServerChannel.py PublisherFTPServer.py RecvChannel.py XmitChannel.py Added Files: Tag: Zope3-Server-Branch TestFilesystemAccess.py UsernamePassword.py Log Message: - Removed AlternateSocketMapMixin. It was there to support multiple socket maps, but if we really need multiple socket maps, it would be better to change asyncore. Had to update a lot of __init__ methods. - Added IUsernamePassword and IFilesystemAccess, which provide a way to implement all kinds of authentication schemes without FTP knowing about any of the details. Modified FTPServerChannel to work based on an IFilesystemAccess object. - Added detection of the ZOPE_SERVER_DEBUG env var. - Added comments here and there. - Fixed CRs :-) === Added File Zope3/lib/python/Zope/Server/FTP/TestFilesystemAccess.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Implementation of IFilesystemAccess intended only for testing. $Id: TestFilesystemAccess.py,v 1.1.2.1 2002/04/10 21:59:21 shane Exp $ """ from Zope.Server.VFS.IFilesystemAccess import IFilesystemAccess from Zope.Server.VFS.IUsernamePassword import IUsernamePassword from Zope.Exceptions import Unauthorized class TestFilesystemAccess: __implements__ = IFilesystemAccess passwords = {'foo': 'bar'} def __init__(self, fs): self.fs = fs def authenticate(self, credentials): if not IUsernamePassword.isImplementedBy(credentials): raise Unauthorized name = credentials.getUserName() if not self.passwords.has_key(name): raise Unauthorized if credentials.getPassword() != self.passwords[name]: raise Unauthorized def open(self, credentials): self.authenticate(credentials) return self.fs === Added File Zope3/lib/python/Zope/Server/FTP/UsernamePassword.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: UsernamePassword.py,v 1.1.2.1 2002/04/10 21:59:21 shane Exp $ """ from Zope.Server.VFS.IUsernamePassword import IUsernamePassword class UsernamePassword: __implements__ = IUsernamePassword def __init__(self, username, password): self.username = username self.password = password def getUserName(self): return self.username def getPassword(self): return self.password === Zope3/lib/python/Zope/Server/FTP/FTPServer.py 1.1.2.10 => 1.1.2.11 === from FTPServerChannel import FTPServerChannel from Zope.Server.ServerBase import ServerBase +from Zope.Server.VFS.IFilesystemAccess import IFilesystemAccess -from Zope.Server.VFS.UnixFileSystem import \ - SchizophrenicUnixFileSystem -from Zope.Server.Authentication.DictionaryAuthentication import \ - DictionaryAuthentication - - -class FileSystemOpener: - - filesystem_class = SchizophrenicUnixFileSystem - - def __init__(self, root_dir): - self.root_dir = root_dir - - def __call__(self, username): - persona = pwd.getpwnam(username)[2:4] - return self.filesystem_class(self.root_dir, persona) class FTPServer(ServerBase): @@ -45,24 +30,23 @@ SERVER_IDENT = 'Zope.Server.FTPServer' - def __init__(self, ip, port, dir='/', auth_source=None, - task_dispatcher=None, adj=None, start=1, hit_log=None, - verbose=0, socket_map=None): - - self.openFilesystem = FileSystemOpener(dir) - self.auth_source = auth_source - - super(FTPServer, self).__init__(ip, port, task_dispatcher, - adj, start, hit_log, - verbose, socket_map) + def __init__(self, ip, port, fs_access, *args, **kw): + + assert IFilesystemAccess.isImplementedBy(fs_access) + self.fs_access = fs_access + + super(FTPServer, self).__init__(ip, port, *args, **kw) if __name__ == '__main__': from Zope.Server.TaskThreads import ThreadedTaskDispatcher + from Zope.Server.VFS.OSFileSystem import OSFileSystem + from TestFilesystemAccess import TestFilesystemAccess td = ThreadedTaskDispatcher() td.setThreadCount(4) - auth_source = DictionaryAuthentication({'root': 'bar'}) - FTPServer('', 8021, '/', auth_source, task_dispatcher=td) + fs = OSFileSystem('/') + fs_access = TestFilesystemAccess(fs) + FTPServer('', 8021, fs_access, task_dispatcher=td) try: while 1: asyncore.poll(5) === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.20 => 1.1.2.21 === from RecvChannel import RecvChannel from XmitChannel import XmitChannel, ApplicationXmitStream +from UsernamePassword import UsernamePassword +from Zope.Exceptions import Unauthorized class FTPServerChannel(LineServerChannel): @@ -70,9 +72,8 @@ type_mode_map = {'a':'t', 'i':'b', 'e':'b', 'l':'b'} - def __init__(self, server, conn, addr, adj=None, socket_map=None): - super(FTPServerChannel, self).__init__(server, conn, addr, - adj, socket_map) + def __init__(self, server, conn, addr, adj=None): + super(FTPServerChannel, self).__init__(server, conn, addr, adj) self.client_addr = (addr[0], 21) @@ -85,14 +86,14 @@ self._rnfr = None self.username = '' - self.password = '' + self.credentials = None self.reply('SERVER_READY', self.server.server_name) def _getFilesystem(self): - """Open the filesystem using the username and password.""" - return self.server.openFilesystem(self.username, self.password) + """Open the filesystem using the current credentials.""" + return self.server.fs_access.open(self.credentials) ############################################################ @@ -222,13 +223,18 @@ def cmd_pass(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' - self.password = args - self.authenticated, message = self.authenticate() - if self.authenticated: - self.reply('LOGIN_SUCCESS') - else: + self.authenticated = 0 + password = args + credentials = UsernamePassword(self.username, password) + try: + self.server.fs_access.authenticate(credentials) + except Unauthorized: self.reply('LOGIN_MISMATCH') self.close_when_done() + else: + self.credentials = credentials + self.authenticated = 1 + self.reply('LOGIN_SUCCESS') def cmd_pasv(self, args): @@ -439,6 +445,7 @@ def cmd_user(self, args): 'See Zope.Server.FTP.IFTPCommandHandler.IFTPCommandHandler' + self.authenticated = 0 if len(args) > 1: self.username = args self.reply('PASS_REQUIRED') @@ -454,17 +461,13 @@ path = args else: path = os.path.join(self.cwd, args) - path = os.path.normpath(path) + # Note: don't use os.path.normpath() here! Otherwise Zope won't + # work on case-insensitive platforms. return path - def authenticate(self): - auth = self.server.auth_source - return auth.authenticate(self.username, self.password) - - def newPassiveAcceptor(self): - # ensure that only one of these exists at a time. + # ensure that only one of these exists at a time. if self.passive_acceptor is not None: self.passive_acceptor.close() self.passive_acceptor = None === Zope3/lib/python/Zope/Server/FTP/PublisherFTPServer.py 1.1.2.5 => 1.1.2.6 === def __init__(self, request_factory, name, ip, port, task_dispatcher=None, adj=None, start=1, hit_log=None, - verbose=0, socket_map=None): + verbose=0): self.request_factory = request_factory self.openFilesystem = PublisherFileSystemOpener('/', request_factory) super(PublisherFTPServer, self).__init__(ip, port, task_dispatcher, adj, start, hit_log, - verbose, socket_map) + verbose) === Zope3/lib/python/Zope/Server/FTP/RecvChannel.py 1.1.2.6 => 1.1.2.7 === _fileno = None # provide a default for asyncore.dispatcher._fileno - def __init__ (self, control_channel, finish_args, - adj=None, socket_map=None): + def __init__ (self, control_channel, finish_args): self.control_channel = control_channel self.finish_args = finish_args self.inbuf = OverflowableBuffer(control_channel.adj.inbuf_overflow) - ChannelBaseClass.__init__(self, None, None, adj, socket_map) + ChannelBaseClass.__init__(self, None, None, control_channel.adj) # Note that this channel starts out in async mode. def writable (self): === Zope3/lib/python/Zope/Server/FTP/XmitChannel.py 1.1.2.5 => 1.1.2.6 === _fileno = None # provide a default for asyncore.dispatcher._fileno - def __init__ (self, control_channel, ok_reply_args, - adj=None, socket_map=None): + def __init__ (self, control_channel, ok_reply_args): self.control_channel = control_channel self.ok_reply_args = ok_reply_args self.set_sync() - ChannelBaseClass.__init__(self, None, None, adj, socket_map) + ChannelBaseClass.__init__(self, None, None, control_channel.adj) def _open(self): """Signal the client to open the connection.""" From shane@cvs.zope.org Wed Apr 10 22:59:52 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Wed, 10 Apr 2002 17:59:52 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP/tests - testFTPServer.py:1.1.2.4 Message-ID: <200204102159.g3ALxqg18439@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP/tests In directory cvs.zope.org:/tmp/cvs-serv18340/FTP/tests Modified Files: Tag: Zope3-Server-Branch testFTPServer.py Log Message: - Removed AlternateSocketMapMixin. It was there to support multiple socket maps, but if we really need multiple socket maps, it would be better to change asyncore. Had to update a lot of __init__ methods. - Added IUsernamePassword and IFilesystemAccess, which provide a way to implement all kinds of authentication schemes without FTP knowing about any of the details. Modified FTPServerChannel to work based on an IFilesystemAccess object. - Added detection of the ZOPE_SERVER_DEBUG env var. - Added comments here and there. - Fixed CRs :-) === Zope3/lib/python/Zope/Server/FTP/tests/testFTPServer.py 1.1.2.3 => 1.1.2.4 === from Zope.Server.ITask import ITask -from Zope.Server.Authentication.DictionaryAuthentication import \ - DictionaryAuthentication +from Zope.Server.VFS.OSFileSystem import OSFileSystem +from Zope.Server.FTP.TestFilesystemAccess import TestFilesystemAccess import ftplib @@ -46,9 +46,6 @@ my_adj = Adjustments() -# Reduce overflows to make testing easier. -my_adj.outbuf_overflow = 10000 -my_adj.inbuf_overflow = 10000 def retrlines(ftpconn, cmd): @@ -67,8 +64,10 @@ os.mkdir(self.root_dir) os.mkdir(os.path.join(self.root_dir, 'test')) - self.server = FTPServer(LOCALHOST, SERVER_PORT, self.root_dir, - DictionaryAuthentication({'foo': 'bar'}), + fs = OSFileSystem(self.root_dir) + fs_access = TestFilesystemAccess(fs) + + self.server = FTPServer(LOCALHOST, SERVER_PORT, fs_access, task_dispatcher=td, adj=my_adj) if CONNECT_TO_PORT == 0: self.port = self.server.socket.getsockname()[1] From shane@cvs.zope.org Wed Apr 10 22:59:52 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Wed, 10 Apr 2002 17:59:52 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/LineReceiver - LineServerChannel.py:1.1.2.7 Message-ID: <200204102159.g3ALxq518442@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/LineReceiver In directory cvs.zope.org:/tmp/cvs-serv18340/LineReceiver Modified Files: Tag: Zope3-Server-Branch LineServerChannel.py Log Message: - Removed AlternateSocketMapMixin. It was there to support multiple socket maps, but if we really need multiple socket maps, it would be better to change asyncore. Had to update a lot of __init__ methods. - Added IUsernamePassword and IFilesystemAccess, which provide a way to implement all kinds of authentication schemes without FTP knowing about any of the details. Modified FTPServerChannel to work based on an IFilesystemAccess object. - Added detection of the ZOPE_SERVER_DEBUG env var. - Added comments here and there. - Fixed CRs :-) === Zope3/lib/python/Zope/Server/LineReceiver/LineServerChannel.py 1.1.2.6 => 1.1.2.7 === +DEBUG = os.environ.get('ZOPE_SERVER_DEBUG') + + class LineServerChannel(ServerChannelBase): """The Line Server Channel represents a connection to a particular client. We can therefore store information here.""" @@ -108,6 +111,9 @@ def exception(self): + if DEBUG: + import traceback + traceback.print_exc() t, v = sys.exc_info()[:2] try: info = '%s: %s' % (getattr(t, '__name__', t), v) From shane@cvs.zope.org Wed Apr 10 22:59:52 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Wed, 10 Apr 2002 17:59:52 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/POP3 - POP3Server.py:1.1.2.3 POP3ServerChannel.py:1.1.2.3 Message-ID: <200204102159.g3ALxql18446@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/POP3 In directory cvs.zope.org:/tmp/cvs-serv18340/POP3 Modified Files: Tag: Zope3-Server-Branch POP3Server.py POP3ServerChannel.py Log Message: - Removed AlternateSocketMapMixin. It was there to support multiple socket maps, but if we really need multiple socket maps, it would be better to change asyncore. Had to update a lot of __init__ methods. - Added IUsernamePassword and IFilesystemAccess, which provide a way to implement all kinds of authentication schemes without FTP knowing about any of the details. Modified FTPServerChannel to work based on an IFilesystemAccess object. - Added detection of the ZOPE_SERVER_DEBUG env var. - Added comments here and there. - Fixed CRs :-) === Zope3/lib/python/Zope/Server/POP3/POP3Server.py 1.1.2.2 => 1.1.2.3 === def __init__(self, ip, port, maildir, auth, task_dispatcher=None, - adj=None, start=1, hit_log=None, verbose=0, - socket_map=None): + adj=None, start=1, hit_log=None, verbose=0): self.auth_source = auth self.maildir = UnixFileSystem(maildir) super(POP3Server, self).__init__(ip, port, task_dispatcher, - adj, start, hit_log, - verbose, socket_map) + adj, start, hit_log, verbose) if __name__ == '__main__': === Zope3/lib/python/Zope/Server/POP3/POP3ServerChannel.py 1.1.2.2 => 1.1.2.3 === 'UIDL [MESG-INDEX', 'USER MAILBOX') - def __init__(self, server, conn, addr, adj=None, socket_map=None): - super(POP3ServerChannel, self).__init__(server, conn, addr, - adj, socket_map) + def __init__(self, server, conn, addr, adj=None): + super(POP3ServerChannel, self).__init__(server, conn, addr, adj) self.username = '' self.password = '' From fdrake@acm.org Wed Apr 10 23:45:37 2002 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Wed, 10 Apr 2002 18:45:37 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/HTTP - HTTPRequest.py:1.1.2.25 Message-ID: <200204102245.g3AMjbq00845@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/HTTP In directory cvs.zope.org:/tmp/cvs-serv830/HTTP Modified Files: Tag: Zope-3x-branch HTTPRequest.py Log Message: Use the random module instead of the deprecated whrandom module. whrandom triggers a DeprecationWarning when using CVS Python. === Zope3/lib/python/Zope/Publisher/HTTP/HTTPRequest.py 1.1.2.24 => 1.1.2.25 === """ -import re, time, whrandom +import re, time, random from urllib import quote, splitport from types import StringType @@ -295,7 +295,7 @@ 'See Zope.Publisher.IPublisherRequest.IPublisherRequest' if self._retry_count < self.retry_max_count: if STAGGER_RETRIES: - time.sleep(whrandom.uniform(0, 2**(self.retry_count))) + time.sleep(random.uniform(0, 2**(self.retry_count))) return 1 From fdrake@acm.org Thu Apr 11 03:59:21 2002 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Wed, 10 Apr 2002 22:59:21 -0400 Subject: [Zope-Checkins] CVS: Packages/webdav - client.py:1.19 Message-ID: <200204110259.g3B2xL503453@cvs.baymountain.com> Update of /cvs-repository/Packages/webdav In directory cvs.zope.org:/tmp/cvs-serv3396/lib/python/webdav Modified Files: client.py Log Message: Use the random module instead of the deprecated whrandom module. whrandom triggers a DeprecationWarning when using CVS Python. === Packages/webdav/client.py 1.18 => 1.19 === from common import rfc1123_date from cStringIO import StringIO -from whrandom import random +from random import random from urllib import quote From fdrake@acm.org Thu Apr 11 04:01:05 2002 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Wed, 10 Apr 2002 23:01:05 -0400 Subject: [Zope-Checkins] CVS: Packages/ZPublisher - HTTPRequest.py:1.65 Message-ID: <200204110301.g3B315L04932@cvs.baymountain.com> Update of /cvs-repository/Packages/ZPublisher In directory cvs.zope.org:/tmp/cvs-serv4922/ZPublisher Modified Files: HTTPRequest.py Log Message: Use the random module instead of the deprecated whrandom module. whrandom triggers a DeprecationWarning when using CVS Python. === Packages/ZPublisher/HTTPRequest.py 1.64 => 1.65 === __version__='$Revision$'[11:-2] -import re, sys, os, urllib, time, whrandom, cgi, codecs +import re, sys, os, urllib, time, random, cgi, codecs from BaseRequest import BaseRequest from HTTPResponse import HTTPResponse from cgi import FieldStorage, escape @@ -114,7 +114,7 @@ retry_max_count=3 def supports_retry(self): if self.retry_count < self.retry_max_count: - time.sleep(whrandom.uniform(0, 2**(self.retry_count))) + time.sleep(random.uniform(0, 2**(self.retry_count))) return 1 def retry(self): From fdrake@acm.org Thu Apr 11 04:03:31 2002 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Wed, 10 Apr 2002 23:03:31 -0400 Subject: [Zope-Checkins] CVS: Releases/Zope/lib/python/Products/Transience/tests - testTimeoutRelated.py:1.6 testTransientObject.py:1.6 Message-ID: <200204110303.g3B33V205806@cvs.baymountain.com> Update of /cvs-repository/Releases/Zope/lib/python/Products/Transience/tests In directory cvs.zope.org:/tmp/cvs-serv5780 Modified Files: testTimeoutRelated.py testTransientObject.py Log Message: Remove unused import of deprecated module. === Releases/Zope/lib/python/Products/Transience/tests/testTimeoutRelated.py 1.5 => 1.6 === from ZODB.DemoStorage import DemoStorage from OFS.Application import Application -import threading, whrandom +import threading import fauxtime import time as oldtime === Releases/Zope/lib/python/Products/Transience/tests/testTransientObject.py 1.5 => 1.6 === # ############################################################################## -import sys, os, whrandom, unittest +import sys, os, unittest if __name__ == "__main__": sys.path.insert(0, '../../..') From fdrake@acm.org Thu Apr 11 04:04:36 2002 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Wed, 10 Apr 2002 23:04:36 -0400 Subject: [Zope-Checkins] CVS: Releases/Zope/lib/python/Products/Transience/tests - testTransientObjectContainer.py:1.8 Message-ID: <200204110304.g3B34aV06459@cvs.baymountain.com> Update of /cvs-repository/Releases/Zope/lib/python/Products/Transience/tests In directory cvs.zope.org:/tmp/cvs-serv6439 Modified Files: testTransientObjectContainer.py Log Message: Use the random module instead of the deprecated whrandom module. whrandom triggers a DeprecationWarning when using CVS Python. === Releases/Zope/lib/python/Products/Transience/tests/testTransientObjectContainer.py 1.7 => 1.8 === # ############################################################################## -import sys, os, time, whrandom, unittest +import sys, os, time, random, unittest if __name__ == "__main__": sys.path.insert(0, '../../..') @@ -165,7 +165,7 @@ added = {} r = range(10, 110) for x in r: - k = whrandom.choice(r) + k = random.choice(r) if not added.has_key(k): self.t[k] = x added[k] = 1 @@ -177,7 +177,7 @@ added = {} r = range(10, 110) for x in r: - k = whrandom.choice(r) + k = random.choice(r) self.t[k] = x added[k] = 1 addl = added.keys() @@ -188,12 +188,12 @@ r = range(10, 1010) added = [] for x in r: - k = whrandom.choice(r) + k = random.choice(r) self.t[k] = x added.append(k) deleted = [] for x in r: - k = whrandom.choice(r) + k = random.choice(r) if self.t.has_key(k): del self.t[k] deleted.append(k) @@ -208,7 +208,7 @@ def testTargetedDeletes(self): r = range(10, 1010) for x in r: - k = whrandom.choice(r) + k = random.choice(r) self.t[k] = x for x in r: try: @@ -372,7 +372,7 @@ added = {} r = range(10, 1010) for x in r: - k = whrandom.choice(r) + k = random.choice(r) self.t[k] = x added[k] = x addl = added.keys() From fdrake@acm.org Thu Apr 11 04:06:14 2002 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Wed, 10 Apr 2002 23:06:14 -0400 Subject: [Zope-Checkins] CVS: Packages/OFS/tests - testRanges.py:1.12 Message-ID: <200204110306.g3B36EE08084@cvs.baymountain.com> Update of /cvs-repository/Packages/OFS/tests In directory cvs.zope.org:/tmp/cvs-serv8077/OFS/tests Modified Files: testRanges.py Log Message: Use the random module instead of the deprecated whrandom module. === Packages/OFS/tests/testRanges.py 1.11 => 1.12 === import os, sys, unittest -import string, whrandom, cStringIO, time, re +import string, random, cStringIO, time, re import ZODB from OFS.Application import Application from OFS.Folder import manage_addFolder @@ -37,7 +37,7 @@ file = cStringIO.StringIO() def addLetter(x, add=file.write, l=string.letters, - c=whrandom.choice): + c=random.choice): add(c(l)) filter(addLetter, range(size)) From fdrake@acm.org Thu Apr 11 04:08:45 2002 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Wed, 10 Apr 2002 23:08:45 -0400 Subject: [Zope-Checkins] CVS: Releases/Zope/lib/python/Products/Sessions/tests - testSessionDataManager.py:1.10 Message-ID: <200204110308.g3B38jJ08819@cvs.baymountain.com> Update of /cvs-repository/Releases/Zope/lib/python/Products/Sessions/tests In directory cvs.zope.org:/tmp/cvs-serv8811/tests Modified Files: testSessionDataManager.py Log Message: Remove unused import of deprecated module. === Releases/Zope/lib/python/Products/Sessions/tests/testSessionDataManager.py 1.9 => 1.10 === from DateTime import DateTime from unittest import TestCase, TestSuite, TextTestRunner, makeSuite -import time, threading, whrandom +import time, threading from cPickle import UnpickleableError from ZODB.DemoStorage import DemoStorage from OFS.Application import Application From fdrake@acm.org Thu Apr 11 04:09:03 2002 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Wed, 10 Apr 2002 23:09:03 -0400 Subject: [Zope-Checkins] CVS: Releases/Zope/lib/python/Products/Sessions/stresstests - stresstestMultiThread.py:1.2 Message-ID: <200204110309.g3B393U08940@cvs.baymountain.com> Update of /cvs-repository/Releases/Zope/lib/python/Products/Sessions/stresstests In directory cvs.zope.org:/tmp/cvs-serv8915/stresstests Modified Files: stresstestMultiThread.py Log Message: Use the random module instead of the deprecated whrandom module. === Releases/Zope/lib/python/Products/Sessions/stresstests/stresstestMultiThread.py 1.1 => 1.2 === from DateTime import DateTime from unittest import TestCase, TestSuite, TextTestRunner, makeSuite -import time, threading, whrandom +import time, threading, random from cPickle import UnpickleableError from ZODB.DemoStorage import DemoStorage from OFS.Application import Application @@ -185,7 +185,7 @@ data = session_data_manager.getSessionData() if not data.has_key(t): self.out.append(1) - time.sleep(whrandom.choice(range(3))) + time.sleep(random.choice(range(3))) get_transaction().commit() class WriterThread(BaseReaderWriter): @@ -194,7 +194,7 @@ for i in range(self.iters): data = session_data_manager.getSessionData() data[time.time()] = 1 - n = whrandom.choice(range(3)) + n = random.choice(range(3)) time.sleep(n) if n % 2 == 0: get_transaction().commit() From srichter@cbu.edu Thu Apr 11 05:32:09 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 11 Apr 2002 00:32:09 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/Authentication - DictionaryAuthentication.py:NONE IAuthentication.py:NONE IUser.py:NONE SimpleUser.py:NONE UnixAuthentication.py:NONE __init__.py:NONE Message-ID: <200204110432.g3B4W9p03215@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/Authentication In directory cvs.zope.org:/tmp/cvs-serv25892/lib/python/Zope/Server/Authentication Removed Files: Tag: Zope3-Server-Branch DictionaryAuthentication.py IAuthentication.py IUser.py SimpleUser.py UnixAuthentication.py __init__.py Log Message: Wee, quiet a bit of changes, but they fix and finnish the stuff Shane did earlier today. - Removed a lot of old files and moved some to more appropriate places. The removal of the Suthentication directory is probably the biggest one. I also deleted all the other FileSystem types, like MSDOS and Unix, since the FielSystem is not returning formatted lists anymore. Yipee! - Fixed PublisherFTPServer, so it works with Shane's new Credentials interfaces. Everything should be working fine again. - Fixed the POP3 and SMTP code to work with the new model. It all works really well. I hope that Gerson Kurz will take over this development soon. I also contacted authors of other server protocols, and they might join. Rich Salz is already writing a method for ZSI, so that we can insert SOAP in the next days. - Made most tests run again and updated them. I still have one error. I know why it is caused, but I do not know how to correct. I know it is a test environment problem though, not a code one. === Removed File Zope3/lib/python/Zope/Server/Authentication/DictionaryAuthentication.py === === Removed File Zope3/lib/python/Zope/Server/Authentication/IAuthentication.py === === Removed File Zope3/lib/python/Zope/Server/Authentication/IUser.py === === Removed File Zope3/lib/python/Zope/Server/Authentication/SimpleUser.py === === Removed File Zope3/lib/python/Zope/Server/Authentication/UnixAuthentication.py === === Removed File Zope3/lib/python/Zope/Server/Authentication/__init__.py === From srichter@cbu.edu Thu Apr 11 05:32:10 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 11 Apr 2002 00:32:10 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/Authentication/tests - __init__.py:NONE testDictionaryAuthentication.py:NONE testSimpleUser.py:NONE Message-ID: <200204110432.g3B4WAo03224@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/Authentication/tests In directory cvs.zope.org:/tmp/cvs-serv25892/lib/python/Zope/Server/Authentication/tests Removed Files: Tag: Zope3-Server-Branch __init__.py testDictionaryAuthentication.py testSimpleUser.py Log Message: Wee, quiet a bit of changes, but they fix and finnish the stuff Shane did earlier today. - Removed a lot of old files and moved some to more appropriate places. The removal of the Suthentication directory is probably the biggest one. I also deleted all the other FileSystem types, like MSDOS and Unix, since the FielSystem is not returning formatted lists anymore. Yipee! - Fixed PublisherFTPServer, so it works with Shane's new Credentials interfaces. Everything should be working fine again. - Fixed the POP3 and SMTP code to work with the new model. It all works really well. I hope that Gerson Kurz will take over this development soon. I also contacted authors of other server protocols, and they might join. Rich Salz is already writing a method for ZSI, so that we can insert SOAP in the next days. - Made most tests run again and updated them. I still have one error. I know why it is caused, but I do not know how to correct. I know it is a test environment problem though, not a code one. === Removed File Zope3/lib/python/Zope/Server/Authentication/tests/__init__.py === === Removed File Zope3/lib/python/Zope/Server/Authentication/tests/testDictionaryAuthentication.py === === Removed File Zope3/lib/python/Zope/Server/Authentication/tests/testSimpleUser.py === From srichter@cbu.edu Thu Apr 11 05:32:14 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 11 Apr 2002 00:32:14 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS/tests - testOSFileSystem.py:1.1.2.8 Message-ID: <200204110432.g3B4WEj03299@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS/tests In directory cvs.zope.org:/tmp/cvs-serv25892/lib/python/Zope/Server/VFS/tests Modified Files: Tag: Zope3-Server-Branch testOSFileSystem.py Log Message: Wee, quiet a bit of changes, but they fix and finnish the stuff Shane did earlier today. - Removed a lot of old files and moved some to more appropriate places. The removal of the Suthentication directory is probably the biggest one. I also deleted all the other FileSystem types, like MSDOS and Unix, since the FielSystem is not returning formatted lists anymore. Yipee! - Fixed PublisherFTPServer, so it works with Shane's new Credentials interfaces. Everything should be working fine again. - Fixed the POP3 and SMTP code to work with the new model. It all works really well. I hope that Gerson Kurz will take over this development soon. I also contacted authors of other server protocols, and they might join. Rich Salz is already writing a method for ZSI, so that we can insert SOAP in the next days. - Made most tests run again and updated them. I still have one error. I know why it is caused, but I do not know how to correct. I know it is a test environment problem though, not a code one. === Zope3/lib/python/Zope/Server/VFS/tests/testOSFileSystem.py 1.1.2.7 => 1.1.2.8 === open(path, 'w').write('test') self.assertEqual(self.filesystem.listdir('/', 0), - 'foo\r\n') - os.remove(path) - - - def testLongify(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('test') - stat_info = os.stat(path) - result = self.filesystem.longify('foo', stat_info) - self.failUnless(result.endswith('foo')) + ['foo']) os.remove(path) From srichter@cbu.edu Thu Apr 11 05:32:13 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 11 Apr 2002 00:32:13 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - TestFilesystemAccess.py:1.1.2.1 UsernamePassword.py:1.1.2.1 PublisherFileSystem.py:1.1.2.8 ListProducer.py:NONE MSDOSFileSystem.py:NONE MergedFileSystem.py:NONE UnixFileSystem.py:NONE Message-ID: <200204110432.g3B4WDc03298@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv25892/lib/python/Zope/Server/VFS Modified Files: Tag: Zope3-Server-Branch PublisherFileSystem.py Added Files: Tag: Zope3-Server-Branch TestFilesystemAccess.py UsernamePassword.py Removed Files: Tag: Zope3-Server-Branch ListProducer.py MSDOSFileSystem.py MergedFileSystem.py UnixFileSystem.py Log Message: Wee, quiet a bit of changes, but they fix and finnish the stuff Shane did earlier today. - Removed a lot of old files and moved some to more appropriate places. The removal of the Suthentication directory is probably the biggest one. I also deleted all the other FileSystem types, like MSDOS and Unix, since the FielSystem is not returning formatted lists anymore. Yipee! - Fixed PublisherFTPServer, so it works with Shane's new Credentials interfaces. Everything should be working fine again. - Fixed the POP3 and SMTP code to work with the new model. It all works really well. I hope that Gerson Kurz will take over this development soon. I also contacted authors of other server protocols, and they might join. Rich Salz is already writing a method for ZSI, so that we can insert SOAP in the next days. - Made most tests run again and updated them. I still have one error. I know why it is caused, but I do not know how to correct. I know it is a test environment problem though, not a code one. === Added File Zope3/lib/python/Zope/Server/VFS/TestFilesystemAccess.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Implementation of IFilesystemAccess intended only for testing. $Id: TestFilesystemAccess.py,v 1.1.2.1 2002/04/11 04:32:11 srichter Exp $ """ from Zope.Server.VFS.IFilesystemAccess import IFilesystemAccess from Zope.Server.VFS.IUsernamePassword import IUsernamePassword from Zope.Exceptions import Unauthorized class TestFilesystemAccess: __implements__ = IFilesystemAccess passwords = {'foo': 'bar'} def __init__(self, fs): self.fs = fs def authenticate(self, credentials): if not IUsernamePassword.isImplementedBy(credentials): raise Unauthorized name = credentials.getUserName() if not self.passwords.has_key(name): raise Unauthorized if credentials.getPassword() != self.passwords[name]: raise Unauthorized def open(self, credentials): self.authenticate(credentials) return self.fs def hasUser(self, username): return self.passwords.has_key(username) def getPassword(self, username): return self.passwords.get(username, None) === Added File Zope3/lib/python/Zope/Server/VFS/UsernamePassword.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: UsernamePassword.py,v 1.1.2.1 2002/04/11 04:32:11 srichter Exp $ """ from Zope.Server.VFS.IUsernamePassword import IUsernamePassword class UsernamePassword: __implements__ = IUsernamePassword def __init__(self, username, password): self.username = username self.password = password def getUserName(self): return self.username def getPassword(self): return self.password === Zope3/lib/python/Zope/Server/VFS/PublisherFileSystem.py 1.1.2.7 => 1.1.2.8 === from IWriteFileSystem import IWriteFileSystem -from Zope.App.Security.PrincipalRegistry import principalRegistry from Zope.Publisher.Publish import publish -from ListProducer import ListProducer class PublisherFileSystem: @@ -37,46 +35,25 @@ __implements__ = IReadFileSystem, IWriteFileSystem path_module = os.path - request_factory = None + def __init__ (self, credentials, request_factory): + self.credentials = credentials + self.request_factory = request_factory - def __init__ (self, root, username, password): - self.root = root - self.username = username - self.password = password - - - - def _create_request(self, env): - env['username'] = self.username - env['password'] = self.password - request = self.request_factory(StringIO(''), StringIO(), env) - return request def _execute(self, path, command, env=None): - if env is None: env = {} env['command'] = command env['path'] = path - - request = self._create_request(env) + env['credentials'] = self.credentials + request = self.request_factory(StringIO(''), StringIO(), env) # Note that publish() calls close() on request, which deletes the - # response from the request, so that we need to keep trakc of it. + # response from the request, so that we need to keep track of it. response = request.getResponse() publish(request) - return response.getResult() - - - def _authenticate(self): - request = self._create_request({}) - id = principalRegistry.authenticate(request) - if id is None: - return 0 - else: - return 1 - + return response.getResult() ############################################################ @@ -192,7 +169,7 @@ # utility methods - def normalize (self, path): + def normalize(self, path): # watch for the ever-sneaky '/+' path element path = re.sub('/+', '/', path) # Someone is trying to get lower than the permitted root. @@ -203,7 +180,7 @@ return path - def translate (self, path): + def translate(self, path): """We need to join together three separate path components, and do it safely. / use the operating system's path separator. @@ -221,5 +198,5 @@ return path - def __repr__ (self): + def __repr__(self): return '' === Removed File Zope3/lib/python/Zope/Server/VFS/ListProducer.py === === Removed File Zope3/lib/python/Zope/Server/VFS/MSDOSFileSystem.py === === Removed File Zope3/lib/python/Zope/Server/VFS/MergedFileSystem.py === === Removed File Zope3/lib/python/Zope/Server/VFS/UnixFileSystem.py === From srichter@cbu.edu Thu Apr 11 05:32:38 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 11 Apr 2002 00:32:38 -0400 Subject: [Zope-Checkins] CVS: Zope3 - startup.zcml:1.1.2.3.4.3 Message-ID: <200204110432.g3B4WcZ03495@cvs.baymountain.com> Update of /cvs-repository/Zope3 In directory cvs.zope.org:/tmp/cvs-serv25892 Modified Files: Tag: Zope3-Server-Branch startup.zcml Log Message: Wee, quiet a bit of changes, but they fix and finnish the stuff Shane did earlier today. - Removed a lot of old files and moved some to more appropriate places. The removal of the Suthentication directory is probably the biggest one. I also deleted all the other FileSystem types, like MSDOS and Unix, since the FielSystem is not returning formatted lists anymore. Yipee! - Fixed PublisherFTPServer, so it works with Shane's new Credentials interfaces. Everything should be working fine again. - Fixed the POP3 and SMTP code to work with the new model. It all works really well. I hope that Gerson Kurz will take over this development soon. I also contacted authors of other server protocols, and they might join. Rich Salz is already writing a method for ZSI, so that we can insert SOAP in the next days. - Made most tests run again and updated them. I still have one error. I know why it is caused, but I do not know how to correct. I know it is a test environment problem though, not a code one. === Zope3/startup.zcml 1.1.2.3.4.2 => 1.1.2.3.4.3 === - xmlns="http://namespaces.zope.org/zope" - xmlns:startup="http://namespaces.zope.org/startup"> - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + From srichter@cbu.edu Thu Apr 11 05:32:38 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 11 Apr 2002 00:32:38 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/File/tests - testFile.py:1.1.2.2.2.1 testNaiveFile.py:1.1.2.2.2.1 Message-ID: <200204110432.g3B4Wcd03503@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File/tests In directory cvs.zope.org:/tmp/cvs-serv25892/lib/python/Zope/App/OFS/Content/File/tests Modified Files: Tag: Zope3-Server-Branch testFile.py testNaiveFile.py Log Message: Wee, quiet a bit of changes, but they fix and finnish the stuff Shane did earlier today. - Removed a lot of old files and moved some to more appropriate places. The removal of the Suthentication directory is probably the biggest one. I also deleted all the other FileSystem types, like MSDOS and Unix, since the FielSystem is not returning formatted lists anymore. Yipee! - Fixed PublisherFTPServer, so it works with Shane's new Credentials interfaces. Everything should be working fine again. - Fixed the POP3 and SMTP code to work with the new model. It all works really well. I hope that Gerson Kurz will take over this development soon. I also contacted authors of other server protocols, and they might join. Rich Salz is already writing a method for ZSI, so that we can insert SOAP in the next days. - Made most tests run again and updated them. I still have one error. I know why it is caused, but I do not know how to correct. I know it is a test environment problem though, not a code one. === Zope3/lib/python/Zope/App/OFS/Content/File/tests/testFile.py 1.1.2.2 => 1.1.2.2.2.1 === self.assertEqual(file.getContentType(), '') - self.assertEqual(file.getData(), None) + self.assertEqual(file.getData(), '') def testConstructor(self): === Zope3/lib/python/Zope/App/OFS/Content/File/tests/testNaiveFile.py 1.1.2.2 => 1.1.2.2.2.1 === self.assertEqual(file.getContentType(), '') - self.assertEqual(file.getData(), None) + self.assertEqual(file.getData(), '') def testConstructor(self): From srichter@cbu.edu Thu Apr 11 05:32:38 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 11 Apr 2002 00:32:38 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/VFS - VFSRequest.py:1.1.2.4 Message-ID: <200204110432.g3B4Wcn03506@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/VFS In directory cvs.zope.org:/tmp/cvs-serv25892/lib/python/Zope/Publisher/VFS Modified Files: Tag: Zope3-Server-Branch VFSRequest.py Log Message: Wee, quiet a bit of changes, but they fix and finnish the stuff Shane did earlier today. - Removed a lot of old files and moved some to more appropriate places. The removal of the Suthentication directory is probably the biggest one. I also deleted all the other FileSystem types, like MSDOS and Unix, since the FielSystem is not returning formatted lists anymore. Yipee! - Fixed PublisherFTPServer, so it works with Shane's new Credentials interfaces. Everything should be working fine again. - Fixed the POP3 and SMTP code to work with the new model. It all works really well. I hope that Gerson Kurz will take over this development soon. I also contacted authors of other server protocols, and they might join. Rich Salz is already writing a method for ZSI, so that we can insert SOAP in the next days. - Made most tests run again and updated them. I still have one error. I know why it is caused, but I do not know how to correct. I know it is a test environment problem though, not a code one. === Zope3/lib/python/Zope/Publisher/VFS/VFSRequest.py 1.1.2.3 => 1.1.2.4 === def _authUserPW(self): 'See Zope.Publisher.VFS.IVFSCredentials.IVFSCredentials' - env = self._environ - return env['username'], env['password'] + credentials = self._environ['credentials'] + return credentials.getUserName(), credentials.getPassword() def unauthorized(self, challenge): 'See Zope.Publisher.VFS.IVFSCredentials.IVFSCredentials' From srichter@cbu.edu Thu Apr 11 05:32:41 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 11 Apr 2002 00:32:41 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP/tests - testFTPServer.py:1.1.2.5 Message-ID: <200204110432.g3B4Wfm03523@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP/tests In directory cvs.zope.org:/tmp/cvs-serv25892/lib/python/Zope/Server/FTP/tests Modified Files: Tag: Zope3-Server-Branch testFTPServer.py Log Message: Wee, quiet a bit of changes, but they fix and finnish the stuff Shane did earlier today. - Removed a lot of old files and moved some to more appropriate places. The removal of the Suthentication directory is probably the biggest one. I also deleted all the other FileSystem types, like MSDOS and Unix, since the FielSystem is not returning formatted lists anymore. Yipee! - Fixed PublisherFTPServer, so it works with Shane's new Credentials interfaces. Everything should be working fine again. - Fixed the POP3 and SMTP code to work with the new model. It all works really well. I hope that Gerson Kurz will take over this development soon. I also contacted authors of other server protocols, and they might join. Rich Salz is already writing a method for ZSI, so that we can insert SOAP in the next days. - Made most tests run again and updated them. I still have one error. I know why it is caused, but I do not know how to correct. I know it is a test environment problem though, not a code one. === Zope3/lib/python/Zope/Server/FTP/tests/testFTPServer.py 1.1.2.4 => 1.1.2.5 === self.server.close() # Make sure all sockets get closed by asyncore normally. - timeout = time() + 5 + timeout = time() + 2 while 1: if len(socket_map) == self.orig_map_size: # Clean! From srichter@cbu.edu Thu Apr 11 05:32:41 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 11 Apr 2002 00:32:41 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - PublisherFilesystemAccess.py:1.1.2.1 FTPServer.py:1.1.2.12 FTPServerChannel.py:1.1.2.22 PublisherFTPServer.py:1.1.2.7 UsernamePassword.py:NONE Message-ID: <200204110432.g3B4Wfh03522@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv25892/lib/python/Zope/Server/FTP Modified Files: Tag: Zope3-Server-Branch FTPServer.py FTPServerChannel.py PublisherFTPServer.py Added Files: Tag: Zope3-Server-Branch PublisherFilesystemAccess.py Removed Files: Tag: Zope3-Server-Branch UsernamePassword.py Log Message: Wee, quiet a bit of changes, but they fix and finnish the stuff Shane did earlier today. - Removed a lot of old files and moved some to more appropriate places. The removal of the Suthentication directory is probably the biggest one. I also deleted all the other FileSystem types, like MSDOS and Unix, since the FielSystem is not returning formatted lists anymore. Yipee! - Fixed PublisherFTPServer, so it works with Shane's new Credentials interfaces. Everything should be working fine again. - Fixed the POP3 and SMTP code to work with the new model. It all works really well. I hope that Gerson Kurz will take over this development soon. I also contacted authors of other server protocols, and they might join. Rich Salz is already writing a method for ZSI, so that we can insert SOAP in the next days. - Made most tests run again and updated them. I still have one error. I know why it is caused, but I do not know how to correct. I know it is a test environment problem though, not a code one. === Added File Zope3/lib/python/Zope/Server/FTP/PublisherFilesystemAccess.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Implementation of IFilesystemAccess intended only for testing. $Id: PublisherFilesystemAccess.py,v 1.1.2.1 2002/04/11 04:32:09 srichter Exp $ """ from cStringIO import StringIO from Zope.Exceptions import Unauthorized from Zope.App.Security.PrincipalRegistry import principalRegistry from Zope.Server.VFS.PublisherFileSystem import PublisherFileSystem from Zope.Server.VFS.IFilesystemAccess import IFilesystemAccess from Zope.Server.VFS.IUsernamePassword import IUsernamePassword class PublisherFilesystemAccess: __implements__ = IFilesystemAccess def __init__(self, request_factory): self.request_factory = request_factory def authenticate(self, credentials): assert IUsernamePassword.isImplementedBy(credentials) env = {'credentials' : credentials} request = self.request_factory(StringIO(''), StringIO(), env) id = principalRegistry.authenticate(request) if id is None: raise Unauthorized def open(self, credentials): return PublisherFileSystem(credentials, self.request_factory) === Zope3/lib/python/Zope/Server/FTP/FTPServer.py 1.1.2.11 => 1.1.2.12 === """ import asyncore -import pwd from FTPServerChannel import FTPServerChannel from Zope.Server.ServerBase import ServerBase from Zope.Server.VFS.IFilesystemAccess import IFilesystemAccess @@ -41,7 +40,7 @@ if __name__ == '__main__': from Zope.Server.TaskThreads import ThreadedTaskDispatcher from Zope.Server.VFS.OSFileSystem import OSFileSystem - from TestFilesystemAccess import TestFilesystemAccess + from Zope.Server.VFS.TestFilesystemAccess import TestFilesystemAccess td = ThreadedTaskDispatcher() td.setThreadCount(4) fs = OSFileSystem('/') === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.21 => 1.1.2.22 === from RecvChannel import RecvChannel from XmitChannel import XmitChannel, ApplicationXmitStream -from UsernamePassword import UsernamePassword +from Zope.Server.VFS.UsernamePassword import UsernamePassword from Zope.Exceptions import Unauthorized @@ -461,9 +461,7 @@ path = args else: path = os.path.join(self.cwd, args) - # Note: don't use os.path.normpath() here! Otherwise Zope won't - # work on case-insensitive platforms. - return path + return self._getFilesystem().normalize(path) def newPassiveAcceptor(self): === Zope3/lib/python/Zope/Server/FTP/PublisherFTPServer.py 1.1.2.6 => 1.1.2.7 === $Id$ """ -from PublisherFTPServerChannel import PublisherFTPServerChannel -from Zope.Server.ServerBase import ServerBase +from FTPServer import FTPServer -from Zope.Server.VFS.PublisherFileSystem import PublisherFileSystem +from Zope.Server.FTP.PublisherFilesystemAccess import PublisherFilesystemAccess - -class PublisherFileSystemOpener: - """ """ - - filesystem_factory = PublisherFileSystem - - - def __init__(self, root_dir, request_factory): - self.root_dir = root_dir - self.filesystem_factory.request_factory = request_factory - - - def __call__(self, username, password): - return PublisherFileSystem(self.root_dir, username, password) - - - -class PublisherFTPServer(ServerBase): +class PublisherFTPServer(FTPServer): """Generic FTP Server""" - channel_class = PublisherFTPServerChannel - SERVER_IDENT = 'Zope.Server.FTPServer' - - - def __init__(self, request_factory, name, ip, port, - task_dispatcher=None, adj=None, start=1, hit_log=None, - verbose=0): + def __init__(self, request_factory, name, ip, port, *args, **kw): self.request_factory = request_factory - self.openFilesystem = PublisherFileSystemOpener('/', request_factory) - - super(PublisherFTPServer, self).__init__(ip, port, task_dispatcher, - adj, start, hit_log, - verbose) + fs_access = PublisherFilesystemAccess(request_factory) + super(PublisherFTPServer, self).__init__(ip, port, fs_access, + *args, **kw) === Removed File Zope3/lib/python/Zope/Server/FTP/UsernamePassword.py === From srichter@cbu.edu Thu Apr 11 05:32:41 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 11 Apr 2002 00:32:41 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/POP3 - POP3MessageList.py:1.1.2.2 POP3Server.py:1.1.2.4 POP3ServerChannel.py:1.1.2.4 Message-ID: <200204110432.g3B4Wf903531@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/POP3 In directory cvs.zope.org:/tmp/cvs-serv25892/lib/python/Zope/Server/POP3 Modified Files: Tag: Zope3-Server-Branch POP3MessageList.py POP3Server.py POP3ServerChannel.py Log Message: Wee, quiet a bit of changes, but they fix and finnish the stuff Shane did earlier today. - Removed a lot of old files and moved some to more appropriate places. The removal of the Suthentication directory is probably the biggest one. I also deleted all the other FileSystem types, like MSDOS and Unix, since the FielSystem is not returning formatted lists anymore. Yipee! - Fixed PublisherFTPServer, so it works with Shane's new Credentials interfaces. Everything should be working fine again. - Fixed the POP3 and SMTP code to work with the new model. It all works really well. I hope that Gerson Kurz will take over this development soon. I also contacted authors of other server protocols, and they might join. Rich Salz is already writing a method for ZSI, so that we can insert SOAP in the next days. - Made most tests run again and updated them. I still have one error. I know why it is caused, but I do not know how to correct. I know it is a test environment problem though, not a code one. === Zope3/lib/python/Zope/Server/POP3/POP3MessageList.py 1.1.2.1 => 1.1.2.2 === import mailbox import os +from cStringIO import StringIO from IPOP3MessageList import IPOP3MessageList from POP3Message import POP3Message @@ -45,7 +46,8 @@ maildrop = self.maildrop else: self.maildrop = maildrop - md_file = self.maildir.open(maildrop, 'r') + md_file = StringIO() + self.maildir.readfile(maildrop, 'r', md_file) self._mb = mailbox.UnixMailbox(md_file) msg = self._mb.next() self._messagelist = [] @@ -60,11 +62,9 @@ for msg in self.getMessages(): mb_str += msg.getEntireMessage() self._mb.fp.close() - file = self.maildir.open(self.maildrop, 'w') - file.write(mb_str) - file.close() - + self.maildir.writefile(self.maildrop, 'w', StringIO(mb_str)) + def exists(self, index): 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' if index > 0 and index <= len(self._messagelist): === Zope3/lib/python/Zope/Server/POP3/POP3Server.py 1.1.2.3 => 1.1.2.4 === $Id$ """ +import asyncore from POP3ServerChannel import POP3ServerChannel from Zope.Server.ServerBase import ServerBase -from Zope.Server.VFS.UnixFileSystem import UnixFileSystem -from Zope.Server.Authentication.DictionaryAuthentication import \ - DictionaryAuthentication +from Zope.Server.VFS.OSFileSystem import OSFileSystem +from Zope.Server.VFS.IFilesystemAccess import IFilesystemAccess class POP3Server(ServerBase): @@ -30,29 +30,30 @@ SERVER_IDENT = 'Zope.Server.POP3Server' - def __init__(self, ip, port, maildir, auth, task_dispatcher=None, - adj=None, start=1, hit_log=None, verbose=0): - - self.auth_source = auth - self.maildir = UnixFileSystem(maildir) - - super(POP3Server, self).__init__(ip, port, task_dispatcher, - adj, start, hit_log, verbose) + def __init__(self, ip, port, maildir, *args, **kw): + + assert IFilesystemAccess.isImplementedBy(maildir) + self.maildir = maildir + + super(POP3Server, self).__init__(ip, port, *args, **kw) if __name__ == '__main__': - - import asyncore from Zope.Server.TaskThreads import ThreadedTaskDispatcher - + from Zope.Server.VFS.OSFileSystem import OSFileSystem + from Zope.Server.VFS.TestFilesystemAccess import TestFilesystemAccess td = ThreadedTaskDispatcher() td.setThreadCount(4) - auth_source = DictionaryAuthentication({'foo': 'bar'}) - POP3Server('', 110, '/var/mail', auth_source, task_dispatcher=td) + fs = OSFileSystem('/opt/ZopeMail') + maildir = TestFilesystemAccess(fs) + td = ThreadedTaskDispatcher() + td.setThreadCount(4) + POP3Server('', 110, maildir, task_dispatcher=td) try: while 1: asyncore.poll(5) - # print 'active channels:', POP3ServerChannel.active_channels + print 'active channels:', POP3ServerChannel.active_channels except KeyboardInterrupt: print 'shutting down...' td.shutdown() + === Zope3/lib/python/Zope/Server/POP3/POP3ServerChannel.py 1.1.2.3 => 1.1.2.4 === import time import md5 +from cStringIO import StringIO from Zope.Server.LineReceiver.LineServerChannel import LineServerChannel +from Zope.Server.VFS.UsernamePassword import UsernamePassword from POP3StatusMessages import status_msgs from POP3MessageList import POP3MessageList @@ -67,7 +69,7 @@ super(POP3ServerChannel, self).__init__(server, conn, addr, adj) self.username = '' - self.password = '' + self.credentials = None self.messagelist = None self.secret = "<%d.%d.%s@%s.%s>" %( os.getpid(), thread.get_ident(), @@ -77,6 +79,11 @@ self.reply('OK_GREETING', self.secret) + def _getFilesystem(self): + """Open the filesystem using the current credentials.""" + return self.server.maildir.open(self.credentials) + + ############################################################ # Implementation methods for interface # Zope.Server.POP3.IPOP3CommandHandler @@ -91,20 +98,20 @@ return self.reply('ERR_CMD_UNKNOWN') # Get the username and check whether the user exists - auth = self.server.auth_source self.username, hash = args.split() - if not auth.hasUser(self.username): + if not self.server.maildir.hasUser(self.username): return self.reply('ERR_LOGIN_MISMATCH') # See whether we got the right MD5 hash - self.password = auth.getPassword(self.username) - expected = md5.new(self.secret + self.password).hexdigest() + password = self.server.maildir.getPassword(self.username) + expected = md5.new(self.secret + password).hexdigest() if expected != hash: return self.reply('ERR_LOGIN_MISMATCH') - + + self.authenticated = 1 + self.credentials = UsernamePassword(self.username, password) self.openMessageList() self.reply('OK_LOGIN') - self.authenticated = 1 def cmd_capa(self, args): @@ -164,7 +171,7 @@ def cmd_pass(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' - self.password = args + password = args if self.authenticated: return self.reply('ERR_INV_STATE') @@ -173,15 +180,17 @@ if not self.username: return self.reply('ERR_NO_USER') - auth = self.server.auth_source - self.authenticated, message = auth.authenticate(self.username, - self.password) - if self.authenticated: - self.openMessageList() - self.reply('OK_LOGIN') - else: + credentials = UsernamePassword(self.username, password) + try: + self.server.maildir.authenticate(credentials) + except: self.reply('ERR_LOGIN_MISMATCH') self.close() + else: + self.credentials = credentials + self.authenticated = 1 + self.openMessageList() + self.reply('OK_LOGIN') def cmd_quit(self, args): @@ -281,7 +290,7 @@ if self.authenticated: return self.reply('ERR_INV_STATE') - if self.server.auth_source.hasUser(args): + if self.server.maildir.hasUser(args): self.username = args self.reply('OK_USER', args) else: @@ -292,7 +301,7 @@ def openMessageList(self): - self.messagelist = self.message_list_factory(self.server.maildir) + self.messagelist = self.message_list_factory(self._getFilesystem()) self.messagelist.open(self.username) From srichter@cbu.edu Thu Apr 11 05:32:42 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 11 Apr 2002 00:32:42 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/POP3/tests - testPOP3MessageList.py:1.1.2.2 testPOP3Server.py:1.1.2.2 Message-ID: <200204110432.g3B4WgG03535@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/POP3/tests In directory cvs.zope.org:/tmp/cvs-serv25892/lib/python/Zope/Server/POP3/tests Modified Files: Tag: Zope3-Server-Branch testPOP3MessageList.py testPOP3Server.py Log Message: Wee, quiet a bit of changes, but they fix and finnish the stuff Shane did earlier today. - Removed a lot of old files and moved some to more appropriate places. The removal of the Suthentication directory is probably the biggest one. I also deleted all the other FileSystem types, like MSDOS and Unix, since the FielSystem is not returning formatted lists anymore. Yipee! - Fixed PublisherFTPServer, so it works with Shane's new Credentials interfaces. Everything should be working fine again. - Fixed the POP3 and SMTP code to work with the new model. It all works really well. I hope that Gerson Kurz will take over this development soon. I also contacted authors of other server protocols, and they might join. Rich Salz is already writing a method for ZSI, so that we can insert SOAP in the next days. - Made most tests run again and updated them. I still have one error. I know why it is caused, but I do not know how to correct. I know it is a test environment problem though, not a code one. === Zope3/lib/python/Zope/Server/POP3/tests/testPOP3MessageList.py 1.1.2.1 => 1.1.2.2 === from Zope.Server.POP3.POP3MessageList import POP3MessageList -from Zope.Server.VFS.UnixFileSystem import UnixFileSystem +from Zope.Server.VFS.OSFileSystem import OSFileSystem import foo_mb @@ -35,7 +35,7 @@ def setUp(self): dir = tempfile.gettempdir() open(os.path.join(dir, 'foo'), 'w').write(foo_mb.mailbox) - self.msg_list = POP3MessageList(UnixFileSystem(dir), 'foo') + self.msg_list = POP3MessageList(OSFileSystem(dir), 'foo') self.msg_list.open() def testOpen(self): === Zope3/lib/python/Zope/Server/POP3/tests/testPOP3Server.py 1.1.2.1 => 1.1.2.2 === import tempfile import os +from cStringIO import StringIO from asyncore import socket_map, poll from threading import Thread @@ -26,12 +27,12 @@ from Zope.Server.POP3.POP3Server import POP3Server from Zope.Server.POP3.POP3ServerChannel import POP3ServerChannel from Zope.Server.POP3.POP3StatusMessages import status_msgs +from Zope.Server.VFS.TestFilesystemAccess import TestFilesystemAccess +from Zope.Server.VFS.UsernamePassword import UsernamePassword from Zope.Server.Adjustments import Adjustments from Zope.Server.ITask import ITask -from Zope.Server.VFS.UnixFileSystem import UnixFileSystem -from Zope.Server.Authentication.DictionaryAuthentication import \ - DictionaryAuthentication +from Zope.Server.VFS.OSFileSystem import OSFileSystem import poplib import foo_mb @@ -60,14 +61,16 @@ root_dir = tempfile.mktemp() os.mkdir(root_dir) - self.root_dir = UnixFileSystem(root_dir) - file = open(os.path.join(root_dir, 'foo'), 'w') file.write(foo_mb.mailbox) file.close() + fs = OSFileSystem('/opt/ZopeMail') + root_dir = TestFilesystemAccess(fs) + credentials = UsernamePassword('foo', 'bar') + self.root_dir = root_dir.open(credentials) + self.server = POP3Server(LOCALHOST, SERVER_PORT, root_dir, - DictionaryAuthentication({'foo': 'bar'}), task_dispatcher=td, adj=my_adj) if CONNECT_TO_PORT == 0: self.port = self.server.socket.getsockname()[1] @@ -87,15 +90,15 @@ self.server.close() # Make sure all sockets get closed by asyncore normally. # timeout = time() + 5 - # while 1: - # if len(socket_map) == self.orig_map_size: - # # Clean! - # break - # if time() >= timeout: - # print 'Leaked a socket: %s' % `socket_map` - # break - # #self.fail('Leaked a socket: %s' % `socket_map`) - # poll(0.1, socket_map) + while 1: + if len(socket_map) == self.orig_map_size: + # Clean! + break + if time() >= timeout: + print 'Leaked a socket: %s' % `socket_map` + break + #self.fail('Leaked a socket: %s' % `socket_map`) + poll(0.1, socket_map) def loop(self): @@ -108,9 +111,7 @@ def getPOP3Connection(self, login=1): # Refresh the file every single time, since some operations might # modify it. - file = self.root_dir.open('foo', 'w') - file.write(foo_mb.mailbox) - file.close() + self.root_dir.writefile('foo', 'w', StringIO(foo_mb.mailbox)) pop = poplib.POP3(LOCALHOST, self.port) if login: From srichter@cbu.edu Thu Apr 11 05:32:42 2002 From: srichter@cbu.edu (Stephan Richter) Date: Thu, 11 Apr 2002 00:32:42 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/SMTP - SMTPServer.py:1.1.2.4 SMTPServerChannel.py:1.1.2.5 Message-ID: <200204110432.g3B4Wgk03542@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/SMTP In directory cvs.zope.org:/tmp/cvs-serv25892/lib/python/Zope/Server/SMTP Modified Files: Tag: Zope3-Server-Branch SMTPServer.py SMTPServerChannel.py Log Message: Wee, quiet a bit of changes, but they fix and finnish the stuff Shane did earlier today. - Removed a lot of old files and moved some to more appropriate places. The removal of the Suthentication directory is probably the biggest one. I also deleted all the other FileSystem types, like MSDOS and Unix, since the FielSystem is not returning formatted lists anymore. Yipee! - Fixed PublisherFTPServer, so it works with Shane's new Credentials interfaces. Everything should be working fine again. - Fixed the POP3 and SMTP code to work with the new model. It all works really well. I hope that Gerson Kurz will take over this development soon. I also contacted authors of other server protocols, and they might join. Rich Salz is already writing a method for ZSI, so that we can insert SOAP in the next days. - Made most tests run again and updated them. I still have one error. I know why it is caused, but I do not know how to correct. I know it is a test environment problem though, not a code one. === Zope3/lib/python/Zope/Server/SMTP/SMTPServer.py 1.1.2.3 => 1.1.2.4 === from Zope.Server.ServerBase import ServerBase -from Zope.Server.VFS.UnixFileSystem import UnixFileSystem -from Zope.Server.Authentication.DictionaryAuthentication import \ - DictionaryAuthentication +from Zope.Server.VFS.OSFileSystem import OSFileSystem +from Zope.Server.VFS.IFilesystemAccess import IFilesystemAccess class SMTPServer(ServerBase): @@ -31,23 +30,27 @@ channel_class = SMTPServerChannel SERVER_IDENT = 'Zope.Server.SMTPServer' - storage = UnixFileSystem('/opt/ZopeMail') - auth_source = DictionaryAuthentication({'foo': 'bar'}) config = SMTPConfigurations - def __init__(self, ip, port, maildir, auth, *args, **kw): + def __init__(self, ip, port, maildir, *args, **kw): - self.auth_source = auth - self.maildir = UnixFileSystem(maildir) + assert IFilesystemAccess.isImplementedBy(maildir) + self.maildir = maildir super(SMTPServer, self).__init__(ip, port, *args, **kw) + if __name__ == '__main__': from Zope.Server.TaskThreads import ThreadedTaskDispatcher + from Zope.Server.VFS.OSFileSystem import OSFileSystem + from Zope.Server.VFS.TestFilesystemAccess import TestFilesystemAccess + td = ThreadedTaskDispatcher() + td.setThreadCount(4) + fs = OSFileSystem('/opt/ZopeMail') + maildir = TestFilesystemAccess(fs) td = ThreadedTaskDispatcher() td.setThreadCount(4) - auth_source = DictionaryAuthentication({'foo': 'bar'}) - SMTPServer('', 25, '/var/mail', auth_source, task_dispatcher=td) + SMTPServer('', 25, maildir, task_dispatcher=td) try: while 1: asyncore.poll(5) === Zope3/lib/python/Zope/Server/SMTP/SMTPServerChannel.py 1.1.2.4 => 1.1.2.5 === import fnmatch import socket +from cStringIO import StringIO from Zope.Server.LineReceiver.LineServerChannel import LineServerChannel +from Zope.Server.VFS.UsernamePassword import UsernamePassword from SMTPStatusMessages import status_msgs from ISMTPCommandHandler import ISMTPCommandHandler @@ -101,6 +103,12 @@ data = data[n:] + def _getFilesystem(self): + """Open the filesystem using the current credentials.""" + credentials = UsernamePassword('foo', 'bar') + return self.server.maildir.open(credentials) + + ############################################################ # Implementation methods for interface # Zope.Server.SMTP.ISMTPCommandHandler @@ -140,7 +148,6 @@ 'See Zope.Server.SMTP.ISMTPCommandHandler.ISMTPCommandHandler' self.reply('HELP') - def cmd_mail(self, args): 'See Zope.Server.SMTP.ISMTPCommandHandler.ISMTPCommandHandler' args = args.split(':') @@ -218,11 +225,10 @@ if receiver[0] == '<' or receiver[-1] == '>': receiver = receiver[1:-1] mailbox = receiver.split('@')[0] - file = self.server.maildir.open(mailbox, 'a') - file.write('From %s %s\n' %(self._from, - time.strftime(self.datetime_format))) - file.write(self._message+'\n\n') - file.close() + data = 'From %s %s\n' %(self._from, + time.strftime(self.datetime_format)) + data += self._message+'\n\n' + self._getFilesystem().writefile(mailbox, 'a', StringIO(data)) else: # XXX: send mail to next server pass @@ -345,8 +351,7 @@ except: username, domain = address, '' - - if self.server.auth_source.hasUser(username): + if self.server.maildir.hasUser(username): return username, 1 elif self.config.LOCAL_DOMAIN_NAME == domain.lower(): return 'unknown', 1 @@ -384,7 +389,7 @@ except: username, domain = address, '' - if ( self.server.auth_source.hasUser(username) and + if ( self.server.maildir.hasUser(username) and (domain.lower() == self.server.server_name or domain == '') ): return 1 From shane@cvs.zope.org Thu Apr 11 15:12:49 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 11 Apr 2002 10:12:49 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/SMTP/tests - __init__.py:1.1.2.2 Message-ID: <200204111412.g3BECng24746@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/SMTP/tests In directory cvs.zope.org:/tmp/cvs-serv24692/SMTP/tests Modified Files: Tag: Zope3-Server-Branch __init__.py Log Message: Removed CRs === Zope3/lib/python/Zope/Server/SMTP/tests/__init__.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" From shane@cvs.zope.org Thu Apr 11 15:12:49 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 11 Apr 2002 10:12:49 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - IPosixFileSystem.py:1.1.2.2 PublisherFileSystem.py:1.1.2.9 Message-ID: <200204111412.g3BECnh24752@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv24692/VFS Modified Files: Tag: Zope3-Server-Branch IPosixFileSystem.py PublisherFileSystem.py Log Message: Removed CRs === Zope3/lib/python/Zope/Server/VFS/IPosixFileSystem.py 1.1.2.1 => 1.1.2.2 === """Create a symbolic link at dst pointing to src. """ - + === Zope3/lib/python/Zope/Server/VFS/PublisherFileSystem.py 1.1.2.8 => 1.1.2.9 === env['credentials'] = self.credentials request = self.request_factory(StringIO(''), StringIO(), env) - # Note that publish() calls close() on request, which deletes the + # Note that publish() calls close() on request, which deletes the # response from the request, so that we need to keep track of it. response = request.getResponse() publish(request) - return response.getResult() - + return response.getResult() + ############################################################ # Implementation methods for interface @@ -68,7 +68,7 @@ path, file = os.path.split(path) env = {'name': file} return self._execute(path, 'exists', env) - + def isdir(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' @@ -162,7 +162,7 @@ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' path = self.translate(path) env = {'mode': mode} - return self._execute(path, 'check_writable', env) + return self._execute(path, 'check_writable', env) # ############################################################ From shane@cvs.zope.org Thu Apr 11 15:13:16 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 11 Apr 2002 10:13:16 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP/tests - testFTPServer.py:1.1.2.6 Message-ID: <200204111413.g3BEDGH24906@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP/tests In directory cvs.zope.org:/tmp/cvs-serv24692/FTP/tests Modified Files: Tag: Zope3-Server-Branch testFTPServer.py Log Message: Removed CRs === Zope3/lib/python/Zope/Server/FTP/tests/testFTPServer.py 1.1.2.5 => 1.1.2.6 === self.assertEqual(ftp.recv(1024), status_msgs['LOGIN_SUCCESS'] +'\r\n') - + return ftp @@ -171,7 +171,7 @@ def testHELP(self): result = status_msgs['HELP_START'] #+ '\r\n' #result += 'Help goes here somewhen.\r\n' - #result += status_msgs['HELP_END'] + #result += status_msgs['HELP_END'] self.assertEqual(self.execute('HELP', 1), result) From shane@cvs.zope.org Thu Apr 11 15:13:17 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 11 Apr 2002 10:13:17 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - CommonFTPActivityLogger.py:1.1.2.5 FTPServerChannel.py:1.1.2.23 OSEmulators.py:1.1.2.2 PublisherFTPServerChannel.py:1.1.2.3 PublisherFilesystemAccess.py:1.1.2.2 Message-ID: <200204111413.g3BEDHg24917@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv24692/FTP Modified Files: Tag: Zope3-Server-Branch CommonFTPActivityLogger.py FTPServerChannel.py OSEmulators.py PublisherFTPServerChannel.py PublisherFilesystemAccess.py Log Message: Removed CRs === Zope3/lib/python/Zope/Server/FTP/CommonFTPActivityLogger.py 1.1.2.4 => 1.1.2.5 === task.channel.cwd, ) - + self.output.log('127.0.0.1', message) === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.22 => 1.1.2.23 === """Open the filesystem using the current credentials.""" return self.server.fs_access.open(self.credentials) - + ############################################################ # Implementation methods for interface @@ -178,7 +178,7 @@ # We simply do not understand this non-standard extension to MDTM if len(args.split()) > 1: self.reply('ERR_ARGS') - return + return path = self._generatePath(args) if not self._getFilesystem().isfile(path): self.reply('ERR_IS_NOT_FILE', path) === Zope3/lib/python/Zope/Server/FTP/OSEmulators.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -import stat -import time -import pwd, grp - -months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] - -mode_table = { - '0':'---', - '1':'--x', - '2':'-w-', - '3':'-wx', - '4':'r--', - '5':'r-x', - '6':'rw-', - '7':'rwx' - } - - -def unix_longify((file, stat_info)): - # for now, only pay attention to the lower bits - - try: username = pwd.getpwuid(int(stat_info[stat.ST_UID]))[0] - except: username = stat_info[stat.ST_UID] - - try: grpname = grp.getgrgid(int(stat_info[stat.ST_GID]))[0] - except: grpname = stat_info[stat.ST_GID] - - - mode = ('%o' % stat_info[stat.ST_MODE])[-3:] - mode = ''.join(map (lambda x: mode_table[x], mode)) - if stat.S_ISDIR (stat_info[stat.ST_MODE]): - dirchar = 'd' - else: - dirchar = '-' - date = ls_date (long(time.time()), stat_info[stat.ST_MTIME]) - return '%s%s %3d %-8s %-8s %8d %s %s' % ( - dirchar, - mode, - stat_info[stat.ST_NLINK], - username, - grpname, - stat_info[stat.ST_SIZE], - date, - file - ) - - -def ls_date (now, t): - """Emulate the unix 'ls' command's date field. it has two formats - - if the date is more than 180 days in the past, then it's like - this: Oct 19 1995 otherwise, it looks like this: Oct 19 17:33 - """ - try: - info = time.gmtime(t) - except: - info = time.gmtime(0) - - # 15,600,000 == 86,400 * 180 - if (now - t) > 15600000: - return '%s %2d %d' % ( - months[info[1]-1], - info[2], - info[0] - ) - else: - return '%s %2d %02d:%02d' % ( - months[info[1]-1], - info[2], - info[3], - info[4] - ) - - -def msdos_longify((file, stat_info)): - """This matches the output of NT's ftp server (when in MSDOS mode) - exactly. - """ - if stat.S_ISDIR(stat_info[stat.ST_MODE]): - dir = '' - else: - dir = ' ' - date = msdos_date(stat_info[stat.ST_MTIME]) - return '%s %s %8d %s' % (date, dir, stat_info[stat.ST_SIZE], file) - - -def msdos_date(t): - try: - info = time.gmtime(t) - except: - info = time.gmtime(0) - - # year, month, day, hour, minute, second, ... - if info[3] > 11: - merid = 'PM' - info[3] = info[3] - 12 - else: - merid = 'AM' - - return '%02d-%02d-%02d %02d:%02d%s' % ( - info[1], info[2], info[0]%100, info[3], info[4], merid ) +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +import stat +import time +import pwd, grp + +months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + +mode_table = { + '0':'---', + '1':'--x', + '2':'-w-', + '3':'-wx', + '4':'r--', + '5':'r-x', + '6':'rw-', + '7':'rwx' + } + + +def unix_longify((file, stat_info)): + # for now, only pay attention to the lower bits + + try: username = pwd.getpwuid(int(stat_info[stat.ST_UID]))[0] + except: username = stat_info[stat.ST_UID] + + try: grpname = grp.getgrgid(int(stat_info[stat.ST_GID]))[0] + except: grpname = stat_info[stat.ST_GID] + + + mode = ('%o' % stat_info[stat.ST_MODE])[-3:] + mode = ''.join(map (lambda x: mode_table[x], mode)) + if stat.S_ISDIR (stat_info[stat.ST_MODE]): + dirchar = 'd' + else: + dirchar = '-' + date = ls_date (long(time.time()), stat_info[stat.ST_MTIME]) + return '%s%s %3d %-8s %-8s %8d %s %s' % ( + dirchar, + mode, + stat_info[stat.ST_NLINK], + username, + grpname, + stat_info[stat.ST_SIZE], + date, + file + ) + + +def ls_date (now, t): + """Emulate the unix 'ls' command's date field. it has two formats + - if the date is more than 180 days in the past, then it's like + this: Oct 19 1995 otherwise, it looks like this: Oct 19 17:33 + """ + try: + info = time.gmtime(t) + except: + info = time.gmtime(0) + + # 15,600,000 == 86,400 * 180 + if (now - t) > 15600000: + return '%s %2d %d' % ( + months[info[1]-1], + info[2], + info[0] + ) + else: + return '%s %2d %02d:%02d' % ( + months[info[1]-1], + info[2], + info[3], + info[4] + ) + + +def msdos_longify((file, stat_info)): + """This matches the output of NT's ftp server (when in MSDOS mode) + exactly. + """ + if stat.S_ISDIR(stat_info[stat.ST_MODE]): + dir = '' + else: + dir = ' ' + date = msdos_date(stat_info[stat.ST_MTIME]) + return '%s %s %8d %s' % (date, dir, stat_info[stat.ST_SIZE], file) + + +def msdos_date(t): + try: + info = time.gmtime(t) + except: + info = time.gmtime(0) + + # year, month, day, hour, minute, second, ... + if info[3] > 11: + merid = 'PM' + info[3] = info[3] - 12 + else: + merid = 'AM' + + return '%02d-%02d-%02d %02d:%02d%s' % ( + info[1], info[2], info[0]%100, info[3], info[4], merid ) === Zope3/lib/python/Zope/Server/FTP/PublisherFTPServerChannel.py 1.1.2.2 => 1.1.2.3 === else: return 0, 'User could not be authenticated.' - - + + === Zope3/lib/python/Zope/Server/FTP/PublisherFilesystemAccess.py 1.1.2.1 => 1.1.2.2 === def open(self, credentials): - return PublisherFileSystem(credentials, self.request_factory) + return PublisherFileSystem(credentials, self.request_factory) From shane@cvs.zope.org Thu Apr 11 15:13:18 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 11 Apr 2002 10:13:18 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/POP3/tests - foo_mb.py:1.1.2.2 testPOP3Message.py:1.1.2.2 testPOP3MessageList.py:1.1.2.3 testPOP3Server.py:1.1.2.3 Message-ID: <200204111413.g3BEDIG24928@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/POP3/tests In directory cvs.zope.org:/tmp/cvs-serv24692/POP3/tests Modified Files: Tag: Zope3-Server-Branch foo_mb.py testPOP3Message.py testPOP3MessageList.py testPOP3Server.py Log Message: Removed CRs === Zope3/lib/python/Zope/Server/POP3/tests/foo_mb.py 1.1.2.1 => 1.1.2.2 === From srichter@iuveno-net.de Sun Apr 7 11:14:50 2002 Received: from Stephan.iuveno-net.de (bohr.cbu.edu [192.168.160.8]) - by cbu.edu (8.11.6+Sun/8.11.6) with ESMTP id g37GEnM20286 - for ; Sun, 7 Apr 2002 11:14:50 -0500 (CDT) + by cbu.edu (8.11.6+Sun/8.11.6) with ESMTP id g37GEnM20286 + for ; Sun, 7 Apr 2002 11:14:50 -0500 (CDT) Message-Id: <5.1.0.14.2.20020407111422.00bc5fd0@imail.iuveno-net.de> X-Sender: srichter@imail.iuveno-net.de X-Mailer: QUALCOMM Windows Eudora Version 5.1 @@ -40,8 +40,8 @@ From srichter@iuveno-net.de Sun Apr 7 11:15:29 2002 Received: from Stephan.iuveno-net.de (bohr.cbu.edu [192.168.160.8]) - by cbu.edu (8.11.6+Sun/8.11.6) with ESMTP id g37GFSM20303; - Sun, 7 Apr 2002 11:15:28 -0500 (CDT) + by cbu.edu (8.11.6+Sun/8.11.6) with ESMTP id g37GFSM20303; + Sun, 7 Apr 2002 11:15:28 -0500 (CDT) Message-Id: <5.1.0.14.2.20020407111444.00bc5b20@imail.iuveno-net.de> X-Sender: srichter@imail.iuveno-net.de X-Mailer: QUALCOMM Windows Eudora Version 5.1 @@ -62,8 +62,8 @@ From srichter@iuveno-net.de Sun Apr 7 11:16:00 2002 Received: from Stephan.iuveno-net.de (bohr.cbu.edu [192.168.160.8]) - by cbu.edu (8.11.6+Sun/8.11.6) with ESMTP id g37GFxM20326; - Sun, 7 Apr 2002 11:16:00 -0500 (CDT) + by cbu.edu (8.11.6+Sun/8.11.6) with ESMTP id g37GFxM20326; + Sun, 7 Apr 2002 11:16:00 -0500 (CDT) Message-Id: <5.1.0.14.2.20020407111522.02331ac0@imail.iuveno-net.de> X-Sender: srichter@imail.iuveno-net.de X-Mailer: QUALCOMM Windows Eudora Version 5.1 === Zope3/lib/python/Zope/Server/POP3/tests/testPOP3Message.py 1.1.2.1 => 1.1.2.2 === import tempfile -from Interface.Verify import verifyClass +from Interface.Verify import verifyClass from Zope.Server.POP3.IPOP3Message import IPOP3Message from Zope.Server.POP3.POP3Message import POP3Message @@ -34,9 +34,9 @@ def setUp(self): fn = tempfile.mktemp() open(fn, 'w').write(foo_mb.mailbox[1:663]) - msg = rfc822.Message(open(fn, 'r')) + msg = rfc822.Message(open(fn, 'r')) self.msg = POP3Message(msg) - + def testIsDeleted(self): self.assertEqual(self.msg.isDeleted(), 0) === Zope3/lib/python/Zope/Server/POP3/tests/testPOP3MessageList.py 1.1.2.2 => 1.1.2.3 === import os -from Interface.Verify import verifyClass +from Interface.Verify import verifyClass from Zope.Server.POP3.IPOP3MessageList import IPOP3MessageList from Zope.Server.POP3.POP3MessageList import POP3MessageList @@ -37,7 +37,7 @@ open(os.path.join(dir, 'foo'), 'w').write(foo_mb.mailbox) self.msg_list = POP3MessageList(OSFileSystem(dir), 'foo') self.msg_list.open() - + def testOpen(self): self._messagelist = [] self.msg_list.open() @@ -55,11 +55,11 @@ self.assertEqual(self.msg_list.getMessage(1), msg) def testGetTotal(self): - self.assertEqual(self.msg_list.getTotalSize(), 2062) + self.assertEqual(self.msg_list.getTotalSize(), 2062) def testGetIndex(self): msg = self.msg_list._messagelist[0] - self.assertEqual(self.msg_list.getIndex(msg), 1) + self.assertEqual(self.msg_list.getIndex(msg), 1) def testInterface(self): self.failUnless(IPOP3MessageList.isImplementedByInstancesOf( === Zope3/lib/python/Zope/Server/POP3/tests/testPOP3Server.py 1.1.2.2 => 1.1.2.3 === self.assertEqual(pop.pass_('bar'), status_msgs['OK_LOGIN']) - + return pop @@ -128,7 +128,7 @@ self.assertEqual(pop.apop('foo', 'bar'), status_msgs['OK_LOGIN']) pop.quit() - + def testDELE(self): pop = self.getPOP3Connection(1) @@ -198,8 +198,8 @@ self.assertEqual(str(error), status_msgs['ERR_MSG_UNKNOWN']) pop.quit() - - + + def testRSET(self): pop = self.getPOP3Connection(1) pop.dele(1) @@ -207,15 +207,15 @@ pop.rset() self.assertEqual(len(pop.list()[1]), 3) pop.quit() - - + + def testSTAT(self): pop = self.getPOP3Connection(1) self.assertEqual(pop.stat(), (2062, 3)) pop.quit() - - + + def testTOP(self): pop = self.getPOP3Connection(1) self.assertEqual(pop.top(1, 2), @@ -227,8 +227,8 @@ self.assertEqual(str(error), status_msgs['ERR_MSG_UNKNOWN']) pop.quit() - - + + def testUIDL(self): pop = self.getPOP3Connection(1) self.assertEqual(pop.uidl(), From shane@cvs.zope.org Thu Apr 11 15:13:18 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 11 Apr 2002 10:13:18 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/POP3 - IPOP3CommandHandler.py:1.1.2.3 IPOP3Message.py:1.1.2.2 IPOP3MessageList.py:1.1.2.2 POP3Message.py:1.1.2.2 POP3MessageList.py:1.1.2.3 POP3Server.py:1.1.2.5 POP3ServerChannel.py:1.1.2.5 POP3StatusMessages.py:1.1.2.3 Message-ID: <200204111413.g3BEDIF24925@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/POP3 In directory cvs.zope.org:/tmp/cvs-serv24692/POP3 Modified Files: Tag: Zope3-Server-Branch IPOP3CommandHandler.py IPOP3Message.py IPOP3MessageList.py POP3Message.py POP3MessageList.py POP3Server.py POP3ServerChannel.py POP3StatusMessages.py Log Message: Removed CRs === Zope3/lib/python/Zope/Server/POP3/IPOP3CommandHandler.py 1.1.2.2 => 1.1.2.3 === (929/1029 lines abridged) -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -from Interface import Interface - -class IPOP3CommandHandler(Interface): - """This interface lists the implemented POP3 commands following - RFC 1939. Some advanced commands specified in RFC 2449 are also - listed. - """ - - def cmd_apop(args): - """APOP name digest - - Arguments: - a string identifying a mailbox and a MD5 digest string - (both required) - - Restrictions: - may only be given in the AUTHORIZATION state after the POP3 - greeting - - Discussion: - Normally, each POP3 session starts with a USER/PASS - exchange. This results in a server/user-id specific - password being sent in the clear on the network. For - intermittent use of POP3, this may not introduce a sizable - risk. However, many POP3 client implementations connect to - the POP3 server on a regular basis -- to check for new - mail. Further the interval of session initiation may be on - the order of five minutes. Hence, the risk of password - capture is greatly enhanced. - - An alternate method of authentication is required which - provides for both origin authentication and replay - protection, but which does not involve sending a password [-=- -=- -=- 929 lines omitted -=- -=- -=-] + The unique-id of a message is an arbitrary server-determined + string, consisting of characters in the range 0x21 to 0x7E, + which uniquely identifies a message within a maildrop and + which persists across sessions. The server should never reuse + an unique-id in a given maildrop, for as long as the entity + using the unique-id exists. + + Note that messages marked as deleted are not listed. + + Possible Responses: + +OK unique-id listing follows + -ERR no such message + + Examples: + C: UIDL + S: +OK + S: 1 whqtswO00WBw418f9t5JxYwZ + S: 2 QhdPYR:00WBw1Ph7x7 + S: . + ... + C: UIDL 2 + S: +OK 2 QhdPYR:00WBw1Ph7x7 + ... + C: UIDL 3 + S: -ERR no such message, only 2 messages in maildrop + """ + + def cmd_user(args): + """USER name + + Arguments: + a string identifying a mailbox (required), which is of + significance ONLY to the server + + Restrictions: + may only be given in the AUTHORIZATION state after the POP3 + greeting or after an unsuccessful USER or PASS command + + Possible Responses: + +OK name is a valid mailbox + -ERR never heard of mailbox name + + Examples: + C: USER mrose + S: +OK mrose is a real hoopy frood + ... + C: USER frated + S: -ERR sorry, no mailbox for frated here + """ + === Zope3/lib/python/Zope/Server/POP3/IPOP3Message.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -from Interface import Interface - -class IPOP3Message(Interface): - """THis interface describes the methods that are expected of a - message by the POP3 server. - """ - - def isDeleted(): - """Return the 'deleted' status of the message. - """ - - def setDeleted(deleted=1): - """Set the message as delted or not-deleted. - """ - - def getEntireMessage(): - """Return the entire message, including headers. - """ - - def getBody(): - """Return only the body of the message. - """ - - def getSize(): - """Return the size of the message in octets. - """ - - def getUID(): - """Get a unique id, following th eguidelines given in the POP3 RFC - in the UIDL section. - """ - - +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +from Interface import Interface + +class IPOP3Message(Interface): + """THis interface describes the methods that are expected of a + message by the POP3 server. + """ + + def isDeleted(): + """Return the 'deleted' status of the message. + """ + + def setDeleted(deleted=1): + """Set the message as delted or not-deleted. + """ + + def getEntireMessage(): + """Return the entire message, including headers. + """ + + def getBody(): + """Return only the body of the message. + """ + + def getSize(): + """Return the size of the message in octets. + """ + + def getUID(): + """Get a unique id, following th eguidelines given in the POP3 RFC + in the UIDL section. + """ + + === Zope3/lib/python/Zope/Server/POP3/IPOP3MessageList.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -from Interface import Interface - -class IPOP3MessageList(Interface): - """ - """ - - def open(): - """Open the mailbox and create the message list. - """ - - def close(): - """Close the mailbox. - - Here the messages that are marked as 'deleted' should be - removed before saving the list. - """ - - def exists(index): - """Check whether this index exists in this Message List. - """ - - def getMessages(): - """Return a list of non-deleted messages. - """ - - def getMessage(index): - """Return the message of the given index. - """ - - def getTotalSize(): - """Get the total size of all non-deleted messages. - """ - - def getIndex(message): - """Get the index of a particular method.""" - - - def __getitem__(index): - """Get the message wuth the specified 'index'. - """ - - - - +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +from Interface import Interface + +class IPOP3MessageList(Interface): + """ + """ + + def open(): + """Open the mailbox and create the message list. + """ + + def close(): + """Close the mailbox. + + Here the messages that are marked as 'deleted' should be + removed before saving the list. + """ + + def exists(index): + """Check whether this index exists in this Message List. + """ + + def getMessages(): + """Return a list of non-deleted messages. + """ + + def getMessage(index): + """Return the message of the given index. + """ + + def getTotalSize(): + """Get the total size of all non-deleted messages. + """ + + def getIndex(message): + """Get the index of a particular method.""" + + + def __getitem__(index): + """Get the message wuth the specified 'index'. + """ + + + + === Zope3/lib/python/Zope/Server/POP3/POP3Message.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -from Zope.Server.POP3.IPOP3Message import IPOP3Message -import md5 - -class POP3Message: - - __implements__ = IPOP3Message - - - def __init__(self, rfc822_msg): - """ """ - self.rfc822_msg = rfc822_msg - self._deleted = 0 - - ############################################################ - # Implementation methods for interface - # Zope.Server.POP3.IPOP3Message. - - def isDeleted(self): - 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' - return self._deleted - - def setDeleted(self, deleted=1): - 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' - self._deleted = deleted - - def getEntireMessage(self): - 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' - self.rfc822_msg.fp.seek(0) - return self.rfc822_msg.fp.read() - - def getBody(self): - 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' - return self.rfc822_msg.fp.read() - - def getSize(self): - 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' - return len(self.getEntireMessage()) - - def getUID(self): - 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' - hash = md5.md5(self.getBody()) - return hash.hexdigest() - - # - ############################################################ +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +from Zope.Server.POP3.IPOP3Message import IPOP3Message +import md5 + +class POP3Message: + + __implements__ = IPOP3Message + + + def __init__(self, rfc822_msg): + """ """ + self.rfc822_msg = rfc822_msg + self._deleted = 0 + + ############################################################ + # Implementation methods for interface + # Zope.Server.POP3.IPOP3Message. + + def isDeleted(self): + 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' + return self._deleted + + def setDeleted(self, deleted=1): + 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' + self._deleted = deleted + + def getEntireMessage(self): + 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' + self.rfc822_msg.fp.seek(0) + return self.rfc822_msg.fp.read() + + def getBody(self): + 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' + return self.rfc822_msg.fp.read() + + def getSize(self): + 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' + return len(self.getEntireMessage()) + + def getUID(self): + 'See Zope.Server.POP3.IPOP3Message.IPOP3Message' + hash = md5.md5(self.getBody()) + return hash.hexdigest() + + # + ############################################################ === Zope3/lib/python/Zope/Server/POP3/POP3MessageList.py 1.1.2.2 => 1.1.2.3 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" -import mailbox -import os -from cStringIO import StringIO - -from IPOP3MessageList import IPOP3MessageList -from POP3Message import POP3Message - -class POP3MessageList: - - __implements__ = IPOP3MessageList - - - - def __init__(self, maildir, maildrop=None): - """ """ - self.maildir = maildir - self.maildrop = maildrop - - self._messagelist = [] - self._mb = None - - ############################################################ - # Implementation methods for interface - # Zope.Server.POP3.IPOP3MessageList. - - def open(self, maildrop=None): - 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' - if maildrop is None: - maildrop = self.maildrop - else: - self.maildrop = maildrop - md_file = StringIO() - self.maildir.readfile(maildrop, 'r', md_file) - self._mb = mailbox.UnixMailbox(md_file) - msg = self._mb.next() - self._messagelist = [] - while msg is not None: - self._messagelist.append(POP3Message(msg)) - msg = self._mb.next() - - - def close(self): - 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' - mb_str = '' - for msg in self.getMessages(): - mb_str += msg.getEntireMessage() - self._mb.fp.close() - self.maildir.writefile(self.maildrop, 'w', StringIO(mb_str)) - - - def exists(self, index): - 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' - if index > 0 and index <= len(self._messagelist): - return 1 - return 0 - - - def getMessages(self): - 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' - return filter(lambda msg: not msg.isDeleted(), self._messagelist) - - - def getMessage(self, index): - 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' - return self._messagelist[index-1] - - - def getTotalSize(self): - 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' - sizes = map(lambda msg: msg.getSize(), self.getMessages()) - if sizes: - return reduce(lambda x, y: x+y, sizes) - else: - return 0 - - - def getIndex(self, message): - 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' - return self._messagelist.index(message) + 1 - - - def __getitem__(self, index): - 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' - return self.getMessage(index) - - # - ############################################################ +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" +import mailbox +import os +from cStringIO import StringIO + +from IPOP3MessageList import IPOP3MessageList +from POP3Message import POP3Message + +class POP3MessageList: + + __implements__ = IPOP3MessageList + + + + def __init__(self, maildir, maildrop=None): + """ """ + self.maildir = maildir + self.maildrop = maildrop + + self._messagelist = [] + self._mb = None + + ############################################################ + # Implementation methods for interface + # Zope.Server.POP3.IPOP3MessageList. + + def open(self, maildrop=None): + 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' + if maildrop is None: + maildrop = self.maildrop + else: + self.maildrop = maildrop + md_file = StringIO() + self.maildir.readfile(maildrop, 'r', md_file) + self._mb = mailbox.UnixMailbox(md_file) + msg = self._mb.next() + self._messagelist = [] + while msg is not None: + self._messagelist.append(POP3Message(msg)) + msg = self._mb.next() + + + def close(self): + 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' + mb_str = '' + for msg in self.getMessages(): + mb_str += msg.getEntireMessage() + self._mb.fp.close() + self.maildir.writefile(self.maildrop, 'w', StringIO(mb_str)) + + + def exists(self, index): + 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' + if index > 0 and index <= len(self._messagelist): + return 1 + return 0 + + + def getMessages(self): + 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' + return filter(lambda msg: not msg.isDeleted(), self._messagelist) + + + def getMessage(self, index): + 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' + return self._messagelist[index-1] + + + def getTotalSize(self): + 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' + sizes = map(lambda msg: msg.getSize(), self.getMessages()) + if sizes: + return reduce(lambda x, y: x+y, sizes) + else: + return 0 + + + def getIndex(self, message): + 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' + return self._messagelist.index(message) + 1 + + + def __getitem__(self, index): + 'See Zope.Server.POP3.IPOP3MessageList.IPOP3MessageList' + return self.getMessage(index) + + # + ############################################################ === Zope3/lib/python/Zope/Server/POP3/POP3Server.py 1.1.2.4 => 1.1.2.5 === from Zope.Server.ServerBase import ServerBase -from Zope.Server.VFS.OSFileSystem import OSFileSystem +from Zope.Server.VFS.OSFileSystem import OSFileSystem from Zope.Server.VFS.IFilesystemAccess import IFilesystemAccess @@ -31,10 +31,10 @@ def __init__(self, ip, port, maildir, *args, **kw): - + assert IFilesystemAccess.isImplementedBy(maildir) self.maildir = maildir - + super(POP3Server, self).__init__(ip, port, *args, **kw) === Zope3/lib/python/Zope/Server/POP3/POP3ServerChannel.py 1.1.2.4 => 1.1.2.5 === str(id(self)) ) self.reply('OK_GREETING', self.secret) - + def _getFilesystem(self): """Open the filesystem using the current credentials.""" @@ -134,8 +134,8 @@ self.messagelist[msg_index].setDeleted() return self.reply('OK_DELETE') - return self.reply('ERR_MSG_UNKNOWN') - + return self.reply('ERR_MSG_UNKNOWN') + def cmd_list(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' @@ -168,7 +168,7 @@ 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' self.reply('OK_GENERAL') - + def cmd_pass(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' password = args @@ -199,7 +199,7 @@ self.closeMessageList() self.close() - + def cmd_retr(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' try: @@ -214,13 +214,13 @@ self.write(msg.getEntireMessage()) self.write('\r\n.\r\n') else: - return self.reply('ERR_MSG_UNKNOWN') + return self.reply('ERR_MSG_UNKNOWN') def cmd_rset(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' for msg in self.messagelist: - # mark all messages as not-deleted + # mark all messages as not-deleted msg.setDeleted(0) self.reply('OK_RSET') @@ -254,9 +254,9 @@ self.write("\r\n".join(lines)) self.write('\r\n.\r\n') self.flush() - else: - return self.reply('ERR_MSG_UNKNOWN') - + else: + return self.reply('ERR_MSG_UNKNOWN') + def cmd_uidl(self, args): 'See Zope.Server.POP3.IPOP3CommandHandler.IPOP3CommandHandler' @@ -303,7 +303,7 @@ def openMessageList(self): self.messagelist = self.message_list_factory(self._getFilesystem()) self.messagelist.open(self.username) - + def closeMessageList(self): if self.messagelist is not None: === Zope3/lib/python/Zope/Server/POP3/POP3StatusMessages.py 1.1.2.2 => 1.1.2.3 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - - -status_msgs = { - 'OK_GENERAL' : '+OK', - 'OK_GREETING' : '+OK Zope 3 POP3 server ready %s', - 'OK_LOGIN' : '+OK login successful', - 'OK_USER' : '+OK %s is a valid mailbox', - 'OK_QUIT' : '+OK Connection is closing.', - 'OK_SINGLE_LIST' : '+OK %i %i', - 'OK_MSG_LIST' : '+OK %i message (%i octets)', - 'OK_DELETE' : '+OK The message was successfully deleted', - 'OK_RETR' : '+OK message follows (%i octets)', - 'OK_RSET' : '+OK Resetting all messages done', - 'OK_STAT' : '+OK %i %i', - 'OK_TOP' : '+OK top %i lines of message follows', - 'OK_APOP' : '+OK maildrop locked and ready', - 'OK_SINGLE_UIDL' : '+OK %i %s', - 'OK_MSG_UIDL' : '+OK Unique message id list follows', - 'OK_CAPA' : '+OK Capability list follows', - - 'ERR_CMD_UNKNOWN' : '-ERR unknown command', - 'ERR_MSG_UNKNOWN' : '-ERR unknown or invalid message id', - 'ERR_INV_STATE' : '-ERR Invalid State', - 'ERR_NO_USER' : '-ERR No user was yet specified', - 'ERR_NOT_USER' : '-ERR never heard of mailbox name', - 'ERR_LOGIN_MISMATCH' : '-ERR username and password did not match', - - 'CMD_UNKNOWN' : '-ERR %s command unknown', - 'LOGIN_REQUIRED' : '-ERR Not yet logged in.', - } - +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + + +status_msgs = { + 'OK_GENERAL' : '+OK', + 'OK_GREETING' : '+OK Zope 3 POP3 server ready %s', + 'OK_LOGIN' : '+OK login successful', + 'OK_USER' : '+OK %s is a valid mailbox', + 'OK_QUIT' : '+OK Connection is closing.', + 'OK_SINGLE_LIST' : '+OK %i %i', + 'OK_MSG_LIST' : '+OK %i message (%i octets)', + 'OK_DELETE' : '+OK The message was successfully deleted', + 'OK_RETR' : '+OK message follows (%i octets)', + 'OK_RSET' : '+OK Resetting all messages done', + 'OK_STAT' : '+OK %i %i', + 'OK_TOP' : '+OK top %i lines of message follows', + 'OK_APOP' : '+OK maildrop locked and ready', + 'OK_SINGLE_UIDL' : '+OK %i %s', + 'OK_MSG_UIDL' : '+OK Unique message id list follows', + 'OK_CAPA' : '+OK Capability list follows', + + 'ERR_CMD_UNKNOWN' : '-ERR unknown command', + 'ERR_MSG_UNKNOWN' : '-ERR unknown or invalid message id', + 'ERR_INV_STATE' : '-ERR Invalid State', + 'ERR_NO_USER' : '-ERR No user was yet specified', + 'ERR_NOT_USER' : '-ERR never heard of mailbox name', + 'ERR_LOGIN_MISMATCH' : '-ERR username and password did not match', + + 'CMD_UNKNOWN' : '-ERR %s command unknown', + 'LOGIN_REQUIRED' : '-ERR Not yet logged in.', + } + From shane@cvs.zope.org Thu Apr 11 15:13:18 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 11 Apr 2002 10:13:18 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/SMTP - ISMTPCommandHandler.py:1.1.2.2 SMTPConfigurations.py:1.1.2.2 SMTPServer.py:1.1.2.5 SMTPServerChannel.py:1.1.2.6 SMTPSpamFilter.py:1.1.2.2 SMTPStatusMessages.py:1.1.2.3 SMTPUtilities.py:1.1.2.2 __init__.py:1.1.2.2 Message-ID: <200204111413.g3BEDI224946@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/SMTP In directory cvs.zope.org:/tmp/cvs-serv24692/SMTP Modified Files: Tag: Zope3-Server-Branch ISMTPCommandHandler.py SMTPConfigurations.py SMTPServer.py SMTPServerChannel.py SMTPSpamFilter.py SMTPStatusMessages.py SMTPUtilities.py __init__.py Log Message: Removed CRs === Zope3/lib/python/Zope/Server/SMTP/ISMTPCommandHandler.py 1.1.2.1 => 1.1.2.2 === (421/521 lines abridged) -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -from Interface import Interface - -class ISMTPCommandHandler(Interface): - """This interface defines all the SMTP commands that are supported by the - server. - - Every command takes the args as first arguments, since it is - responsible for parsing the rest of the input (which is usually - easy). - """ - - def cmd_data(args): - """DATA (DATA) - - The receiver treats the lines following the command as mail - data from the sender. This command causes the mail data - from this command to be appended to the mail data buffer. - The mail data may contain any of the 128 ASCII character - codes. - - The mail data is terminated by a line containing only a - period, that is the character sequence "." (see - Section 4.5.2 on Transparency). This is the end of mail - data indication. - - The end of mail data indication requires that the receiver - must now process the stored mail transaction information. - This processing consumes the information in the reverse-path - buffer, the forward-path buffer, and the mail data buffer, - and on the completion of this command these buffers are - cleared. If the processing is successful the receiver must - send an OK reply. If the processing fails completely the - receiver must send a failure reply. [-=- -=- -=- 421 lines omitted -=- -=- -=-] + + The forward-path consists of an optional list of hosts and a + required destination mailbox. When the list of hosts is + present, it is a source route and indicates that the mail + must be relayed to the next host on the list. If the + receiver-SMTP does not implement the relay function it may + user the same reply it would for an unknown local user + (550). + + When mail is relayed, the relay host must remove itself from + the beginning forward-path and put itself at the beginning + of the reverse-path. When mail reaches its ultimate + destination (the forward-path contains only a destination + mailbox), the receiver-SMTP inserts it into the destination + mailbox in accordance with its host mail conventions. + + For example, mail received at relay host A with arguments + + FROM: + TO:<@HOSTA.ARPA,@HOSTB.ARPA:USERC@HOSTD.ARPA> + + will be relayed on to host B with arguments + + FROM:<@HOSTA.ARPA:USERX@HOSTY.ARPA> + TO:<@HOSTB.ARPA:USERC@HOSTD.ARPA>. + + This command causes its forward-path argument to be appended + to the forward-path buffer. + """ + + def cmd_rset(args): + """RESET (RSET) + + This command specifies that the current mail transaction is + to be aborted. Any stored sender, recipients, and mail data + must be discarded, and all buffers and state tables cleared. + The receiver must send an OK reply. + """ + + def cmd_vrfy(args): + """VERIFY (VRFY) + + This command asks the receiver to confirm that the argument + identifies a user. If it is a user name, the full name of + the user (if known) and the fully specified mailbox are + returned. + + This command has no effect on any of the reverse-path + buffer, the forward-path buffer, or the mail data buffer. + """ === Zope3/lib/python/Zope/Server/SMTP/SMTPConfigurations.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -# ** Relay rules ** - -# Specify relay level. -# true: Allow relaying except from domains specified in DENY_RELAY_FROM -# and to domains in DENY_RELAY_TO -# false: Deny relaying except from domains specified in ALLOW_RELAY_FROM -# and to domains in ALLOW_RELAY_TO -RELAY_FROM = 1 -ACCEPT_RELAY_FROM = ('*cbu.edu', '*zope.org') -DENY_RELAY_FROM = () - -RELAY_TO = 1 -ACCEPT_RELAY_TO = ('*.cbu.edu') -DENY_RELAY_TO = () - -# If specified all mail is forwarded to this server. -USE_RELAY_SERVER = '' - -# When set to true, a local sender is only allowed to send, if the connection -# is coming from a local IP. -STRICT_RELAY_TEST = 0 - -# Define some standard mail accounts -ADMIN_ACCOUNT = 'foo' -UNKNOWN_ACCOUNT = 'unknown' - -LOCAL_DOMAIN_NAME = '*cbu.edu' +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +# ** Relay rules ** + +# Specify relay level. +# true: Allow relaying except from domains specified in DENY_RELAY_FROM +# and to domains in DENY_RELAY_TO +# false: Deny relaying except from domains specified in ALLOW_RELAY_FROM +# and to domains in ALLOW_RELAY_TO +RELAY_FROM = 1 +ACCEPT_RELAY_FROM = ('*cbu.edu', '*zope.org') +DENY_RELAY_FROM = () + +RELAY_TO = 1 +ACCEPT_RELAY_TO = ('*.cbu.edu') +DENY_RELAY_TO = () + +# If specified all mail is forwarded to this server. +USE_RELAY_SERVER = '' + +# When set to true, a local sender is only allowed to send, if the connection +# is coming from a local IP. +STRICT_RELAY_TEST = 0 + +# Define some standard mail accounts +ADMIN_ACCOUNT = 'foo' +UNKNOWN_ACCOUNT = 'unknown' + +LOCAL_DOMAIN_NAME = '*cbu.edu' === Zope3/lib/python/Zope/Server/SMTP/SMTPServer.py 1.1.2.4 => 1.1.2.5 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ @@ -20,23 +20,23 @@ import SMTPConfigurations from Zope.Server.ServerBase import ServerBase -from Zope.Server.VFS.OSFileSystem import OSFileSystem +from Zope.Server.VFS.OSFileSystem import OSFileSystem from Zope.Server.VFS.IFilesystemAccess import IFilesystemAccess class SMTPServer(ServerBase): """Generic FTP Server""" - + channel_class = SMTPServerChannel SERVER_IDENT = 'Zope.Server.SMTPServer' config = SMTPConfigurations def __init__(self, ip, port, maildir, *args, **kw): - + assert IFilesystemAccess.isImplementedBy(maildir) self.maildir = maildir - + super(SMTPServer, self).__init__(ip, port, *args, **kw) === Zope3/lib/python/Zope/Server/SMTP/SMTPServerChannel.py 1.1.2.5 => 1.1.2.6 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ @@ -25,7 +25,7 @@ from Zope.Server.VFS.UsernamePassword import UsernamePassword from SMTPStatusMessages import status_msgs -from ISMTPCommandHandler import ISMTPCommandHandler +from ISMTPCommandHandler import ISMTPCommandHandler class SMTPServerChannel(LineServerChannel): @@ -62,7 +62,7 @@ self._from = '' self._to = [] self._message = '' - + self._sender_host = None self.receiving_data = 0 @@ -84,7 +84,7 @@ self.handleMail() break else: - self._message += data + self._message += data data = None else: if preq is None: @@ -105,9 +105,9 @@ def _getFilesystem(self): """Open the filesystem using the current credentials.""" - credentials = UsernamePassword('foo', 'bar') + credentials = UsernamePassword('foo', 'bar') return self.server.maildir.open(credentials) - + ############################################################ # Implementation methods for interface @@ -137,7 +137,7 @@ 'See Zope.Server.SMTP.ISMTPCommandHandler.ISMTPCommandHandler' if args: self.sender_host = args - hostname = args + hostname = args ip = hostname2ip(args, args) self.reply('OK_GREETING', (args, hostname, ip)) else: @@ -203,7 +203,7 @@ self._to = [] self._message = '' self.reply('OK_RESET') - + def cmd_vrfy(self, args): 'See Zope.Server.SMTP.ISMTPCommandHandler.ISMTPCommandHandler' @@ -236,7 +236,7 @@ self._from = '' self._to = [] - self._message = '' + self._message = '' self.reply('OK_DATA_RECV') @@ -251,7 +251,7 @@ # this users mail. It is the final destination. if self.isLocalAddress(address): return 1 - + # set default relay setting allow = config.RELAY_TO @@ -261,7 +261,7 @@ rules = config.DENY_RELAY_TO else: rules = config.ALLOW_RELAY_TO - + # enumerate all rules. they are priority-sorted, with higher # priorities comming later for rule in rules: @@ -278,10 +278,10 @@ address = address[1:-1] config = self.server.config - + # If the sender is a local address, it must come from a local # IP, otherwise access is denied - if ( config.STRICT_RELAY_TEST and + if ( config.STRICT_RELAY_TEST and self.isLocalConnection() and not self.isLocalAddress(address) ): return 0 @@ -317,7 +317,7 @@ # it is a message from somebody outside can_process_message, remote_receivers = 1, 0 - + for receiver in self._to: rid, rcs = self.getAddressID(receiver) @@ -350,7 +350,7 @@ username, domain = address.split('@') except: username, domain = address, '' - + if self.server.maildir.hasUser(username): return username, 1 elif self.config.LOCAL_DOMAIN_NAME == domain.lower(): @@ -369,8 +369,8 @@ except: username, domain = address, '' - return '"%s" <%s@%s>' %(username, username, domain) - + return '"%s" <%s@%s>' %(username, username, domain) + def isLocalConnection(self): name = ip2hostname(self.addr[0]) @@ -394,8 +394,8 @@ return 1 return 0 - - + + def ip2hostname(ip, default=None): """Resolves an IP into a hostname""" @@ -403,7 +403,7 @@ return socket.gethostbyaddr(ip)[0] except socket.herror: return default - + def hostname2ip(hostname, default=None): === Zope3/lib/python/Zope/Server/SMTP/SMTPSpamFilter.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -import spam_data - -def isSpamSubjectLine(subject): - subject = subject.lower() - reload(spam_data) - - weight = float(reduce(lambda x,y:x+y,map(ord,subject)))/len(subject) - if weight > 128: - print "Weight %.2f indicates spam mail." % weight - return 1 - - for token_tuple in spam_data.subject_tokens: - found = 0 - for token in token_tuple: - if subject.find(token) >= 0: - found += 1 - if found == len(token_tuple): - print "Tokens '%s' indicate spam mail." % str(token_tuple).strip() - return 1 - - tokens = subject.split() - try: - isdigit = int(tokens[-1]) - isdigit = len(tokens[-1]) > 3 - except: - isdigit = 0 - if isdigit: - print "Integer as last token indicates spam mail." - return 1 - - return 0 - - -def checkSpamMail(lines): - index = -1 - for line in lines: - index += 1 - if line.strip() == "": break - - s = line.find(':') - if s < 0: continue - - tokens = (line[:s],line[s:]) - keyword = tokens[0].lower() - if keyword == 'subject': - if IsSpamSubjectLine(tokens[1]): - print "SPAM SUBJECT: "+tokens[1].strip() - new_subject_line = line[:9] + "[SPAM] " + line[9:] - lines[index] = new_subject_line - else: - print "NOT SPAM SUBJECT: "+ tokens[1].strip() - break - return lines +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +import spam_data + +def isSpamSubjectLine(subject): + subject = subject.lower() + reload(spam_data) + + weight = float(reduce(lambda x,y:x+y,map(ord,subject)))/len(subject) + if weight > 128: + print "Weight %.2f indicates spam mail." % weight + return 1 + + for token_tuple in spam_data.subject_tokens: + found = 0 + for token in token_tuple: + if subject.find(token) >= 0: + found += 1 + if found == len(token_tuple): + print "Tokens '%s' indicate spam mail." % str(token_tuple).strip() + return 1 + + tokens = subject.split() + try: + isdigit = int(tokens[-1]) + isdigit = len(tokens[-1]) > 3 + except: + isdigit = 0 + if isdigit: + print "Integer as last token indicates spam mail." + return 1 + + return 0 + + +def checkSpamMail(lines): + index = -1 + for line in lines: + index += 1 + if line.strip() == "": break + + s = line.find(':') + if s < 0: continue + + tokens = (line[:s],line[s:]) + keyword = tokens[0].lower() + if keyword == 'subject': + if IsSpamSubjectLine(tokens[1]): + print "SPAM SUBJECT: "+tokens[1].strip() + new_subject_line = line[:9] + "[SPAM] " + line[9:] + lines[index] = new_subject_line + else: + print "NOT SPAM SUBJECT: "+ tokens[1].strip() + break + return lines === Zope3/lib/python/Zope/Server/SMTP/SMTPStatusMessages.py 1.1.2.2 => 1.1.2.3 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - - -status_msgs = { - 'OK_HELP' : '214 Help not available. RTFM!', - 'OK_WELCOME' : '220 %s Zope 3 SMTP Service ready; %s', - 'OK_QUIT' : '221 Closing transmission channel', - 'OK_NOOP' : '250 OK', - 'OK_GREETING' : '250 %s Hello %s [%s], pleased to meet you', - 'OK_FROM_ACCPT' : '250 Sender has been accepted', - 'OK_TO_ACCPT' : '250 Receiver has been accepted', - 'OK_RESET' : '250 Session reset', - 'OK_VERIFY' : '250 %s', - 'OK_DATA_RECV' : '250 Data received', - 'OK_TSFR_START' : '354 Start mail input; end with .', - - 'ERR_CMD_UNKNOWN' : '500 "%s" Syntax error, command unrecognized', - 'ERR_DOMAIN_REQ' : '501 HELO requires domain address', - 'ERR_MISS_FROM' : '501 MAIL command without "FROM:"', - 'ERR_MISS_TO' : '501 RCPT command without "TO:"', - 'ERR_USR_UNKNOWN' : '550 No user called "%s" known', - 'ERR_FROM_DENIED' : '551 Access for sender %s denied', - 'ERR_TO_DENIED' : '551 Access for sender %s denied', - 'ERR_ACC_DENIED' : '551 Data transfer access denied', - } +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + + +status_msgs = { + 'OK_HELP' : '214 Help not available. RTFM!', + 'OK_WELCOME' : '220 %s Zope 3 SMTP Service ready; %s', + 'OK_QUIT' : '221 Closing transmission channel', + 'OK_NOOP' : '250 OK', + 'OK_GREETING' : '250 %s Hello %s [%s], pleased to meet you', + 'OK_FROM_ACCPT' : '250 Sender has been accepted', + 'OK_TO_ACCPT' : '250 Receiver has been accepted', + 'OK_RESET' : '250 Session reset', + 'OK_VERIFY' : '250 %s', + 'OK_DATA_RECV' : '250 Data received', + 'OK_TSFR_START' : '354 Start mail input; end with .', + + 'ERR_CMD_UNKNOWN' : '500 "%s" Syntax error, command unrecognized', + 'ERR_DOMAIN_REQ' : '501 HELO requires domain address', + 'ERR_MISS_FROM' : '501 MAIL command without "FROM:"', + 'ERR_MISS_TO' : '501 RCPT command without "TO:"', + 'ERR_USR_UNKNOWN' : '550 No user called "%s" known', + 'ERR_FROM_DENIED' : '551 Access for sender %s denied', + 'ERR_TO_DENIED' : '551 Access for sender %s denied', + 'ERR_ACC_DENIED' : '551 Data transfer access denied', + } === Zope3/lib/python/Zope/Server/SMTP/SMTPUtilities.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" - -def getLongIpAddress(ipaddr): - """ """ - tokens = ipaddr.split(".") - - if len(tokens) != 4: - raise "ERROR, IP-Address '%s' invalid" % ipaddr - - tokens = map(long,tokens) - - return ( tokens[0] * (256 * 256 * 256) + tokens[1] * (256 * 256) + - tokens[2] * (256) + tokens[3] ) - - -def decodeValidIpRanges(data): - """ """ - data = data.split(",") - - for i in xrange(len(data)): - item = map(GetLongIpAddress,data[i].split("-")) - if len(item) == 1: - item.append(item[0]) - elif len(item) > 2: - raise "ERROR, IP-Addressrange '%s' invalid" % data[i] - data[i] = tuple(item) - return tuple(data) - - -def domainOfAddress(address): - x = address.find('@') - if x >= 0: - return address[x+1:] - return "" - - -def splitMailHeader(s): - result = [] - startindex = -1 - index = 0 - while index < len(s): - c = s[index] - if c == ' ': - # ok, split - if startindex != -1: - result.append(s[startindex:index]) - startindex = -1 - elif c == ':': - # ok, split - if startindex != -1: - result.append(s[startindex:index+1]) - startindex = -1 - # ok, split *including* this character - elif startindex == -1: - startindex = index - index += 1 - if startindex != -1: - result.append(s[startindex:]) - return result - -import spam_data +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" + +def getLongIpAddress(ipaddr): + """ """ + tokens = ipaddr.split(".") + + if len(tokens) != 4: + raise "ERROR, IP-Address '%s' invalid" % ipaddr + + tokens = map(long,tokens) + + return ( tokens[0] * (256 * 256 * 256) + tokens[1] * (256 * 256) + + tokens[2] * (256) + tokens[3] ) + + +def decodeValidIpRanges(data): + """ """ + data = data.split(",") + + for i in xrange(len(data)): + item = map(GetLongIpAddress,data[i].split("-")) + if len(item) == 1: + item.append(item[0]) + elif len(item) > 2: + raise "ERROR, IP-Addressrange '%s' invalid" % data[i] + data[i] = tuple(item) + return tuple(data) + + +def domainOfAddress(address): + x = address.find('@') + if x >= 0: + return address[x+1:] + return "" + + +def splitMailHeader(s): + result = [] + startindex = -1 + index = 0 + while index < len(s): + c = s[index] + if c == ' ': + # ok, split + if startindex != -1: + result.append(s[startindex:index]) + startindex = -1 + elif c == ':': + # ok, split + if startindex != -1: + result.append(s[startindex:index+1]) + startindex = -1 + # ok, split *including* this character + elif startindex == -1: + startindex = index + index += 1 + if startindex != -1: + result.append(s[startindex:]) + return result + +import spam_data === Zope3/lib/python/Zope/Server/SMTP/__init__.py 1.1.2.1 => 1.1.2.2 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" From philikon@gmx.net Thu Apr 11 15:42:56 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Thu, 11 Apr 2002 10:42:56 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl - RuntimeInfo.py:1.1.2.3 Message-ID: <200204111442.g3BEgu204527@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl In directory cvs.zope.org:/tmp/cvs-serv3686 Modified Files: Tag: Zope-3x-branch RuntimeInfo.py Log Message: os.uname() is not available outside Unix. RuntimeInfo will return sys.platform in that case instead. === Zope3/lib/python/Zope/App/OFS/ApplicationControl/RuntimeInfo.py 1.1.2.2 => 1.1.2.3 === def getSystemPlatform(self): 'See Zope.App.OFS.ApplicationControl.IRuntimeInfo.IRuntimeInfo' - return os.uname() + if hasattr(os, "uname"): + return os.uname() + else: + return (sys.platform,) def getCommandLine(self): 'See Zope.App.OFS.ApplicationControl.IRuntimeInfo.IRuntimeInfo' From philikon@gmx.net Thu Apr 11 15:42:56 2002 From: philikon@gmx.net (Philipp von Weitershausen) Date: Thu, 11 Apr 2002 10:42:56 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests - testRuntimeInfo.py:1.1.2.4 Message-ID: <200204111442.g3BEgu804529@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests In directory cvs.zope.org:/tmp/cvs-serv3686/tests Modified Files: Tag: Zope-3x-branch testRuntimeInfo.py Log Message: os.uname() is not available outside Unix. RuntimeInfo will return sys.platform in that case instead. === Zope3/lib/python/Zope/App/OFS/ApplicationControl/tests/testRuntimeInfo.py 1.1.2.3 => 1.1.2.4 === def test_SystemPlatform(self): runtime_info = self._Test__new() - self.assertEqual(runtime_info.getSystemPlatform(), os.uname()) + test_platform = (sys.platform,) + if hasattr(os, "uname"): + test_platform = os.uname() + self.assertEqual(runtime_info.getSystemPlatform(), test_platform) def test_CommandLine(self): runtime_info = self._Test__new() From casey@zope.com Thu Apr 11 15:52:08 2002 From: casey@zope.com (Casey Duncan) Date: Thu, 11 Apr 2002 10:52:08 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Memento - memento.zcml:1.1.2.3 Message-ID: <200204111452.g3BEq8B08037@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Memento In directory cvs.zope.org:/tmp/cvs-serv7846/OFS/Memento Modified Files: Tag: Zope-3x-branch memento.zcml Log Message: Fixed memento configuration to be explicit again. === Zope3/lib/python/Zope/App/OFS/Memento/memento.zcml 1.1.2.2 => 1.1.2.3 === > - + factory=".AttributeMementoBag." + provides=".IMementoBag." + for=".IAttributeMementoStorable." /> From matt@zope.com Thu Apr 11 17:14:54 2002 From: matt@zope.com (Matthew T. Kromer) Date: Thu, 11 Apr 2002 12:14:54 -0400 Subject: [Zope-Checkins] CVS: Products/DCOracle2/DCOracle2 - DCOracle2.py:1.83 Message-ID: <200204111614.g3BGEsN06112@cvs.baymountain.com> Update of /cvs-repository/Products/DCOracle2/DCOracle2 In directory cvs.zope.org:/tmp/cvs-serv5799/DCOracle2 Modified Files: DCOracle2.py Log Message: Made synonyms work with stored procedures; the synonym will now be dereferenced when the getattr is made on the procedure object === Products/DCOracle2/DCOracle2/DCOracle2.py 1.82 => 1.83 === answer.append(contains) + if type == "synonym": + answer.append("%s.%s" % ( + desc['OCI_ATTR_SCHEMA_NAME'], + desc['OCI_ATTR_NAME'] + )) + + if len(answer) < 4: answer.append(None) + return answer @@ -519,6 +527,12 @@ answer = "%s\n%s%s" % (answer, "\t" * indent, self.decodedesc(args[i],indent+1)) + if type == "synonym": + answer = "%sfor %s.%s" % (answer, + desc['OCI_ATTR_SCHEMA_NAME'], + desc['OCI_ATTR_NAME'] + ) + if type == "argument" or type == "column": if type == "argument": mode = desc['OCI_ATTR_IOMODE'] @@ -587,6 +601,8 @@ for d in sdesc[1:]: answer = "%s%s" % (answer, self.decodecdesc(d, indent=indent+1)) + elif etype == "synonym": + answer = "%ssynonym for %s" % (answer, sdesc) elif etype == "argument": if name is not None: answer = "%s%s " % (answer, name) @@ -627,9 +643,9 @@ proc = {} (sname, uname, type, desc) = d - if type == "procedure" or type == "function": + + if type == "procedure" or type == "function" or type == 'synonym': proc[name] = d - return proc elif type == "package": proc[name] = d for d1 in desc: @@ -1358,6 +1374,7 @@ d = newproc.__dict__ # Temporarily override the target dict inpkg = 1 + # Do all entries within the package for p in desc.keys(): (schema, uname, type, pdesc) = desc[p] @@ -1386,6 +1403,13 @@ newproc.__doc__ = cursor._connection.decodecdesc( newproc._description, newproc.__name__) d[uname] = newproc + elif type == 'synonym': + # OK now what? we need to try to look up the synonym in + # this proc -- so we have to go back to the top level + # proc on the cursor (sigh) + + newproc = cursor.findproc(pdesc) + d[uname] = newproc d = self.__dict__ From matt@zope.com Thu Apr 11 17:14:55 2002 From: matt@zope.com (Matthew T. Kromer) Date: Thu, 11 Apr 2002 12:14:55 -0400 Subject: [Zope-Checkins] CVS: Products/DCOracle2 - CHANGELOG:1.47 Message-ID: <200204111614.g3BGEth06117@cvs.baymountain.com> Update of /cvs-repository/Products/DCOracle2 In directory cvs.zope.org:/tmp/cvs-serv5799 Modified Files: CHANGELOG Log Message: Made synonyms work with stored procedures; the synonym will now be dereferenced when the getattr is made on the procedure object === Products/DCOracle2/CHANGELOG 1.46 => 1.47 === o Made TABLE OF support work with stored procs, input and output + o Made SYNONYMs work with stored procedures for Mike Hewiett Desired Features Not Yet Implemented: From shane@cvs.zope.org Thu Apr 11 17:23:38 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 11 Apr 2002 12:23:38 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/POP3/tests - testPOP3Message.py:1.1.2.3 testPOP3MessageList.py:1.1.2.4 testPOP3Server.py:1.1.2.4 Message-ID: <200204111623.g3BGNcn10230@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/POP3/tests In directory cvs.zope.org:/tmp/cvs-serv10201/tests Modified Files: Tag: Zope3-Server-Branch testPOP3Message.py testPOP3MessageList.py testPOP3Server.py Log Message: Disabled the POP3 tests. === Zope3/lib/python/Zope/Server/POP3/tests/testPOP3Message.py 1.1.2.2 => 1.1.2.3 === -def test_suite(): +def disabled_test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(Tests) === Zope3/lib/python/Zope/Server/POP3/tests/testPOP3MessageList.py 1.1.2.3 => 1.1.2.4 === -def test_suite(): +def disabled_test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(Tests) === Zope3/lib/python/Zope/Server/POP3/tests/testPOP3Server.py 1.1.2.3 => 1.1.2.4 === -def test_suite(): +def disabled_test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(Tests) From shane@cvs.zope.org Thu Apr 11 17:25:06 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 11 Apr 2002 12:25:06 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS/tests - testOSFileSystem.py:1.1.2.9 Message-ID: <200204111625.g3BGP6e10557@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS/tests In directory cvs.zope.org:/tmp/cvs-serv10356 Modified Files: Tag: Zope3-Server-Branch testOSFileSystem.py Log Message: Disabled the chown() test. It won't work for most people on Unix. === Zope3/lib/python/Zope/Server/VFS/tests/testOSFileSystem.py 1.1.2.8 => 1.1.2.9 === def testChown(self): + # This test is disabled until we start using a RAM filesystem + # for testing. + return path = os.path.join(self.root, 'foo') open(path, 'w').write('writing test') self.filesystem.chown('foo', 500, 500) From shane@cvs.zope.org Thu Apr 11 17:29:15 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 11 Apr 2002 12:29:15 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/HTTP/tests - testHTTPServer.py:1.1.2.4 testPublisherServer.py:1.1.2.3 Message-ID: <200204111629.g3BGTF412157@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/HTTP/tests In directory cvs.zope.org:/tmp/cvs-serv12014/tests Modified Files: Tag: Zope3-Server-Branch testHTTPServer.py testPublisherServer.py Log Message: - HTTPTask now knows how to build a CGI environment. - Moved execute() to the server rather than the task and renamed it executeRequest(). This simplified PublisherHTTPServer and eliminated the need for two classes. - Reenabled verification of the status code in the tests, which uncovered an important oversight in the publisher refactoring. === Zope3/lib/python/Zope/Server/HTTP/tests/testHTTPServer.py 1.1.2.3 => 1.1.2.4 === from Zope.Server.TaskThreads import ThreadedTaskDispatcher from Zope.Server.HTTP.HTTPServer import HTTPServer -from Zope.Server.HTTP.HTTPServerChannel import HTTPServerChannel -from Zope.Server.HTTP.HTTPTask import HTTPTask from Zope.Server.Adjustments import Adjustments from Zope.Server.ITask import ITask @@ -46,29 +44,19 @@ my_adj.inbuf_overflow = 10000 -class EchoHTTPTask(HTTPTask): +class EchoHTTPServer(HTTPServer): - def execute(self): - headers = self.request_data.headers + def executeRequest(self, task): + headers = task.request_data.headers if headers.has_key('CONTENT_LENGTH'): cl = headers['CONTENT_LENGTH'] - self.response_headers['Content-Length'] = cl - instream = self.request_data.getBodyStream() + task.response_headers['Content-Length'] = cl + instream = task.request_data.getBodyStream() while 1: data = instream.read(8192) if not data: break - self.write(data) - - -class EchoHTTPChannel(HTTPServerChannel): - - task_class = EchoHTTPTask - - -class EchoHTTPServer(HTTPServer): - - channel_class = EchoHTTPChannel + task.write(data) class SleepingTask: === Zope3/lib/python/Zope/Server/HTTP/tests/testPublisherServer.py 1.1.2.2 => 1.1.2.3 === else: response_body = '' - # XXX How to test this now that we don't set the response code? - ##self.failUnlessEqual(int(response.status), status_expected) + + # Please do not disable the status code check. It must work. + self.failUnlessEqual(int(response.status), status_expected) + self.failUnlessEqual(length, len(response_body)) if (status_expected == 200): From shane@cvs.zope.org Thu Apr 11 17:29:15 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 11 Apr 2002 12:29:15 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/HTTP - HTTPServer.py:1.1.2.4 HTTPTask.py:1.1.2.3 PublisherHTTPServer.py:1.1.2.3 PublisherHTTPChannel.py:NONE PublisherHTTPTask.py:NONE Message-ID: <200204111629.g3BGTFc12154@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/HTTP In directory cvs.zope.org:/tmp/cvs-serv12014 Modified Files: Tag: Zope3-Server-Branch HTTPServer.py HTTPTask.py PublisherHTTPServer.py Removed Files: Tag: Zope3-Server-Branch PublisherHTTPChannel.py PublisherHTTPTask.py Log Message: - HTTPTask now knows how to build a CGI environment. - Moved execute() to the server rather than the task and renamed it executeRequest(). This simplified PublisherHTTPServer and eliminated the need for two classes. - Reenabled verification of the status code in the tests, which uncovered an important oversight in the publisher refactoring. === Zope3/lib/python/Zope/Server/HTTP/HTTPServer.py 1.1.2.3 => 1.1.2.4 === SERVER_IDENT = 'Zope.Server.HTTPServer' + def executeRequest(self, task): + """Execute an HTTP request.""" + # This is a default implementation, meant to be overridden. + body = "The HTTP server is running!\r\n" * 10 + task.response_headers['Content-Type'] = 'text/plain' + task.response_headers['Content-Length'] = str(len(body)) + task.write(body) if __name__ == '__main__': === Zope3/lib/python/Zope/Server/HTTP/HTTPTask.py 1.1.2.2 => 1.1.2.3 === +rename_headers = { + 'CONTENT_LENGTH' : 'CONTENT_LENGTH', + 'CONTENT_TYPE' : 'CONTENT_TYPE', + 'CONNECTION' : 'CONNECTION_TYPE', + } + + class HTTPTask: """An HTTP task accepts a request and writes to a channel. @@ -43,6 +50,7 @@ accumulated_headers = None bytes_written = 0 auth_user_name = '' + cgi_env = None def __init__(self, channel, request_data): self.channel = channel @@ -66,7 +74,7 @@ try: try: self.start() - self.execute() + self.channel.server.executeRequest(self) self.finish() except socket.error: self.close_on_finish = 1 @@ -155,19 +163,64 @@ res = '%s\r\n\r\n' % '\r\n'.join(lines) return res + def getCGIEnvironment(self): + """Returns a CGI-like environment.""" + env = self.cgi_env + if env is not None: + # Return the cached copy. + return env + + request_data = self.request_data + path = request_data.path + channel = self.channel + server = channel.server + + while path and path.startswith('/'): + path = path[1:] + + env = {} + env['REQUEST_METHOD'] = request_data.command.upper() + env['SERVER_PORT'] = str(server.port) + env['SERVER_NAME'] = server.server_name + env['SERVER_SOFTWARE'] = server.SERVER_IDENT + env['SERVER_PROTOCOL'] = "HTTP/%s" % self.version + env['CHANNEL_CREATION_TIME'] = channel.creation_time + env['SCRIPT_NAME']='' + env['PATH_INFO']='/' + path + query = request_data.query + if query: + env['QUERY_STRING'] = query + env['GATEWAY_INTERFACE'] = 'CGI/1.1' + addr = channel.addr[0] + env['REMOTE_ADDR'] = addr + + # If the server has a resolver, try to get the + # remote host from the resolver's cache. + resolver = getattr(server, 'resolver', None) + if resolver is not None: + dns_cache = resolver.cache + if dns_cache.has_key(addr): + remote_host = dns_cache[addr][2] + if remote_host is not None: + env['REMOTE_HOST'] = remote_host + + env_has = env.has_key + + for key, value in request_data.headers.items(): + value = value.strip() + mykey = rename_headers.get(key, None) + if mykey is None: + mykey = 'HTTP_%s' % key + if not env_has(mykey): + env[mykey] = value + + self.cgi_env = env + return env + def start(self): now = time.time() self.start_time = now self.response_headers['Date'] = build_http_date (now) - - def execute(self): - """ - Override this. - """ - body = "The HTTP server is running!\r\n" * 10 - self.response_headers['Content-Type'] = 'text/plain' - self.response_headers['Content-Length'] = str(len(body)) - self.write(body) def finish(self): if not self.wrote_header: === Zope3/lib/python/Zope/Server/HTTP/PublisherHTTPServer.py 1.1.2.2 => 1.1.2.3 === from HTTPServer import HTTPServer -from PublisherHTTPChannel import PublisherHTTPChannel +from Zope.Publisher.Publish import publish class PublisherHTTPServer(HTTPServer): @@ -25,9 +25,6 @@ __implements__ = HTTPServer.__implements__ - channel_class = PublisherHTTPChannel - - def __init__(self, request_factory, sub_protocol=None, *args, **kw): self.request_factory = request_factory @@ -39,3 +36,12 @@ HTTPServer.__init__(self, *args, **kw) + def executeRequest(self, task): + """Overrides HTTPServer.executeRequest().""" + env = task.getCGIEnvironment() + instream = task.request_data.getBodyStream() + + request = self.request_factory(instream, task, env) + response = request.getResponse() + response.setHeaderOutput(task) + publish(request) === Removed File Zope3/lib/python/Zope/Server/HTTP/PublisherHTTPChannel.py === === Removed File Zope3/lib/python/Zope/Server/HTTP/PublisherHTTPTask.py === From shane@cvs.zope.org Thu Apr 11 17:34:16 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 11 Apr 2002 12:34:16 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/VFS - VFSRequest.py:1.1.2.5 Message-ID: <200204111634.g3BGYGn13950@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/VFS In directory cvs.zope.org:/tmp/cvs-serv13902/VFS Modified Files: Tag: Zope3-Server-Branch VFSRequest.py Log Message: - Fixed status code handling. For HTTP, default to a special 599, which means nothing set the status code. Added an internalError() call, which should tell the client that the server failed to handle an exception. - Fixed the retry mechanism. Because the status code check was disabled in testHTTPServer, no one knew that retry wasn't working at all. (tsk, tsk!) Had to add another argument to request constructors. === Zope3/lib/python/Zope/Publisher/VFS/VFSRequest.py 1.1.2.4 => 1.1.2.5 === - def __init__(self, body_instream, outstream, environ): + def __init__(self, body_instream, outstream, environ, response=None): """ """ - super(VFSRequest, self).__init__(body_instream, outstream, environ) + super(VFSRequest, self).__init__( + body_instream, outstream, environ, response) self._environ = environ self.method = '' From shane@cvs.zope.org Thu Apr 11 17:34:16 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 11 Apr 2002 12:34:16 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/XMLRPC - XMLRPCRequest.py:1.1.2.2.2.1 Message-ID: <200204111634.g3BGYG813954@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/XMLRPC In directory cvs.zope.org:/tmp/cvs-serv13902/XMLRPC Modified Files: Tag: Zope3-Server-Branch XMLRPCRequest.py Log Message: - Fixed status code handling. For HTTP, default to a special 599, which means nothing set the status code. Added an internalError() call, which should tell the client that the server failed to handle an exception. - Fixed the retry mechanism. Because the status code check was disabled in testHTTPServer, no one knew that retry wasn't working at all. (tsk, tsk!) Had to add another argument to request constructors. === Zope3/lib/python/Zope/Publisher/XMLRPC/XMLRPCRequest.py 1.1.2.2 => 1.1.2.2.2.1 === class TestRequest(XMLRPCRequest): - def __init__(self, body_instream=None, outstream=None, environ=None, **kw): + def __init__(self, body_instream=None, outstream=None, environ=None, + response=None, **kw): _testEnv = { 'SERVER_URL': 'http://127.0.0.1', @@ -78,5 +79,6 @@ if outstream is None: outstream = StringIO() - super(TestRequest, self).__init__(body_instream, outstream, _testEnv) - + super(TestRequest, self).__init__( + body_instream, outstream, _testEnv, response) + From shane@cvs.zope.org Thu Apr 11 17:34:45 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 11 Apr 2002 12:34:45 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher - BaseRequest.py:1.1.2.26.2.1 BaseResponse.py:1.1.2.11.2.1 IPublisherResponse.py:1.1.2.5.2.1 Publish.py:1.1.2.16.2.2 Message-ID: <200204111634.g3BGYjq14020@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher In directory cvs.zope.org:/tmp/cvs-serv13902 Modified Files: Tag: Zope3-Server-Branch BaseRequest.py BaseResponse.py IPublisherResponse.py Publish.py Log Message: - Fixed status code handling. For HTTP, default to a special 599, which means nothing set the status code. Added an internalError() call, which should tell the client that the server failed to handle an exception. - Fixed the retry mechanism. Because the status code check was disabled in testHTTPServer, no one knew that retry wasn't working at all. (tsk, tsk!) Had to add another argument to request constructors. === Zope3/lib/python/Zope/Publisher/BaseRequest.py 1.1.2.26 => 1.1.2.26.2.1 === environment = RequestDataProperty(RequestEnvironment) - def __init__(self, body_instream, outstream, environ, positional=()): + def __init__(self, body_instream, outstream, environ, response=None, + positional=()): self._traversal_stack = [] self._traversed_names = [] self._environ = environ self._args = positional - self._response = self._createResponse(outstream) + if response is None: + self._response = self._createResponse(outstream) + else: + self._response = response self._body_instream = body_instream self._held = () === Zope3/lib/python/Zope/Publisher/BaseResponse.py 1.1.2.11 => 1.1.2.11.2.1 === exc_info[0], exc_info[1], exc_info[2], 100, self) + def internalError(self): + 'See Zope.Publisher.IPublisherResponse.IPublisherResponse' + pass + def retry(self): 'See Zope.Publisher.IPublisherResponse.IPublisherResponse' return self.__class__(self.outstream) === Zope3/lib/python/Zope/Publisher/IPublisherResponse.py 1.1.2.5 => 1.1.2.5.2.1 === def setBody(result): - """Set's the response result value. + """Sets the response result value. """ def handleException(exc_info): - """Handle an otherwise unhandled exception. + """Handles an otherwise unhandled exception. - The handling of the exception is expected to effect the reponse body. + The publication object gets the first chance to handle an exception, + and if it doesn't have a good way to do it, it defers to the + response. Implementations should set the reponse body. + """ + + def internalError(): + """Called when the exception handler bombs. + + Should report back to the client that an internal error occurred. """ - # XXX ZopePublication seems to call this, so maybe this should be - # in an IPublicationResponse interface, but maybe this will change, - # so we'll apply YAGNI for now. def outputBody(): - """Output the response to the client + """Outputs the response to the client """ def retry(): - """Return a retry response + """Returns a retry response - Return a response suitable for repeating the publication attempt. + Returns a response suitable for repeating the publication attempt. """ === Zope3/lib/python/Zope/Publisher/Publish.py 1.1.2.16.2.1 => 1.1.2.16.2.2 === # Bad exception handler or retry method. # Re-raise after outputting the response. + request.getResponse().internalError() to_raise = sys.exc_info() break From shane@cvs.zope.org Thu Apr 11 17:34:45 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 11 Apr 2002 12:34:45 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/Browser - BrowserRequest.py:1.1.4.9.2.1 BrowserResponse.py:1.1.4.3.2.1 Message-ID: <200204111634.g3BGYj914024@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/Browser In directory cvs.zope.org:/tmp/cvs-serv13902/Browser Modified Files: Tag: Zope3-Server-Branch BrowserRequest.py BrowserResponse.py Log Message: - Fixed status code handling. For HTTP, default to a special 599, which means nothing set the status code. Added an internalError() call, which should tell the client that the server failed to handle an exception. - Fixed the retry mechanism. Because the status code check was disabled in testHTTPServer, no one knew that retry wasn't working at all. (tsk, tsk!) Had to add another argument to request constructors. === Zope3/lib/python/Zope/Publisher/Browser/BrowserRequest.py 1.1.4.9 => 1.1.4.9.2.1 === - def __init__(self, body_instream, outstream, environ): + def __init__(self, body_instream, outstream, environ, response=None): self._form = {} - super(BrowserRequest, self).__init__(body_instream, outstream, environ) + super(BrowserRequest, self).__init__( + body_instream, outstream, environ, response) def _createResponse(self, outstream): === Zope3/lib/python/Zope/Publisher/Browser/BrowserResponse.py 1.1.4.3 => 1.1.4.3.2.1 === Sets the return body equal to the (string) argument "body". Also - updates the "content-length" return header. - - If the body is a 2-element tuple, then it will be treated - as (title,body) - - If is_error is true then the HTML will be formatted as a Zope error - message instead of a generic HTML page. + updates the "content-length" return header and sets the status to + 200 if it has not already been set. """ body = str(body) @@ -65,6 +60,8 @@ body = self.__insertBase(body) self._body = body self._updateContentLength() + if not self._status_set: + self.setStatus(200) def __isHTML(self, str): s = str.strip().lower() @@ -85,7 +82,7 @@ def __insertBase(self, body): # Only insert a base tag if content appears to be html. content_type = self.getHeader('content-type', '') - if content_type and content_type != 'text/html': + if content_type and not is_text_html(content_type): return body if getattr(self, '_base', ''): From shane@cvs.zope.org Thu Apr 11 17:34:46 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Thu, 11 Apr 2002 12:34:46 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/HTTP - HTTPRequest.py:1.1.2.24.2.1 HTTPResponse.py:1.1.2.16.2.1 Message-ID: <200204111634.g3BGYkZ14030@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/HTTP In directory cvs.zope.org:/tmp/cvs-serv13902/HTTP Modified Files: Tag: Zope3-Server-Branch HTTPRequest.py HTTPResponse.py Log Message: - Fixed status code handling. For HTTP, default to a special 599, which means nothing set the status code. Added an internalError() call, which should tell the client that the server failed to handle an exception. - Fixed the retry mechanism. Because the status code check was disabled in testHTTPServer, no one knew that retry wasn't working at all. (tsk, tsk!) Had to add another argument to request constructors. === Zope3/lib/python/Zope/Publisher/HTTP/HTTPRequest.py 1.1.2.24 => 1.1.2.24.2.1 === '_app_server', # The server path of the application url '_orig_env', # The original environment - '_endswithslash' # Does the given path end with / + '_endswithslash', # Does the given path end with / ) retry_max_count = 3 # How many times we're willing to retry - def __init__(self, body_instream, outstream, environ): + def __init__(self, body_instream, outstream, environ, response=None): - super(HTTPRequest, self).__init__(body_instream, outstream, environ) + super(HTTPRequest, self).__init__( + body_instream, outstream, environ, response) self._orig_env = environ environ = sane_environment(environ) @@ -293,22 +294,27 @@ def supportsRetry(self): 'See Zope.Publisher.IPublisherRequest.IPublisherRequest' - if self._retry_count < self.retry_max_count: + count = getattr(self, '_retry_count', 0) + if count < self.retry_max_count: if STAGGER_RETRIES: - time.sleep(whrandom.uniform(0, 2**(self.retry_count))) + time.sleep(random.uniform(0, 2**(count))) return 1 def retry(self): 'See Zope.Publisher.IPublisherRequest.IPublisherRequest' - self.retry_count = self.retry_count + 1 - self.body_instream.seek(0) + count = getattr(self, '_retry_count', 0) + self._retry_count = count + 1 + self._body_instream.seek(0) + new_response = self.getResponse().retry() request = self.__class__( - body_instream = self._body_instream, - outstream = self.getResponse().getOutputStream(), - environ = self._orig_env + body_instream=self._body_instream, + outstream=None, + environ=self._orig_env, + response=new_response, ) - request.retry_count = self.retry_count + request.setPublication(self.getPublication()) + request._retry_count = self._retry_count return request === Zope3/lib/python/Zope/Publisher/HTTP/HTTPResponse.py 1.1.2.16 => 1.1.2.16.2.1 === '_wrote_headers', '_streaming', - '_status', # The response status (usually an integer) - '_reason' # The reason that goes with the status + '_status', # The response status (usually an integer) + '_reason', # The reason that goes with the status + '_status_set', # Boolean: status explicitly set ) @@ -121,8 +122,9 @@ self._accumulated_headers = [] self._wrote_headers = 0 self._streaming = 0 - self._status = 200 - self._reason = 'Ok' + self._status = 599 + self._reason = 'No status set' + self._status_set = 0 def setHeaderOutput(self, header_output): @@ -143,7 +145,7 @@ if status_codes.has_key(status): status = status_codes[status] else: - status=500 + status = 500 self._status = status if reason is None: @@ -154,6 +156,7 @@ else: reason = 'Unknown' self._reason = reason + self._status_set = 1 def getStatus(self): @@ -261,6 +264,11 @@ ###################################### # from: Zope.Publisher.IPublisherResponse.IPublisherResponse + def setBody(self, body): + self._body = body + if not self._status_set: + self.setStatus(200) + def handleException(self, exc_info): """ Calls self.setBody() with an error response. @@ -283,6 +291,11 @@ self.setBody(body) + def internalError(self): + 'See Zope.Publisher.IPublisherResponse.IPublisherResponse' + self.setStatus(500, "The engines can't take any more, Jim!") + + def _html(self, title, content): t = escape(title) return ( @@ -292,9 +305,6 @@ "\n" % (t, t, content) ) - - - def retry(self): From andreas@digicool.com Thu Apr 11 18:34:30 2002 From: andreas@digicool.com (Andreas Jung) Date: Thu, 11 Apr 2002 13:34:30 -0400 Subject: [Zope-Checkins] CVS: Zope/ZServer - FCGIServer.py:1.14 Message-ID: <200204111734.g3BHYUR32080@cvs.baymountain.com> Update of /cvs-repository/Zope/ZServer In directory cvs.zope.org:/tmp/cvs-serv32068/ZServer Modified Files: FCGIServer.py Log Message: Collector #341: minor fixes to logging code === Zope/ZServer/FCGIServer.py 1.13 => 1.14 === DebugLogger.log('E', id(self)) + + user_agent=self.get_header('user-agent') + if not user_agent: user_agent='' + referer=self.get_header('referer') + if not referer: referer='' + + auth=self.get_header('Authorization') + name='Anonymous' + if auth is not None: + if string.lower(auth[:6]) == 'basic ': + try: decoded=base64.decodestring(auth[6:]) + except base64.binascii.Error: decoded='' + t = string.split(decoded, ':', 1) + if len(t) < 2: + name = 'Unknown (bad auth string)' + else: + name = t[0] if self.env.has_key('PATH_INFO'): path=self.env['PATH_INFO'] @@ -452,20 +469,22 @@ self.addr[1], time.strftime ( '%d/%b/%Y:%H:%M:%S ', - time.gmtime(time.time()) + time.localtime(time.time()) ) + tz_for_log, - method, path, self.reply_code, bytes + method, path, self.reply_code, bytes, + referer, user_agent ) ) else: self.server.logger.log ( - '127.0.0.1', + '127.0.0.1 ', '- - [%s] "%s %s" %d %d' % ( time.strftime ( '%d/%b/%Y:%H:%M:%S ', - time.gmtime(time.time()) + time.localtime(time.time()) ) + tz_for_log, - method, path, self.reply_code, bytes + method, path, self.reply_code, bytes, + referer, user_agent ) ) From andreas@digicool.com Thu Apr 11 18:36:42 2002 From: andreas@digicool.com (Andreas Jung) Date: Thu, 11 Apr 2002 13:36:42 -0400 Subject: [Zope-Checkins] CVS: Zope/ZServer - FCGIServer.py:1.15 Message-ID: <200204111736.g3BHagk00645@cvs.baymountain.com> Update of /cvs-repository/Zope/ZServer In directory cvs.zope.org:/tmp/cvs-serv631/ZServer Modified Files: FCGIServer.py Log Message: removed auth code === Zope/ZServer/FCGIServer.py 1.14 => 1.15 === if not referer: referer='' - auth=self.get_header('Authorization') - name='Anonymous' - if auth is not None: - if string.lower(auth[:6]) == 'basic ': - try: decoded=base64.decodestring(auth[6:]) - except base64.binascii.Error: decoded='' - t = string.split(decoded, ':', 1) - if len(t) < 2: - name = 'Unknown (bad auth string)' - else: - name = t[0] - if self.env.has_key('PATH_INFO'): path=self.env['PATH_INFO'] else: From matt@zope.com Thu Apr 11 19:21:18 2002 From: matt@zope.com (Matthew T. Kromer) Date: Thu, 11 Apr 2002 14:21:18 -0400 Subject: [Zope-Checkins] CVS: Products/DCOracle2/DCOracle2 - DCOracle2.py:1.84 Message-ID: <200204111821.g3BILIF13388@cvs.baymountain.com> Update of /cvs-repository/Products/DCOracle2/DCOracle2 In directory cvs.zope.org:/tmp/cvs-serv12870/DCOracle2 Modified Files: DCOracle2.py Log Message: Add a wee bit of narration about how stored procedures work in the comments === Products/DCOracle2/DCOracle2/DCOracle2.py 1.83 => 1.84 === # $Id$ +# +# Stored Procedure Narrative Documenation +# +# Stored procedures are some of most difficult thing to get working right. +# Normal statements will undergo type conversion by Oracle for input parameters +# and offer a description of the resultant output columns after the execute +# takes place for conversion back to Python. +# +# Stored procedures, on the other hand, modify variables defined by the +# calling environment. Thus, those variables must be set up in advance, +# and must align with what the procedure is defined for. It is possible +# to still have Oracle do type conversion on the variables (dco2 does +# use strings for numbers at the time of this note) but a lot more must +# be set up in advance for the process to work (e.g. binding arrays of +# a structure, returning cursors, etc.) +# +# The original DCOracle left behind a notion of the "procedure" object +# on a cursor. This procedure object had as children all procedures +# available to the cursor it was invoked on. Thus, you can use +# a notion of cursor.procedures.SCHEMA.PACKAGE.PROCEDURE(params) to invoke +# a particular stored procedure. +# +# DCOracle2 continues this, although it leads to some convoluted looking +# code (particularly the getattr on a procedure). +# +# The database connection can do a schema describe of any object in Oracle. +# This describe() function returns back a dictionary (of lists and more) +# which represent the results of the OCIDescribeAny call. The mapproc +# method on the connection uses describe and the method collapsedesc to +# "collapse" the description down into a more terse form. +# +# The utility functions decodedesc and decodecdesc will decode the +# uncollapsed and collapsed descriptions, for diagnostic purposes. +# +# When mapproc() on a database object is called, it will save the description +# of the mapped object into the _procdesc attribute on the connection. This +# avoids calling OCIDescribeAny again for any schema object. +# +# When a cursor object is asked for its procedure or procedures attribute, +# the cursor __getattr__ code will create a new top-level procedure object, +# if it does not exist, and then save this object into the cursor's dictionary +# so that the __getattr__ code is not called again. +# +# The procedure object's __getattr__ does most of the heavy permutation, +# creating new procedure objects representing each segment of the schema +# name being traversed, and associating the invoking cursor with that object. +# Each time the procedure's __getattr__ makes a new attribute (for dynamic +# discovery) it is added to the procedure's dict so the getattr hook does +# not get invoked again. +# +# The description of the object being traversed is saved in the procedure +# object so it does not have to be fetched again. The decoded description +# is saved in the procedure's __doc__ string as human-readable text. +# +# The cursor's callproc method (the API 2.0 compliant way of invoking a +# stored procedure) calls the cursor findproc() method, which firsts checks +# to see if a known procedure is found by looking in the cursor's _mapproc +# attribute. If not, it breaks the name up by splitting on periods, and +# tries to getattr() each successive element from the procedure object, +# starting with the base procedure object. Once it finds a procedure object +# it saves it in its _mapproc attribute so it does not have to do the +# traversal again. +# + + import dco2 import sys import types From andreas@digicool.com Thu Apr 11 19:45:33 2002 From: andreas@digicool.com (Andreas Jung) Date: Thu, 11 Apr 2002 14:45:33 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/PluginIndexes/common - UnIndex.py:1.10 Message-ID: <200204111845.g3BIjXJ19567@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/PluginIndexes/common In directory cvs.zope.org:/tmp/cvs-serv19554/lib/python/Products/PluginIndexes/common Modified Files: UnIndex.py Log Message: - Collector #343: The ZCatalogs 'Indexes' view showed the wrong number of indexed objects for FieldIndexes. === Zope/lib/python/Products/PluginIndexes/common/UnIndex.py 1.9 => 1.10 === def numObjects(self): """ return number of indexed objects """ - return len(self._index) + return len(self._unindex) def unindex_object(self, documentId): From andreas@digicool.com Thu Apr 11 19:46:03 2002 From: andreas@digicool.com (Andreas Jung) Date: Thu, 11 Apr 2002 14:46:03 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.455 Message-ID: <200204111846.g3BIk3p19658@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv19554/doc Modified Files: CHANGES.txt Log Message: - Collector #343: The ZCatalogs 'Indexes' view showed the wrong number of indexed objects for FieldIndexes. === Zope/doc/CHANGES.txt 1.454 => 1.455 === are no longer deletable to prevent malfunction. + - Collector #343: The ZCatalogs 'Indexes' view showed the + wrong number of indexed objects for FieldIndexes. + + Zope 2.5.1 beta 1 Bugs Fixed From andreas@digicool.com Thu Apr 11 19:46:10 2002 From: andreas@digicool.com (Andreas Jung) Date: Thu, 11 Apr 2002 14:46:10 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/PluginIndexes/common - UnIndex.py:1.7.12.1 Message-ID: <200204111846.g3BIkAo19957@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/PluginIndexes/common In directory cvs.zope.org:/tmp/cvs-serv19665/lib/python/Products/PluginIndexes/common Modified Files: Tag: Zope-2_5-branch UnIndex.py Log Message: - Collector #343: The ZCatalogs 'Indexes' view showed the wrong number of indexed objects for FieldIndexes. === Zope/lib/python/Products/PluginIndexes/common/UnIndex.py 1.7 => 1.7.12.1 === def numObjects(self): """ return number of indexed objects """ - return len(self._index) + return len(self._unindex) def unindex_object(self, documentId): From andreas@digicool.com Thu Apr 11 19:46:39 2002 From: andreas@digicool.com (Andreas Jung) Date: Thu, 11 Apr 2002 14:46:39 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.406.2.40 Message-ID: <200204111846.g3BIkd720122@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv19665/doc Modified Files: Tag: Zope-2_5-branch CHANGES.txt Log Message: - Collector #343: The ZCatalogs 'Indexes' view showed the wrong number of indexed objects for FieldIndexes. === Zope/doc/CHANGES.txt 1.406.2.39 => 1.406.2.40 === cleared the standard Vocabulary. + - Collector #343: The ZCatalogs 'Indexes' view showed the + wrong number of indexed objects for FieldIndexes. Zope 2.5.0 Final From andreas@digicool.com Thu Apr 11 19:46:54 2002 From: andreas@digicool.com (Andreas Jung) Date: Thu, 11 Apr 2002 14:46:54 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.335.2.109 Message-ID: <200204111846.g3BIksn20141@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv20129/doc Modified Files: Tag: Zope-2_4-branch CHANGES.txt Log Message: - Collector #343: The ZCatalogs 'Indexes' view showed the wrong number of indexed objects for FieldIndexes. === Zope/doc/CHANGES.txt 1.335.2.108 => 1.335.2.109 === file HISTORY.txt. + + - Collector #343: The ZCatalogs 'Indexes' view showed the + wrong number of indexed objects for FieldIndexes. + Zope 2.4.4 Bugs Fixed From andreas@digicool.com Thu Apr 11 19:46:54 2002 From: andreas@digicool.com (Andreas Jung) Date: Thu, 11 Apr 2002 14:46:54 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/PluginIndexes/common - UnIndex.py:1.3.4.3 Message-ID: <200204111846.g3BIks320142@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/PluginIndexes/common In directory cvs.zope.org:/tmp/cvs-serv20129/lib/python/Products/PluginIndexes/common Modified Files: Tag: Zope-2_4-branch UnIndex.py Log Message: - Collector #343: The ZCatalogs 'Indexes' view showed the wrong number of indexed objects for FieldIndexes. === Zope/lib/python/Products/PluginIndexes/common/UnIndex.py 1.3.4.2 => 1.3.4.3 === def numObjects(self): """ return number of indexed objects """ - return len(self._index) + return len(self._unindex) def unindex_object(self, documentId): From andreas@digicool.com Thu Apr 11 20:26:41 2002 From: andreas@digicool.com (Andreas Jung) Date: Thu, 11 Apr 2002 15:26:41 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/PluginIndexes/PathIndex - PathIndex.py:1.18 Message-ID: <200204111926.g3BJQfL30336@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/PluginIndexes/PathIndex In directory cvs.zope.org:/tmp/cvs-serv30326/lib/python/Products/PluginIndexes/PathIndex Modified Files: PathIndex.py Log Message: PathIndex returned wrong number of indexed objects === Zope/lib/python/Products/PluginIndexes/PathIndex/PathIndex.py 1.17 => 1.18 === def numObjects(self): """ return the number of indexed objects""" - - x = IISet() - for k,v in self._index.items(): - for level,ids in v.items(): - x = union(x,ids) - - return len(x) + return len(self._unindex) def keys(self): From andreas@digicool.com Thu Apr 11 20:27:40 2002 From: andreas@digicool.com (Andreas Jung) Date: Thu, 11 Apr 2002 15:27:40 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/PluginIndexes/PathIndex - PathIndex.py:1.4.4.4 Message-ID: <200204111927.g3BJReJ30440@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/PluginIndexes/PathIndex In directory cvs.zope.org:/tmp/cvs-serv30433/lib/python/Products/PluginIndexes/PathIndex Modified Files: Tag: Zope-2_4-branch PathIndex.py Log Message: PathIndex returned wrong number of indexed objects === Zope/lib/python/Products/PluginIndexes/PathIndex/PathIndex.py 1.4.4.3 => 1.4.4.4 === def numObjects(self): """ return the number of indexed objects""" - - x = IISet() - for k,v in self._index.items(): - for level,ids in v.items(): - x = union(x,ids) - - return len(x) + return len(self._unindex) def keys(self): From andreas@digicool.com Thu Apr 11 20:27:10 2002 From: andreas@digicool.com (Andreas Jung) Date: Thu, 11 Apr 2002 15:27:10 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/PluginIndexes/PathIndex - PathIndex.py:1.15.16.2 Message-ID: <200204111927.g3BJRAS30424@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/PluginIndexes/PathIndex In directory cvs.zope.org:/tmp/cvs-serv30417/lib/python/Products/PluginIndexes/PathIndex Modified Files: Tag: Zope-2_5-branch PathIndex.py Log Message: PathIndex returned wrong number of indexed objects === Zope/lib/python/Products/PluginIndexes/PathIndex/PathIndex.py 1.15.16.1 => 1.15.16.2 === def numObjects(self): """ return the number of indexed objects""" - - x = IISet() - for k,v in self._index.items(): - for level,ids in v.items(): - x = union(x,ids) - - return len(x) + return len(self._unindex) def keys(self): From jeremy@zope.com Thu Apr 11 21:40:36 2002 From: jeremy@zope.com (Jeremy Hylton) Date: Thu, 11 Apr 2002 16:40:36 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/ZODB/tests - TransactionalUndoStorage.py:1.13.44.2 TransactionalUndoVersionStorage.py:1.4.88.2 Message-ID: <200204112040.g3BKeaL20079@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/ZODB/tests In directory cvs.zope.org:/tmp/cvs-serv20065/tests Modified Files: Tag: Zope-2_5-branch TransactionalUndoStorage.py TransactionalUndoVersionStorage.py Log Message: Backport fix of transaction_id generation from the trunk. The transaction_id generated by undoLog() is now meaningful across packs or across multiple Standby storages. It's possible that the transaction won't be present, but the storage will find it if it is regardless of its exact location in the file. === Zope/lib/python/ZODB/tests/TransactionalUndoStorage.py 1.13.44.1 => 1.13.44.2 === """ +import time import types from ZODB import POSException from ZODB.Transaction import Transaction +from ZODB.referencesf import referencesf +from ZODB.utils import u64 from ZODB.tests.MinPO import MinPO from ZODB.tests.StorageTestBase import zodb_pickle, zodb_unpickle @@ -421,3 +424,36 @@ self._storage.transactionalUndo, tid, t) self._storage.tpc_abort(t) + + def checkTransactionalUndoAfterPack(self): + eq = self.assertEqual + # Add a few object revisions + oid = self._storage.new_oid() + revid1 = self._dostore(oid, data=MinPO(51)) + # Save now for packing away revid1 + packtime = time.time() + time.sleep(1) + revid2 = self._dostore(oid, revid=revid1, data=MinPO(52)) + revid3 = self._dostore(oid, revid=revid2, data=MinPO(53)) + # Now get the undo log + info = self._storage.undoInfo() + eq(len(info), 3) + tid = info[0]['id'] + # Now pack just the initial revision of the object. We need the + # second revision otherwise we won't be able to undo the third + # revision! + self._storage.pack(packtime, referencesf) + # Make some basic assertions about the undo information now + info2 = self._storage.undoInfo() + eq(len(info2), 2) + # And now attempt to undo the last transaction + t = Transaction() + self._storage.tpc_begin(t) + oids = self._storage.transactionalUndo(tid, t) + self._storage.tpc_vote(t) + self._storage.tpc_finish(t) + eq(len(oids), 1) + eq(oids[0], oid) + data, revid = self._storage.load(oid, '') + # The object must now be at the second state + eq(zodb_unpickle(data), MinPO(52)) === Zope/lib/python/ZODB/tests/TransactionalUndoVersionStorage.py 1.4.88.1 => 1.4.88.2 === + # Check interactions between transactionalUndo() and versions. Any storage # that supports both transactionalUndo() and versions must pass these tests. +import time + from ZODB import POSException +from ZODB.referencesf import referencesf from ZODB.Transaction import Transaction from ZODB.tests.MinPO import MinPO from ZODB.tests.StorageTestBase import zodb_unpickle @@ -95,3 +100,115 @@ assert zodb_unpickle(data) == MinPO(92) data, revid = self._storage.load(oid, '') assert zodb_unpickle(data) == MinPO(91) + + def checkUndoCommitVersion(self): + def load_value(oid, version=''): + data, revid = self._storage.load(oid, version) + return zodb_unpickle(data).value + + # create a bunch of packable transactions + oid = self._storage.new_oid() + revid = '\000' * 8 + for i in range(4): + revid = self._dostore(oid, revid, description='packable%d' % i) + pt = time.time() + time.sleep(1) + + oid1 = self._storage.new_oid() + version = 'version' + revid1 = self._dostore(oid1, data=MinPO(0), description='create1') + revid2 = self._dostore(oid1, data=MinPO(1), revid=revid1, + version=version, description='version1') + revid3 = self._dostore(oid1, data=MinPO(2), revid=revid2, + version=version, description='version2') + self._dostore(description='create2') + + t = Transaction() + t.description = 'commit version' + self._storage.tpc_begin(t) + self._storage.commitVersion(version, '', t) + self._storage.tpc_vote(t) + self._storage.tpc_finish(t) + + info = self._storage.undoInfo() + t_id = info[0]['id'] + + self.assertEqual(load_value(oid1), 2) + self.assertEqual(load_value(oid1, version), 2) + + self._storage.pack(pt, referencesf) + + t = Transaction() + t.description = 'undo commit version' + self._storage.tpc_begin(t) + self._storage.transactionalUndo(t_id, t) + self._storage.tpc_vote(t) + self._storage.tpc_finish(t) + + self.assertEqual(load_value(oid1), 0) + self.assertEqual(load_value(oid1, version), 2) + + def checkUndoAbortVersion(self): + def load_value(oid, version=''): + data, revid = self._storage.load(oid, version) + return zodb_unpickle(data).value + + # create a bunch of packable transactions + oid = self._storage.new_oid() + revid = '\000' * 8 + for i in range(3): + revid = self._dostore(oid, revid, description='packable%d' % i) + pt = time.time() + time.sleep(1) + + oid1 = self._storage.new_oid() + version = 'version' + revid1 = self._dostore(oid1, data=MinPO(0), description='create1') + revid2 = self._dostore(oid1, data=MinPO(1), revid=revid1, + version=version, description='version1') + revid3 = self._dostore(oid1, data=MinPO(2), revid=revid2, + version=version, description='version2') + self._dostore(description='create2') + + t = Transaction() + t.description = 'abort version' + self._storage.tpc_begin(t) + self._storage.abortVersion(version, t) + self._storage.tpc_vote(t) + self._storage.tpc_finish(t) + + info = self._storage.undoInfo() + t_id = info[0]['id'] + + self.assertEqual(load_value(oid1), 0) + # after abort, we should see non-version data + self.assertEqual(load_value(oid1, version), 0) + + t = Transaction() + t.description = 'undo abort version' + self._storage.tpc_begin(t) + self._storage.transactionalUndo(t_id, t) + self._storage.tpc_vote(t) + self._storage.tpc_finish(t) + + self.assertEqual(load_value(oid1), 0) + # t undo will re-create the version + self.assertEqual(load_value(oid1, version), 2) + + info = self._storage.undoInfo() + t_id = info[0]['id'] + + self._storage.pack(pt, referencesf) + + t = Transaction() + t.description = 'undo undo' + self._storage.tpc_begin(t) + self._storage.transactionalUndo(t_id, t) + self._storage.tpc_vote(t) + self._storage.tpc_finish(t) + + # undo of undo will put as back where we started + self.assertEqual(load_value(oid1), 0) + # after abort, we should see non-version data + self.assertEqual(load_value(oid1, version), 0) + From jeremy@zope.com Thu Apr 11 21:40:36 2002 From: jeremy@zope.com (Jeremy Hylton) Date: Thu, 11 Apr 2002 16:40:36 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/ZODB - FileStorage.py:1.76.16.3 Message-ID: <200204112040.g3BKeao20078@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/ZODB In directory cvs.zope.org:/tmp/cvs-serv20065 Modified Files: Tag: Zope-2_5-branch FileStorage.py Log Message: Backport fix of transaction_id generation from the trunk. The transaction_id generated by undoLog() is now meaningful across packs or across multiple Standby storages. It's possible that the transaction won't be present, but the storage will find it if it is regardless of its exact location in the file. === Zope/lib/python/ZODB/FileStorage.py 1.76.16.2 => 1.76.16.3 === def load(self, oid, version, _stuff=None): self._lock_acquire() - try: return self._load(oid, version, self._index, self._file) - finally: self._lock_release() + try: + return self._load(oid, version, self._index, self._file) + finally: + self._lock_release() def loadSerial(self, oid, serial): self._lock_acquire() try: - _index=self._index file=self._file seek=file.seek read=file.read try: - pos=_index[oid] + pos = self._index[oid] except KeyError: raise POSKeyError(oid) while 1: @@ -619,7 +620,10 @@ def modifiedInVersion(self, oid): self._lock_acquire() try: - pos=self._index[oid] + try: + pos = self._index[oid] + except KeyError: + raise POSKeyError(oid) file=self._file seek=file.seek seek(pos) @@ -873,7 +877,7 @@ self._lock_acquire() try: self._clear_index() - transaction_id=base64.decodestring(transaction_id+'==\n') + transaction_id=base64.decodestring(transaction_id + '\n') tid, tpos = transaction_id[:8], U64(transaction_id[8:]) packt=self._packt if packt is None or packt > tid: @@ -967,7 +971,6 @@ self._file.seek(pos+8) return self._file.read(8) - def _transactionalUndoRecord(self, oid, pos, serial, pre, version): """Get the indo information for a data record @@ -975,7 +978,6 @@ version, packed non-version data pointer, and current position. If the pickle is true, then the data pointer must be 0, but the pickle can be empty *and* the pointer 0. - """ copy=1 # Can we just copy a data pointer @@ -1031,6 +1033,85 @@ raise UndoError('Some data were modified by a later transaction') + # undoLog() returns a description dict that includes an id entry. + # The id is opaque to the client, but encodes information that + # uniquely identifies a transaction in the storage. The id is a + # base64 encoded string, where the components of the string are: + # - the transaction id + # - the packed file position of the transaction record + # - the oid of an object modified by the transaction + + # The file position is sufficient in most cases, but doesn't work + # if the id is used after a pack and may not work if used with + # replicated storages. If the file position is incorrect, the oid + # can be used for a relatively efficient search for the + # transaction record. FileStorage keeps an index mapping oids to + # file positions, but do notes have a transaction id to file + # offset index. The oid index maps to the most recent revision of + # the object. Transactional undo must follow back pointers until + # it finds the correct transaction record, + + # This approach fails if the transaction record has no data + # records. It's not clear if that is possible, but it may be for + # commitVersion and abortVersion. + + # The file offset also supports non-transactional undo, which + # won't work after a pack and isn't supported by replicated + # storages. + + def undoLog(self, first=0, last=-20, filter=None): + if last < 0: + last = first - last + 1 + self._lock_acquire() + try: + if self._packt is None: + raise UndoError( + 'Undo is currently disabled for database maintenance.

') + pos = self._pos + r = [] + i = 0 + # BAW: Why 39 please? This makes no sense (see also below). + while i < last and pos > 39: + self._file.seek(pos - 8) + pos = pos - U64(self._file.read(8)) - 8 + self._file.seek(pos) + h = self._file.read(TRANS_HDR_LEN) + tid, tl, status, ul, dl, el = struct.unpack(">8s8scHHH", h) + if tid < self._packt: + break + if status != ' ': + continue + d = u = '' + if ul: + u = self._file.read(ul) + if dl: + d = self._file.read(dl) + e = {} + if el: + try: + e = loads(read(el)) + except: + pass + next = self._file.read(8) + # next is either the redundant txn length - 8, or an oid + if next == tl: + # There were no objects in this txn + id = tid + p64(pos) + else: + id = tid + p64(pos) + next + d = {'id': base64.encodestring(id).rstrip(), + 'time': TimeStamp(tid).timeTime(), + 'user_name': u, + 'description': d} + d.update(e) + if filter is None or filter(d): + if i >= first: + r.append(d) + i += 1 + return r + finally: + self._lock_release() + def transactionalUndo(self, transaction_id, transaction): """Undo a transaction, given by transaction_id. @@ -1050,124 +1131,136 @@ self._lock_acquire() try: - transaction_id = base64.decodestring(transaction_id + '==\n') - tid, tpos = transaction_id[:8], U64(transaction_id[8:]) - - ostloc = p64(self._pos) - here = self._pos + (self._tfile.tell() + self._thl) + return self._txn_undo(transaction_id) + finally: + self._lock_release() - self._file.seek(tpos) - h = self._file.read(TRANS_HDR_LEN) - if len(h) != TRANS_HDR_LEN or h[:8] != tid: - raise UndoError, 'Invalid undo transaction id' - if h[16] == 'u': - return - if h[16] != ' ': - raise UndoError, 'non-undoable transaction' - tl = U64(h[8:16]) - ul, dl, el = struct.unpack(">HHH", h[17:TRANS_HDR_LEN]) - tend = tpos + tl - pos = tpos + (TRANS_HDR_LEN + ul + dl + el) - tindex = {} - failures = {} # keep track of failures, cause we may succeed later - failed = failures.has_key - # Read the data records for this transaction - while pos < tend: + def _txn_undo(self, transaction_id): + # Find the right transaction to undo and call _txn_undo_write(). + transaction_id = base64.decodestring(transaction_id + '\n') + tid = transaction_id[:8] + tpos = U64(transaction_id[8:16]) + if not self._check_txn_pos(tpos, tid): + # If the pos and tid don't match, we must use the oid to + # find the transaction record. Find the file position for + # the current revision of this object, and search back for + # the beginning of its transaction record + oid = transaction_id[16:] + if oid == '' or not self._index.has_key(oid): + # XXX Is this the right error message? + raise UndoError('Undoing a non-object affecting transaction') + pos = self._index[oid] + while 1: self._file.seek(pos) h = self._file.read(DATA_HDR_LEN) - oid, serial, sprev, stloc, vlen, splen = \ - struct.unpack(">8s8s8s8sH8s", h) - if failed(oid): - del failures[oid] # second chance! - plen = U64(splen) - prev = U64(sprev) - if vlen: - dlen = DATA_VERSION_HDR_LEN + vlen + (plen or 8) - self._file.seek(16, 1) - version = self._file.read(vlen) - else: - dlen = DATA_HDR_LEN + (plen or 8) - version = '' + doid, serial, prev, tpos, vlen, plen = \ + unpack('>8s8s8s8sH8s', h) + tpos = U64(tpos) + self._file.seek(tpos) + # Read transaction id to see if we've got a match + thistid = self._file.read(8) + if thistid == tid: + break # Yeee ha! + # Keep looking + pos = U64(prev) + if not pos: + # We never found the right transaction + raise UndoError('Invalid undo transaction id') + tindex = self._txn_undo_write(tpos, tid) + self._tindex.update(tindex) + return tindex.keys() - try: - p, prev, v, snv, ipos = self._transactionalUndoRecord( - oid, pos, serial, prev, version) - except UndoError, v: - # Don't fail right away. We may be redeemed later! - failures[oid] = v + def _check_txn_pos(self, pos, tid): + "Return true if pos is location of the transaction record for tid." + self._file.seek(pos) + this_tid = self._file.read(8) + if this_tid != tid: + return 0 + # be extra cautious: Check the record length makes sense, to + # guard against a random file location that happens to have + # the right 8-byte pattern. + stlen = self._file.read(8) + tlen = U64(stlen) + self._file.seek(tlen, 1) + redundant_stlen = self._file.read(8) + if len(redundant_stlen) != 8: + return 0 + if redundant_stlen != stlen: + return 0 + return 1 + + def _txn_undo_write(self, tpos, tid): + # a helper function to write the data records for transactional undo + + ostloc = p64(self._pos) + here = self._pos + (self._tfile.tell() + self._thl) + # Let's move the file pointer back to the start of the txn record. + self._file.seek(tpos) + h = self._file.read(TRANS_HDR_LEN) + if h[16] == 'u': + return + if h[16] != ' ': + raise UndoError('non-undoable transaction') + tl = U64(h[8:16]) + ul, dl, el = struct.unpack(">HHH", h[17:TRANS_HDR_LEN]) + tend = tpos + tl + pos = tpos + (TRANS_HDR_LEN + ul + dl + el) + tindex = {} + failures = {} # keep track of failures, cause we may succeed later + failed = failures.has_key + # Read the data records for this transaction + while pos < tend: + self._file.seek(pos) + h = self._file.read(DATA_HDR_LEN) + oid, serial, sprev, stloc, vlen, splen = \ + struct.unpack(">8s8s8s8sH8s", h) + if failed(oid): + del failures[oid] # second chance! + plen = U64(splen) + prev = U64(sprev) + if vlen: + dlen = DATA_VERSION_HDR_LEN + vlen + (plen or 8) + self._file.seek(16, 1) + version = self._file.read(vlen) + else: + dlen = DATA_HDR_LEN + (plen or 8) + version = '' + + try: + p, prev, v, snv, ipos = self._transactionalUndoRecord( + oid, pos, serial, prev, version) + except UndoError, v: + # Don't fail right away. We may be redeemed later! + failures[oid] = v + else: + plen = len(p) + self._tfile.write(pack(">8s8s8s8sH8s", + oid, self._serial, p64(ipos), + ostloc, len(v), p64(plen))) + if v: + vprev=self._tvindex.get(v, 0) or self._vindex.get(v, 0) + self._tfile.write(snv + p64(vprev) + v) + self._tvindex[v] = here + odlen = DATA_VERSION_HDR_LEN + len(v)+(plen or 8) else: - plen =len(p) - self._tfile.write(pack(">8s8s8s8sH8s", - oid, self._serial, p64(ipos), - ostloc, len(v), p64(plen))) - if v: - vprev=self._tvindex.get(v, 0) or self._vindex.get(v, 0) - self._tfile.write(snv + p64(vprev) + v) - self._tvindex[v]=here - odlen = DATA_VERSION_HDR_LEN + len(v)+(plen or 8) - else: - odlen = DATA_HDR_LEN+(plen or 8) - - if p: - self._tfile.write(p) - else: - self._tfile.write(p64(prev)) - tindex[oid]=here - here=here+odlen + odlen = DATA_HDR_LEN+(plen or 8) - pos=pos+dlen - if pos > tend: - raise UndoError, 'non-undoable transaction' + if p: + self._tfile.write(p) + else: + self._tfile.write(p64(prev)) + tindex[oid] = here + here += odlen - if failures: raise UndoError(failures) - self._tindex.update(tindex) - return tindex.keys() + pos=pos+dlen + if pos > tend: + raise UndoError, 'non-undoable transaction' - finally: self._lock_release() + if failures: + raise UndoError(failures) - def undoLog(self, first=0, last=-20, filter=None): - if last < 0: last=first-last+1 - self._lock_acquire() - try: - packt=self._packt - if packt is None: - raise UndoError( - 'Undo is currently disabled for database maintenance.

') - pos=self._pos - if pos < 39: return [] - file=self._file - seek=file.seek - read=file.read - unpack=struct.unpack - strip=string.strip - encode=base64.encodestring - r=[] - append=r.append - i=0 - while i < last and pos > 39: - seek(pos-8) - pos=pos-U64(read(8))-8 - seek(pos) - h=read(TRANS_HDR_LEN) - tid, tl, status, ul, dl, el = unpack(">8s8scHHH", h) - if tid < packt: break - if status != ' ': continue - u=ul and read(ul) or '' - d=dl and read(dl) or '' - d={'id': encode(tid+p64(pos))[:22], - 'time': TimeStamp(tid).timeTime(), - 'user_name': u, 'description': d} - if el: - try: - e=loads(read(el)) - d.update(e) - except: pass - if filter is None or filter(d): - if i >= first: append(d) - i=i+1 - - return r - finally: self._lock_release() + return tindex + def versionEmpty(self, version): if not version: From andreas@digicool.com Fri Apr 12 15:08:12 2002 From: andreas@digicool.com (Andreas Jung) Date: Fri, 12 Apr 2002 10:08:12 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.456 Message-ID: <200204121408.g3CE8CB18972@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv18886/doc Modified Files: CHANGES.txt Log Message: - FTP server: replaced 'System_Process' by 'Sysproc' to avoid breaking some FTP clients and the output format with overlong usernames. === Zope/doc/CHANGES.txt 1.455 => 1.456 === - Collector #343: The ZCatalogs 'Indexes' view showed the wrong number of indexed objects for FieldIndexes. + + - FTP server: replaced 'System_Process' by 'Sysproc' to + avoid breaking some FTP clients and the output format + with overlong usernames. Zope 2.5.1 beta 1 From andreas@digicool.com Fri Apr 12 15:08:12 2002 From: andreas@digicool.com (Andreas Jung) Date: Fri, 12 Apr 2002 10:08:12 -0400 Subject: [Zope-Checkins] CVS: Zope/ZServer/medusa - filesys.py:1.11 Message-ID: <200204121408.g3CE8Cj18973@cvs.baymountain.com> Update of /cvs-repository/Zope/ZServer/medusa In directory cvs.zope.org:/tmp/cvs-serv18886/ZServer/medusa Modified Files: filesys.py Log Message: - FTP server: replaced 'System_Process' by 'Sysproc' to avoid breaking some FTP clients and the output format with overlong usernames. === Zope/ZServer/medusa/filesys.py 1.10 => 1.11 === dirchar = '-' date = ls_date (long(time.time()), stat_info[stat.ST_MTIME]) + user = str(stat_info[stat.ST_UID].replace(' ','_')) + group= str(stat_info[stat.ST_GID].replace(' ','_')) + if user=='System_Processes': user='Sysproc' + if group=='System_Processes': group='Sysproc' + return '%s%s %3d %-8s %-8s %8d %s %s' % ( dirchar, mode, stat_info[stat.ST_NLINK], - stat_info[stat.ST_UID].replace(' ','_'), - stat_info[stat.ST_GID].replace(' ','_'), + user, + group, stat_info[stat.ST_SIZE], date, file From andreas@digicool.com Fri Apr 12 15:11:23 2002 From: andreas@digicool.com (Andreas Jung) Date: Fri, 12 Apr 2002 10:11:23 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.406.2.41 Message-ID: <200204121411.g3CEBNG20094@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv19641/doc Modified Files: Tag: Zope-2_5-branch CHANGES.txt Log Message: - FTP server: replaced 'System_Process' by 'Sysproc' to avoid breaking some FTP clients and the output format with overlong usernames. === Zope/doc/CHANGES.txt 1.406.2.40 => 1.406.2.41 === wrong number of indexed objects for FieldIndexes. + - FTP server: replaced 'System_Process' by 'Sysproc' to + avoid breaking some FTP clients and the output format + with overlong usernames. + Zope 2.5.0 Final Bugs Fixed From andreas@digicool.com Fri Apr 12 15:11:23 2002 From: andreas@digicool.com (Andreas Jung) Date: Fri, 12 Apr 2002 10:11:23 -0400 Subject: [Zope-Checkins] CVS: Zope/ZServer/medusa - filesys.py:1.9.90.2 Message-ID: <200204121411.g3CEBNf20096@cvs.baymountain.com> Update of /cvs-repository/Zope/ZServer/medusa In directory cvs.zope.org:/tmp/cvs-serv19641/ZServer/medusa Modified Files: Tag: Zope-2_5-branch filesys.py Log Message: - FTP server: replaced 'System_Process' by 'Sysproc' to avoid breaking some FTP clients and the output format with overlong usernames. === Zope/ZServer/medusa/filesys.py 1.9.90.1 => 1.9.90.2 === dirchar = '-' date = ls_date (long(time.time()), stat_info[stat.ST_MTIME]) + user = str(stat_info[stat.ST_UID].replace(' ','_')) + group= str(stat_info[stat.ST_GID].replace(' ','_')) + if user=='System_Processes': user='Sysproc' + if group=='System_Processes': group='Sysproc' + return '%s%s %3d %-8s %-8s %8d %s %s' % ( dirchar, mode, stat_info[stat.ST_NLINK], +<<<<<<< filesys.py stat_info[stat.ST_UID].replace(' ','_'), stat_info[stat.ST_GID].replace(' ','_'), +======= + user, + group, +>>>>>>> 1.11 stat_info[stat.ST_SIZE], date, file From andreas@digicool.com Fri Apr 12 15:17:16 2002 From: andreas@digicool.com (Andreas Jung) Date: Fri, 12 Apr 2002 10:17:16 -0400 Subject: [Zope-Checkins] CVS: Zope/ZServer/medusa - filesys.py:1.9.90.3 Message-ID: <200204121417.g3CEHGH21455@cvs.baymountain.com> Update of /cvs-repository/Zope/ZServer/medusa In directory cvs.zope.org:/tmp/cvs-serv21447/ZServer/medusa Modified Files: Tag: Zope-2_5-branch filesys.py Log Message: fixed merge conflict === Zope/ZServer/medusa/filesys.py 1.9.90.2 => 1.9.90.3 === mode, stat_info[stat.ST_NLINK], -<<<<<<< filesys.py - stat_info[stat.ST_UID].replace(' ','_'), - stat_info[stat.ST_GID].replace(' ','_'), -======= user, group, ->>>>>>> 1.11 stat_info[stat.ST_SIZE], date, file From shane@cvs.zope.org Fri Apr 12 15:35:12 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 10:35:12 -0400 Subject: [Zope-Checkins] CVS: Zope/ZServer/medusa - ftp_server.py:1.18.60.1 Message-ID: <200204121435.g3CEZCH26051@cvs.baymountain.com> Update of /cvs-repository/Zope/ZServer/medusa In directory cvs.zope.org:/tmp/cvs-serv25964 Modified Files: Tag: Zope-2_5-branch ftp_server.py Log Message: Fixed blocking FTP connections === Zope/ZServer/medusa/ftp_server.py 1.18 => 1.18.60.1 === # methods, using try/finally. [this seems to work] -VERSION = string.split(RCS_ID)[2] +if RCS_ID.startswith('$Id: '): + VERSION = string.split(RCS_ID)[2] +else: + VERSION = '0.0' from counter import counter import producers @@ -829,6 +832,7 @@ def handle_accept (self): conn, addr = self.accept() + conn.setblocking(0) dc = self.control_channel.client_dc if dc is not None: dc.set_socket (conn) From shane@cvs.zope.org Fri Apr 12 15:38:04 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 10:38:04 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.406.2.42 Message-ID: <200204121438.g3CEc4v27130@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv27049 Modified Files: Tag: Zope-2_5-branch CHANGES.txt Log Message: ... === Zope/doc/CHANGES.txt 1.406.2.41 => 1.406.2.42 === with overlong usernames. + - FTP: some passive FTP connections were blocking. Fixed. + Zope 2.5.0 Final Bugs Fixed From tdickenson@geminidataloggers.com Fri Apr 12 15:55:17 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Fri, 12 Apr 2002 10:55:17 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - ImageFile.py:1.15.40.1 Message-ID: <200204121455.g3CEtHs31162@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv31146/lib/python/App Modified Files: Tag: toby-cacheable-zmi-branch ImageFile.py Log Message: collector 196; better caching of ZMI === Zope/lib/python/App/ImageFile.py 1.15 => 1.15.40.1 === from os import stat import Acquisition +import Globals import os - class ImageFile(Acquisition.Explicit): """Image objects stored in external files.""" - def __init__(self,path,_prefix=None): + def __init__(self,path,_prefix=None,max_age=None): if _prefix is None: _prefix=SOFTWARE_HOME elif type(_prefix) is not type(''): _prefix=package_home(_prefix) path = os.path.join(_prefix, path) self.path=path + self.cch = 'public' + if max_age is None: + # Use a default value + if Globals.DevelopmentMode: + # In development mode, shorter is handy + max_age = 60 + else: + # In production mode, longer saves bandwith and latency + max_age = 600 + if max_age: + self.cch += ', max-age=%d' % max_age file=open(path, 'rb') data=file.read() @@ -52,6 +63,9 @@ # HTTP If-Modified-Since header handling. This is duplicated # from OFS.Image.Image - it really should be consolidated # somewhere... + RESPONSE.setHeader('Content-Type', self.content_type) + RESPONSE.setHeader('Last-Modified', self.lmh) + RESPONSE.setHeader('Cache-Control', self.cch) header=REQUEST.get_header('If-Modified-Since', None) if header is not None: header=header.split(';')[0] @@ -72,8 +86,6 @@ RESPONSE.setStatus(304) return '' - RESPONSE.setHeader('Content-Type', self.content_type) - RESPONSE.setHeader('Last-Modified', self.lmh) f=open(self.path,'rb') data=f.read() f.close() From tdickenson@geminidataloggers.com Fri Apr 12 15:55:17 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Fri, 12 Apr 2002 10:55:17 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App/dtml - manage_page_style.css.dtml:1.7.68.1 Message-ID: <200204121455.g3CEtH631164@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App/dtml In directory cvs.zope.org:/tmp/cvs-serv31146/lib/python/App/dtml Modified Files: Tag: toby-cacheable-zmi-branch manage_page_style.css.dtml Log Message: collector 196; better caching of ZMI === Zope/lib/python/App/dtml/manage_page_style.css.dtml 1.7 => 1.7.68.1 === + h1 { font-family: Verdana, Helvetica, sans-serif; From tdickenson@geminidataloggers.com Fri Apr 12 15:55:47 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Fri, 12 Apr 2002 10:55:47 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.453.2.1.2.1 Message-ID: <200204121455.g3CEtlZ31170@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv31146/doc Modified Files: Tag: toby-cacheable-zmi-branch CHANGES.txt Log Message: collector 196; better caching of ZMI === Zope/doc/CHANGES.txt 1.453.2.1 => 1.453.2.1.2.1 === objects to be created in the specified container object. + - Collector 196: manage_page_style.css is now cacheable. + Added freshness information to ImageFile, to improve + cacheability of management interface + Bugs: - Fixed bug reported on maillist during EWOULDBLOCK when using FTP server From shane@cvs.zope.org Fri Apr 12 16:02:32 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 11:02:32 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication/XMLRPC - Publication.py:1.1.2.2.2.1 Message-ID: <200204121502.g3CF2Wm01009@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/XMLRPC In directory cvs.zope.org:/tmp/cvs-serv1002 Modified Files: Tag: Zope3-Server-Branch Publication.py Log Message: Removed CRs === Zope3/lib/python/Zope/App/ZopePublication/XMLRPC/Publication.py 1.1.2.2 => 1.1.2.2.2.1 === # ############################################################################## -""" - -$Id$ -""" - -from Zope.App.ZopePublication.HTTP.Publication import ZopeHTTPPublication -from Zope.ComponentArchitecture import getRequestView -from Zope.ContextWrapper import Wrapper -from Zope.App.Security.SecurityManagement import getSecurityManager - - -class XMLRPCPublication(ZopeHTTPPublication): - """XML-RPC publication handling. - - There is nothing special here right now. - """ - - -# For now, have a factory that returns a singleton -class XMLRPCPublicationFactory: - - def __init__(self, db): - self.__pub = XMLRPCPublication(db) - - def __call__(self): - return self.__pub +""" + +$Id$ +""" + +from Zope.App.ZopePublication.HTTP.Publication import ZopeHTTPPublication +from Zope.ComponentArchitecture import getRequestView +from Zope.ContextWrapper import Wrapper +from Zope.App.Security.SecurityManagement import getSecurityManager + + +class XMLRPCPublication(ZopeHTTPPublication): + """XML-RPC publication handling. + + There is nothing special here right now. + """ + + +# For now, have a factory that returns a singleton +class XMLRPCPublicationFactory: + + def __init__(self, db): + self.__pub = XMLRPCPublication(db) + + def __call__(self): + return self.__pub From shane@cvs.zope.org Fri Apr 12 16:08:10 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 11:08:10 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - FTPServerChannel.py:1.1.2.24 Message-ID: <200204121508.g3CF8AV02383@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv2302 Modified Files: Tag: Zope3-Server-Branch FTPServerChannel.py Log Message: After discussing this, it turns out os.path.normpath is a good thing after all. === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.23 => 1.1.2.24 === def _generatePath(self, args): - # Get the right source path. + """Convert relative paths to absolute paths.""" if args.startswith('/'): path = args else: path = os.path.join(self.cwd, args) - return self._getFilesystem().normalize(path) + if path.startswith('..'): + path = '/' + return os.path.normpath(path) def newPassiveAcceptor(self): From shane@cvs.zope.org Fri Apr 12 16:10:15 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 11:10:15 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - TestFilesystemAccess.py:1.1.2.2 Message-ID: <200204121510.g3CFAFo02596@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv2512 Modified Files: Tag: Zope3-Server-Branch TestFilesystemAccess.py Log Message: Removed two methods that I believe were added accidentally === Zope3/lib/python/Zope/Server/VFS/TestFilesystemAccess.py 1.1.2.1 => 1.1.2.2 === return self.fs - - def hasUser(self, username): - return self.passwords.has_key(username) - - - def getPassword(self, username): - return self.passwords.get(username, None) From matt@zope.com Fri Apr 12 16:18:45 2002 From: matt@zope.com (Matthew T. Kromer) Date: Fri, 12 Apr 2002 11:18:45 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/AccessControl - cAccessControl.c:1.13.2.2 Message-ID: <200204121518.g3CFIjV04953@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/AccessControl In directory cvs.zope.org:/tmp/cvs-serv4869 Modified Files: Tag: Zope-2_5-branch cAccessControl.c Log Message: Change cAccessControl's PermissionRole deallocator to handle the case where the object pointers aren't initialized (because the constructor was called with an invalid number of arguments) This just amounts to using the XDECREF macro rather than DECREF. === Zope/lib/python/AccessControl/cAccessControl.c 1.13.2.1 => 1.13.2.2 === static void PermissionRole_dealloc(PermissionRole *self) { - Py_DECREF(self->__name__); + Py_XDECREF(self->__name__); - Py_DECREF(self->_p); + Py_XDECREF(self->_p); - Py_DECREF(self->__roles__); + Py_XDECREF(self->__roles__); - Py_DECREF(self->ob_type); /* Extensionclass init incref'd */ + Py_XDECREF(self->ob_type); /* Extensionclass init incref'd */ PyMem_DEL(self); } From matt@zope.com Fri Apr 12 16:20:05 2002 From: matt@zope.com (Matthew T. Kromer) Date: Fri, 12 Apr 2002 11:20:05 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.406.2.43 Message-ID: <200204121520.g3CFK5905176@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv5128/doc Modified Files: Tag: Zope-2_5-branch CHANGES.txt Log Message: Updated doc === Zope/doc/CHANGES.txt 1.406.2.42 => 1.406.2.43 === - FTP: some passive FTP connections were blocking. Fixed. + - Fix potential segfault with cAccessControl's permission role + deallocator when the permisson role is constructed with a non-tuple + argument. + + Zope 2.5.0 Final Bugs Fixed From brian@zope.com Fri Apr 12 16:20:31 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 11:20:31 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/AccessControl/tests - testClassSecurityInfo.py:1.1.2.1 Message-ID: <200204121520.g3CFKVX05196@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/AccessControl/tests In directory cvs.zope.org:/tmp/cvs-serv5189 Added Files: Tag: Zope-2_5-branch testClassSecurityInfo.py Log Message: Added unit test for bug #275 === Added File Zope/lib/python/AccessControl/tests/testClassSecurityInfo.py === ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ """ import os, sys, unittest, ZODB, Globals from AccessControl.SecurityInfo import ClassSecurityInfo from OFS.Folder import Folder class ClassSecurityInfoTests(unittest.TestCase): def testSetPermissionDefault(self): """Test setting default roles for permissions.""" # Setup a test class with default role -> permission decls. class Test(Folder): """Test class""" __ac_roles__ = ('Role A', 'Role B', 'Role C') meta_type = "Test" security = ClassSecurityInfo() security.setPermissionDefault( 'Test permission', ('Manager', 'Role A', 'Role B', 'Role C') ) security.declareProtected('Test permission', 'foo') def foo(self, REQUEST=None): """ """ pass # Do class initialization. Globals.InitializeClass(Test) # Now check the resulting class to see if the mapping was made # correctly. Note that this uses carnal knowledge of the internal # structures used to store this information! object = Test() imPermissionRole = object.foo__roles__ self.failUnless(len(imPermissionRole) == 4) for item in ('Manager', 'Role A', 'Role B', 'Role C'): self.failUnless(item in imPermissionRole) def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(ClassSecurityInfoTests)) return suite def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': main() From brian@zope.com Fri Apr 12 16:20:45 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 11:20:45 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - class_init.py:1.12.16.1 Message-ID: <200204121520.g3CFKjm05217@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv5204 Modified Files: Tag: Zope-2_5-branch class_init.py Log Message: Fixed bug 275 === Zope/lib/python/App/class_init.py 1.12 => 1.12.16.1 === for acp in self.__ac_permissions__: pname, mnames = acp[:2] - pr=PermissionRole(pname) + if len(acp) > 2: + roles = acp[2] + pr = PermissionRole(pname, roles) + else: + pr=PermissionRole(pname) for mname in mnames: dict[mname+'__roles__']=pr From matt@zope.com Fri Apr 12 16:21:47 2002 From: matt@zope.com (Matthew T. Kromer) Date: Fri, 12 Apr 2002 11:21:47 -0400 Subject: [Zope-Checkins] CVS: Releases/Zope/lib/python/AccessControl - cAccessControl.c:1.16 Message-ID: <200204121521.g3CFLll06154@cvs.baymountain.com> Update of /cvs-repository/Releases/Zope/lib/python/AccessControl In directory cvs.zope.org:/tmp/cvs-serv6142 Modified Files: cAccessControl.c Log Message: Change cAccessControl's PermissionRole deallocator to handle the case where the object pointers aren't initialized (because the constructor was called with an invalid number of arguments) This just amounts to using the XDECREF macro rather than DECREF. === Releases/Zope/lib/python/AccessControl/cAccessControl.c 1.15 => 1.16 === static void PermissionRole_dealloc(PermissionRole *self) { - Py_DECREF(self->__name__); + Py_XDECREF(self->__name__); - Py_DECREF(self->_p); + Py_XDECREF(self->_p); - Py_DECREF(self->__roles__); + Py_XDECREF(self->__roles__); - Py_DECREF(self->ob_type); /* Extensionclass init incref'd */ + Py_XDECREF(self->ob_type); /* Extensionclass init incref'd */ PyMem_DEL(self); } From brian@zope.com Fri Apr 12 16:21:59 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 11:21:59 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.406.2.44 Message-ID: <200204121521.g3CFLx606168@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv6161 Modified Files: Tag: Zope-2_5-branch CHANGES.txt Log Message: Updated === Zope/doc/CHANGES.txt 1.406.2.43 => 1.406.2.44 === Bugs Fixed + - Fix for Collector # 275: setPermissionDefault was not being + propagated to actual security settings. + - Fixed bug where TTW code that called: del REQUEST.SESSION['key'] From brian@zope.com Fri Apr 12 16:22:43 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 11:22:43 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/AccessControl/tests - testClassSecurityInfo.py:1.2 Message-ID: <200204121522.g3CFMhJ06278@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/AccessControl/tests In directory cvs.zope.org:/tmp/cvs-serv6269 Added Files: testClassSecurityInfo.py Log Message: Added unit test === Zope/lib/python/AccessControl/tests/testClassSecurityInfo.py 1.1 => 1.2 === +# +# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE +# +############################################################################## +""" """ + +import os, sys, unittest, ZODB, Globals +from AccessControl.SecurityInfo import ClassSecurityInfo +from OFS.Folder import Folder + + +class ClassSecurityInfoTests(unittest.TestCase): + + + def testSetPermissionDefault(self): + """Test setting default roles for permissions.""" + + # Setup a test class with default role -> permission decls. + class Test(Folder): + """Test class""" + __ac_roles__ = ('Role A', 'Role B', 'Role C') + + meta_type = "Test" + + security = ClassSecurityInfo() + + security.setPermissionDefault( + 'Test permission', + ('Manager', 'Role A', 'Role B', 'Role C') + ) + + security.declareProtected('Test permission', 'foo') + def foo(self, REQUEST=None): + """ """ + pass + + # Do class initialization. + Globals.InitializeClass(Test) + + # Now check the resulting class to see if the mapping was made + # correctly. Note that this uses carnal knowledge of the internal + # structures used to store this information! + object = Test() + imPermissionRole = object.foo__roles__ + self.failUnless(len(imPermissionRole) == 4) + for item in ('Manager', 'Role A', 'Role B', 'Role C'): + self.failUnless(item in imPermissionRole) + + +def test_suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(ClassSecurityInfoTests)) + return suite + +def main(): + unittest.TextTestRunner().run(test_suite()) + +if __name__ == '__main__': + main() From matt@zope.com Fri Apr 12 16:22:53 2002 From: matt@zope.com (Matthew T. Kromer) Date: Fri, 12 Apr 2002 11:22:53 -0400 Subject: [Zope-Checkins] CVS: Releases/Zope/doc - CHANGES.txt:1.457 Message-ID: <200204121522.g3CFMrt06297@cvs.baymountain.com> Update of /cvs-repository/Releases/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv6290/doc Modified Files: CHANGES.txt Log Message: Updated changes === Releases/Zope/doc/CHANGES.txt 1.456 => 1.457 === with overlong usernames. + - Fixed a potential bug with cAccessControl's permission + role deallocator which would try to decref things which + may not have been set, due to a change in the initializer + (which will bail out if it doesnt get called with a tuple + argument) Zope 2.5.1 beta 1 From brian@zope.com Fri Apr 12 16:23:56 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 11:23:56 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - class_init.py:1.13 Message-ID: <200204121523.g3CFNux06442@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv6435 Modified Files: class_init.py Log Message: Fix for collector #275 === Zope/lib/python/App/class_init.py 1.12 => 1.13 === for acp in self.__ac_permissions__: pname, mnames = acp[:2] - pr=PermissionRole(pname) + if len(acp) > 2: + roles = acp[2] + pr = PermissionRole(pname, roles) + else: + pr=PermissionRole(pname) for mname in mnames: dict[mname+'__roles__']=pr From brian@zope.com Fri Apr 12 16:26:14 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 11:26:14 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.458 Message-ID: <200204121526.g3CFQEr07080@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv7073 Modified Files: CHANGES.txt Log Message: Updated === Zope/doc/CHANGES.txt 1.457 => 1.458 === Bugs: + - Fixed bug #275: setPermissionDefault didn't actually set the + right permission -> role mappings. + - Fixed bug reported on maillist during EWOULDBLOCK when using FTP server (http:// lists.zope.org/pipermail/zope/2002-March/111521.html). From brian@zope.com Fri Apr 12 16:27:21 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 11:27:21 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - class_init.py:1.11.4.1 Message-ID: <200204121527.g3CFRLE07620@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv7613 Modified Files: Tag: Zope-2_4-branch class_init.py Log Message: Fixed bug #275 === Zope/lib/python/App/class_init.py 1.11 => 1.11.4.1 === for acp in self.__ac_permissions__: pname, mnames = acp[:2] - pr=PermissionRole(pname) + if len(acp) > 2: + roles = acp[2] + pr = PermissionRole(pname, roles) + else: + pr=PermissionRole(pname) for mname in mnames: dict[mname+'__roles__']=pr + + From brian@zope.com Fri Apr 12 16:28:54 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 11:28:54 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.335.2.110 Message-ID: <200204121528.g3CFSs507772@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv7762 Modified Files: Tag: Zope-2_4-branch CHANGES.txt Log Message: Updated === Zope/doc/CHANGES.txt 1.335.2.109 => 1.335.2.110 === Bugs Fixed + - Collector #275: ClassSecurityInfo.setPermissionDefault + broken + - Collector #236: recursive ownership changes could be short-circuited prematurely if a user already owned a subobject. From casey@zope.com Fri Apr 12 16:37:14 2002 From: casey@zope.com (Casey Duncan) Date: Fri, 12 Apr 2002 11:37:14 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/PythonScripts - PythonScript.py:1.42 Message-ID: <200204121537.g3CFbEK10231@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/PythonScripts In directory cvs.zope.org:/tmp/cvs-serv9270/lib/python/Products/PythonScripts Modified Files: PythonScript.py Log Message: FileUpload objects now eval false if filename is empty. Upload buttons on DTML, Py Scripts, Files, Images and PTs raise an error if the file is not specified instead of clearing the source (Bug #144) === Zope/lib/python/Products/PythonScripts/PythonScript.py 1.41 => 1.42 === if self.wl_isLocked(): raise ResourceLockedError, "The script is locked via WebDAV." - if type(file) is not type(''): file = file.read() + + if type(file) is not type(''): + if not file: raise ValueError, 'File not specified' + file = file.read() + self.write(file) message = 'Saved changes.' return self.ZPythonScriptHTML_editForm(self, REQUEST, From casey@zope.com Fri Apr 12 16:37:14 2002 From: casey@zope.com (Casey Duncan) Date: Fri, 12 Apr 2002 11:37:14 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/ZPublisher - HTTPRequest.py:1.66 Message-ID: <200204121537.g3CFbEF10233@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/ZPublisher In directory cvs.zope.org:/tmp/cvs-serv9270/lib/python/ZPublisher Modified Files: HTTPRequest.py Log Message: FileUpload objects now eval false if filename is empty. Upload buttons on DTML, Py Scripts, Files, Images and PTs raise an error if the file is not specified instead of clearing the source (Bug #144) === Zope/lib/python/ZPublisher/HTTPRequest.py 1.65 => 1.66 === try: self.headers.__allow_access_to_unprotected_subobjects__ = 1 except: pass + + def __nonzero__(self): + """FileUpload objects are considered false if their + filename is empty. + """ + return not not self.filename parse_cookie_lock=allocate_lock() From casey@zope.com Fri Apr 12 16:37:43 2002 From: casey@zope.com (Casey Duncan) Date: Fri, 12 Apr 2002 11:37:43 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.459 Message-ID: <200204121537.g3CFbhG10243@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv9270/doc Modified Files: CHANGES.txt Log Message: FileUpload objects now eval false if filename is empty. Upload buttons on DTML, Py Scripts, Files, Images and PTs raise an error if the file is not specified instead of clearing the source (Bug #144) === Zope/doc/CHANGES.txt 1.458 => 1.459 === new Features: + - FileUpload objects now evaluate false when the have an empty file + name. Making it easier to check for omitted file upload form fields. + - ZClasses now use a python script as their constructor method instead of a DTML method. Also, ZClasses inherit from CatalogPathAwareness now instead of CatalogAwareness. @@ -72,6 +75,10 @@ Bugs: + - Fixed bug #144: Upload button on dtml, py scripts, images, files and + pts now raises an error if the file is not specified rather than + clearing the source. + - Fixed bug #275: setPermissionDefault didn't actually set the right permission -> role mappings. From casey@zope.com Fri Apr 12 16:37:44 2002 From: casey@zope.com (Casey Duncan) Date: Fri, 12 Apr 2002 11:37:44 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - DTMLDocument.py:1.47 DTMLMethod.py:1.75 Image.py:1.137 Message-ID: <200204121537.g3CFbim10248@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv9270/lib/python/OFS Modified Files: DTMLDocument.py DTMLMethod.py Image.py Log Message: FileUpload objects now eval false if filename is empty. Upload buttons on DTML, Py Scripts, Files, Images and PTs raise an error if the file is not specified instead of clearing the source (Bug #144) === Zope/lib/python/OFS/DTMLDocument.py 1.46 => 1.47 === raise ResourceLockedError, ( 'This document has been locked via WebDAV.') - if type(file) is not type(''): file=file.read() + + if type(file) is not type(''): + if REQUEST and not file: + raise ValueError, 'No file specified' + file=file.read() + self.munge(file) self.ZCacheable_invalidate() if REQUEST: === Zope/lib/python/OFS/DTMLMethod.py 1.74 => 1.75 === raise ResourceLockedError, 'This DTML Method is locked via WebDAV' - if type(file) is not type(''): file=file.read() + if type(file) is not type(''): + if REQUEST and not file: + raise ValueError, 'No file specified' + file=file.read() + self.munge(file) self.ZCacheable_invalidate() if REQUEST: === Zope/lib/python/OFS/Image.py 1.136 => 1.137 === from mimetools import choose_boundary from ZPublisher import HTTPRangeSupport +from ZPublisher.HTTPRequest import FileUpload StringType=type('') manage_addFileForm=DTMLFile('dtml/imageAdd', globals(),Kind='File',kind='file') @@ -437,6 +438,8 @@ size=len(file) if size < n: return file, size return Pdata(file), size + elif isinstance(file, FileUpload) and not file: + raise ValueError, 'File not specified' if hasattr(file, '__class__') and file.__class__ is Pdata: size=len(file) From casey@zope.com Fri Apr 12 16:37:44 2002 From: casey@zope.com (Casey Duncan) Date: Fri, 12 Apr 2002 11:37:44 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/PageTemplates - ZopePageTemplate.py:1.33 Message-ID: <200204121537.g3CFbiT10251@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/PageTemplates In directory cvs.zope.org:/tmp/cvs-serv9270/lib/python/Products/PageTemplates Modified Files: ZopePageTemplate.py Log Message: FileUpload objects now eval false if filename is empty. Upload buttons on DTML, Py Scripts, Files, Images and PTs raise an error if the file is not specified instead of clearing the source (Bug #144) === Zope/lib/python/Products/PageTemplates/ZopePageTemplate.py 1.32 => 1.33 === if SUPPORTS_WEBDAV_LOCKS and self.wl_isLocked(): raise ResourceLockedError, "File is locked via WebDAV" - if type(file) is not type(''): file = file.read() + + if type(file) is not type(''): + if not file: raise ValueError, 'File not specified' + file = file.read() + self.write(file) message = 'Saved changes.' return self.pt_editForm(manage_tabs_message=message) From brian@zope.com Fri Apr 12 16:38:16 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 11:38:16 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/AccessControl - SecurityInfo.py:1.12.2.1 Message-ID: <200204121538.g3CFcGR10344@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/AccessControl In directory cvs.zope.org:/tmp/cvs-serv10283 Modified Files: Tag: Zope-2_5-branch SecurityInfo.py Log Message: Fixed an obscure bug found during 275 investigation. === Zope/lib/python/AccessControl/SecurityInfo.py 1.12 => 1.12.2.1 === self._setaccess(item[1], permission_name) if len(item) > 2: - self.setDefaultRoles(permission_name, item[2]) + self.setPermissionDefault(permission_name, item[2]) # Set __roles__ for attributes declared public or private. # Collect protected attribute names in ac_permissions. From brian@zope.com Fri Apr 12 16:38:50 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 11:38:50 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/AccessControl - SecurityInfo.py:1.13 Message-ID: <200204121538.g3CFco910394@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/AccessControl In directory cvs.zope.org:/tmp/cvs-serv10356 Modified Files: SecurityInfo.py Log Message: Fixed obscure bug found in 275 investigation. === Zope/lib/python/AccessControl/SecurityInfo.py 1.12 => 1.13 === self._setaccess(item[1], permission_name) if len(item) > 2: - self.setDefaultRoles(permission_name, item[2]) + self.setPermissionDefault(permission_name, item[2]) # Set __roles__ for attributes declared public or private. # Collect protected attribute names in ac_permissions. From brian@zope.com Fri Apr 12 16:39:53 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 11:39:53 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/AccessControl - SecurityInfo.py:1.9.32.1 Message-ID: <200204121539.g3CFdr310509@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/AccessControl In directory cvs.zope.org:/tmp/cvs-serv10490 Modified Files: Tag: Zope-2_4-branch SecurityInfo.py Log Message: Fixed obscure bug found during 275 investigation === Zope/lib/python/AccessControl/SecurityInfo.py 1.9 => 1.9.32.1 === self._setaccess(item[1], permission_name) if len(item) > 2: - self.setDefaultRoles(permission_name, item[2]) + self.setPermissionDefault(permission_name, item[2]) # Set __roles__ for attributes declared public or private. # Collect protected attribute names in ac_permissions. From tseaver@zope.com Fri Apr 12 16:47:27 2002 From: tseaver@zope.com (Tres Seaver) Date: Fri, 12 Apr 2002 11:47:27 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/ZPublisher - HTTPRequest.py:1.67 Message-ID: <200204121547.g3CFlR212868@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/ZPublisher In directory cvs.zope.org:/tmp/cvs-serv12776/lib/python/ZPublisher Modified Files: HTTPRequest.py Log Message: - Resolve Collector #89 by making repr of record eval'able as a dict. === Zope/lib/python/ZPublisher/HTTPRequest.py 1.66 => 1.67 === def __repr__(self): + #return repr( self.__dict__ ) L1 = self.__dict__.items() L1.sort() - return ', '.join( - map(lambda item: "%s: %s" % (item[0], repr(item[1])), L1)) + return '{%s}' % ', '.join( + map(lambda item: "'%s': %s" % (item[0], repr(item[1])), L1)) # Flags SEQUENCE=1 From tseaver@zope.com Fri Apr 12 16:47:27 2002 From: tseaver@zope.com (Tres Seaver) Date: Fri, 12 Apr 2002 11:47:27 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/ZPublisher/tests - testHTTPRequest.py:1.1 Message-ID: <200204121547.g3CFlRA12870@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/ZPublisher/tests In directory cvs.zope.org:/tmp/cvs-serv12776/lib/python/ZPublisher/tests Added Files: testHTTPRequest.py Log Message: - Resolve Collector #89 by making repr of record eval'able as a dict. === Added File Zope/lib/python/ZPublisher/tests/testHTTPRequest.py === import unittest class RecordTests( unittest.TestCase ): def test_repr( self ): from ZPublisher.HTTPRequest import record record = record() record.a = 1 record.b = 'foo' r = repr( record ) d = eval( r ) self.assertEqual( d, record.__dict__ ) def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(RecordTests, 'test')) return suite if __name__ == '__main__': unittest.main() From tseaver@zope.com Fri Apr 12 16:47:57 2002 From: tseaver@zope.com (Tres Seaver) Date: Fri, 12 Apr 2002 11:47:57 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.460 Message-ID: <200204121547.g3CFlvm12886@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv12776/doc Modified Files: CHANGES.txt Log Message: - Resolve Collector #89 by making repr of record eval'able as a dict. === Zope/doc/CHANGES.txt 1.459 => 1.460 === Bugs: + - Made repr of an HTTPRequest.record eval'able as a dict (Collector + #89). + - Fixed bug #144: Upload button on dtml, py scripts, images, files and pts now raises an error if the file is not specified rather than clearing the source. From brian@zope.com Fri Apr 12 16:53:37 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 11:53:37 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - UNITTEST.txt:1.3 Message-ID: <200204121553.g3CFrbr14224@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv14217 Modified Files: UNITTEST.txt Log Message: Added a pointer to the Testing package. === Zope/doc/UNITTEST.txt 1.2 => 1.3 === higher-quality code. - - + There is a testing support package in lib/python/Testing that might + be useful to you for writing unit tests. See the README.txt in that + directory for details. From brian@zope.com Fri Apr 12 16:55:39 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 11:55:39 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - UNITTEST.txt:1.2.108.1 Message-ID: <200204121555.g3CFtdi14443@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv14435 Modified Files: Tag: Zope-2_4-branch UNITTEST.txt Log Message: Added a pointer to the Testing package. === Zope/doc/UNITTEST.txt 1.2 => 1.2.108.1 === higher-quality code. + There is a testing support package in lib/python/Testing that might + be useful to you for writing unit tests. See the README.txt in that + directory for details. From brian@zope.com Fri Apr 12 16:55:00 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 11:55:00 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - UNITTEST.txt:1.2.180.1 Message-ID: <200204121555.g3CFt0m14352@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv14343 Modified Files: Tag: Zope-2_5-branch UNITTEST.txt Log Message: Added pointer to the Testing package === Zope/doc/UNITTEST.txt 1.2 => 1.2.180.1 === higher-quality code. + There is a testing support package in lib/python/Testing that might + be useful to you for writing unit tests. See the README.txt in that + directory for details. From brian@zope.com Fri Apr 12 17:04:25 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 12:04:25 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - Application.py:1.179.4.1 Message-ID: <200204121604.g3CG4P516908@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv16890 Modified Files: Tag: Zope-2_5-branch Application.py Log Message: Fix theoretical bug 213. === Zope/lib/python/OFS/Application.py 1.179 => 1.179.4.1 === # Initialize the application - # Initialize the cache: - app.Control_Panel.initialize_cache() - # The following items marked b/c are backward compatibility hacks # which make sure that expected system objects are added to the # bobobase. This is required because the bobobase in use may pre- @@ -257,6 +254,9 @@ app._setObject('Control_Panel', cpl) get_transaction().note('Added Control_Panel') get_transaction().commit() + + # Initialize the cache: + app.Control_Panel.initialize_cache() # b/c: Ensure that a ProductFolder exists. if not hasattr(app.Control_Panel.aq_base, 'Products'): From matt@zigg.com Fri Apr 12 17:04:49 2002 From: matt@zigg.com (Matt Behrens) Date: Fri, 12 Apr 2002 12:04:49 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.461 Message-ID: <200204121604.g3CG4n716935@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv16915/doc Modified Files: CHANGES.txt Log Message: #185 plus fix ajung's fix for #341: repair Z2.log for [FP]CGIServer, and give them extended log format like HTTPServer === Zope/doc/CHANGES.txt 1.460 => 1.461 === argument) + - Collector #185, 341: PCGIServer and FCGIServer logs corrected + and now output extended information like HTTPServer does. + Zope 2.5.1 beta 1 Bugs Fixed From matt@zigg.com Fri Apr 12 17:04:49 2002 From: matt@zigg.com (Matt Behrens) Date: Fri, 12 Apr 2002 12:04:49 -0400 Subject: [Zope-Checkins] CVS: Zope/ZServer - FCGIServer.py:1.16 PCGIServer.py:1.22 Message-ID: <200204121604.g3CG4na16938@cvs.baymountain.com> Update of /cvs-repository/Zope/ZServer In directory cvs.zope.org:/tmp/cvs-serv16915/ZServer Modified Files: FCGIServer.py PCGIServer.py Log Message: #185 plus fix ajung's fix for #341: repair Z2.log for [FP]CGIServer, and give them extended log format like HTTPServer === Zope/ZServer/FCGIServer.py 1.15 => 1.16 === DebugLogger.log('E', id(self)) - user_agent=self.get_header('user-agent') - if not user_agent: user_agent='' - referer=self.get_header('referer') - if not referer: referer='' + if self.env.has_key('HTTP_USER_AGENT'): + user_agent=self.env['HTTP_USER_AGENT'] + else: + user_agent='' + if self.env.has_key('HTTP_REFERER'): + referer=self.env['HTTP_REFERER'] + else: + referer='' if self.env.has_key('PATH_INFO'): path=self.env['PATH_INFO'] @@ -453,7 +457,7 @@ if self.addr: self.server.logger.log ( self.addr[0], - '%s - - [%s] "%s %s" %d %d' % ( + '%s - - [%s] "%s %s" %d %d "%s" "%s"' % ( self.addr[1], time.strftime ( '%d/%b/%Y:%H:%M:%S ', @@ -466,7 +470,7 @@ else: self.server.logger.log ( '127.0.0.1 ', - '- - [%s] "%s %s" %d %d' % ( + '- - [%s] "%s %s" %d %d "%s" "%s"' % ( time.strftime ( '%d/%b/%Y:%H:%M:%S ', time.localtime(time.time()) === Zope/ZServer/PCGIServer.py 1.21 => 1.22 === def log_request(self, bytes): + if self.env.has_key('HTTP_USER_AGENT'): + user_agent=self.env['HTTP_USER_AGENT'] + else: + user_agent='' + if self.env.has_key('HTTP_REFERER'): + referer=self.env['HTTP_REFERER'] + else: + referer='' + if self.env.has_key('PATH_INFO'): path=self.env['PATH_INFO'] else: @@ -153,24 +162,26 @@ if addr and type(addr) is TupleType: self.server.logger.log ( addr[0], - '%d - - [%s] "%s %s" %d %d' % ( + '%d - - [%s] "%s %s" %d %d "%s" "%s"' % ( addr[1], time.strftime ( '%d/%b/%Y:%H:%M:%S ', - time.gmtime(time.time()) + time.localtime(time.time()) ) + tz_for_log, - method, path, self.reply_code, bytes + method, path, self.reply_code, bytes, + referer, user_agent ) ) else: self.server.logger.log ( '127.0.0.1', - '- - [%s] "%s %s" %d %d' % ( + ' - - [%s] "%s %s" %d %d "%s" "%s"' % ( time.strftime ( '%d/%b/%Y:%H:%M:%S ', time.gmtime(time.time()) ) + tz_for_log, - method, path, self.reply_code, bytes + method, path, self.reply_code, bytes, + referer, user_agent ) ) From brian@zope.com Fri Apr 12 17:06:02 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 12:06:02 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - Application.py:1.183 Message-ID: <200204121606.g3CG62417123@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv17044 Modified Files: Application.py Log Message: fix theoretical bug 213. === Zope/lib/python/OFS/Application.py 1.182 => 1.183 === # Initialize the application - # Initialize the cache: - app.Control_Panel.initialize_cache() - # The following items marked b/c are backward compatibility hacks # which make sure that expected system objects are added to the # bobobase. This is required because the bobobase in use may pre- @@ -259,6 +256,9 @@ app._setObject('Control_Panel', cpl) get_transaction().note('Added Control_Panel') get_transaction().commit() + + # Initialize the cache: + app.Control_Panel.initialize_cache() # b/c: Ensure that a ProductFolder exists. if not hasattr(app.Control_Panel.aq_base, 'Products'): From tseaver@zope.com Fri Apr 12 17:07:46 2002 From: tseaver@zope.com (Tres Seaver) Date: Fri, 12 Apr 2002 12:07:46 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/ZPublisher/tests - testHTTPRequest.py:1.1.2.1 Message-ID: <200204121607.g3CG7kR18057@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/ZPublisher/tests In directory cvs.zope.org:/tmp/cvs-serv18043/lib/python/ZPublisher/tests Added Files: Tag: Zope-2_5-branch testHTTPRequest.py Log Message: - Backport fix for Collector #89. === Added File Zope/lib/python/ZPublisher/tests/testHTTPRequest.py === import unittest class RecordTests( unittest.TestCase ): def test_repr( self ): from ZPublisher.HTTPRequest import record record = record() record.a = 1 record.b = 'foo' r = repr( record ) d = eval( r ) self.assertEqual( d, record.__dict__ ) def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(RecordTests, 'test')) return suite if __name__ == '__main__': unittest.main() From tseaver@zope.com Fri Apr 12 17:08:16 2002 From: tseaver@zope.com (Tres Seaver) Date: Fri, 12 Apr 2002 12:08:16 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/ZPublisher - HTTPRequest.py:1.61.6.2 Message-ID: <200204121608.g3CG8Gx18148@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/ZPublisher In directory cvs.zope.org:/tmp/cvs-serv18043/lib/python/ZPublisher Modified Files: Tag: Zope-2_5-branch HTTPRequest.py Log Message: - Backport fix for Collector #89. === Zope/lib/python/ZPublisher/HTTPRequest.py 1.61.6.1 => 1.61.6.2 === def __repr__(self): + #return repr( self.__dict__ ) L1 = self.__dict__.items() L1.sort() - return ', '.join( - map(lambda item: "%s: %s" % (item[0], repr(item[1])), L1)) + return '{%s}' % ', '.join( + map(lambda item: "'%s': %s" % (item[0], repr(item[1])), L1)) # Flags SEQUENCE=1 From matt@zigg.com Fri Apr 12 17:23:07 2002 From: matt@zigg.com (Matt Behrens) Date: Fri, 12 Apr 2002 12:23:07 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.406.2.45 Message-ID: <200204121623.g3CGN7g22037@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv21947/doc Modified Files: Tag: Zope-2_5-branch CHANGES.txt Log Message: #185, #341 === Zope/doc/CHANGES.txt 1.406.2.44 => 1.406.2.45 === argument. + - Collector #185, 341: PCGIServer and FCGIServer logs corrected + and now output extended information like HTTPServer does. Zope 2.5.0 Final From matt@zigg.com Fri Apr 12 17:23:08 2002 From: matt@zigg.com (Matt Behrens) Date: Fri, 12 Apr 2002 12:23:08 -0400 Subject: [Zope-Checkins] CVS: Zope/ZServer - FCGIServer.py:1.13.16.1 PCGIServer.py:1.21.16.1 Message-ID: <200204121623.g3CGN8Q22040@cvs.baymountain.com> Update of /cvs-repository/Zope/ZServer In directory cvs.zope.org:/tmp/cvs-serv21947/ZServer Modified Files: Tag: Zope-2_5-branch FCGIServer.py PCGIServer.py Log Message: #185, #341 === Zope/ZServer/FCGIServer.py 1.13 => 1.13.16.1 === DebugLogger.log('E', id(self)) - + + if self.env.has_key('HTTP_USER_AGENT'): + user_agent=self.env['HTTP_USER_AGENT'] + else: + user_agent='' + if self.env.has_key('HTTP_REFERER'): + referer=self.env['HTTP_REFERER'] + else: + referer='' + if self.env.has_key('PATH_INFO'): path=self.env['PATH_INFO'] else: @@ -448,24 +457,26 @@ if self.addr: self.server.logger.log ( self.addr[0], - '%s - - [%s] "%s %s" %d %d' % ( + '%s - - [%s] "%s %s" %d %d "%s" "%s"' % ( self.addr[1], time.strftime ( '%d/%b/%Y:%H:%M:%S ', - time.gmtime(time.time()) + time.localtime(time.time()) ) + tz_for_log, - method, path, self.reply_code, bytes + method, path, self.reply_code, bytes, + referer, user_agent ) ) else: self.server.logger.log ( - '127.0.0.1', - '- - [%s] "%s %s" %d %d' % ( + '127.0.0.1 ', + '- - [%s] "%s %s" %d %d "%s" "%s"' % ( time.strftime ( '%d/%b/%Y:%H:%M:%S ', - time.gmtime(time.time()) + time.localtime(time.time()) ) + tz_for_log, - method, path, self.reply_code, bytes + method, path, self.reply_code, bytes, + referer, user_agent ) ) === Zope/ZServer/PCGIServer.py 1.21 => 1.21.16.1 === def log_request(self, bytes): + if self.env.has_key('HTTP_USER_AGENT'): + user_agent=self.env['HTTP_USER_AGENT'] + else: + user_agent='' + if self.env.has_key('HTTP_REFERER'): + referer=self.env['HTTP_REFERER'] + else: + referer='' + if self.env.has_key('PATH_INFO'): path=self.env['PATH_INFO'] else: @@ -153,24 +162,26 @@ if addr and type(addr) is TupleType: self.server.logger.log ( addr[0], - '%d - - [%s] "%s %s" %d %d' % ( + '%d - - [%s] "%s %s" %d %d "%s" "%s"' % ( addr[1], time.strftime ( '%d/%b/%Y:%H:%M:%S ', - time.gmtime(time.time()) + time.localtime(time.time()) ) + tz_for_log, - method, path, self.reply_code, bytes + method, path, self.reply_code, bytes, + referer, user_agent ) ) else: self.server.logger.log ( '127.0.0.1', - '- - [%s] "%s %s" %d %d' % ( + ' - - [%s] "%s %s" %d %d "%s" "%s"' % ( time.strftime ( '%d/%b/%Y:%H:%M:%S ', time.gmtime(time.time()) ) + tz_for_log, - method, path, self.reply_code, bytes + method, path, self.reply_code, bytes, + referer, user_agent ) ) From matt@zigg.com Fri Apr 12 17:24:58 2002 From: matt@zigg.com (Matt Behrens) Date: Fri, 12 Apr 2002 12:24:58 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.335.2.111 Message-ID: <200204121624.g3CGOws22172@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv22161/doc Modified Files: Tag: Zope-2_4-branch CHANGES.txt Log Message: #185, #341 === Zope/doc/CHANGES.txt 1.335.2.110 => 1.335.2.111 === underscores + - Collector #185, 341: PCGIServer and FCGIServer logs corrected + and now output extended information like HTTPServer does. + Zope 2.4.4 beta 1 Bugs Fixed From matt@zigg.com Fri Apr 12 17:24:58 2002 From: matt@zigg.com (Matt Behrens) Date: Fri, 12 Apr 2002 12:24:58 -0400 Subject: [Zope-Checkins] CVS: Zope/ZServer - FCGIServer.py:1.12.32.1 PCGIServer.py:1.20.32.1 Message-ID: <200204121624.g3CGOwI22175@cvs.baymountain.com> Update of /cvs-repository/Zope/ZServer In directory cvs.zope.org:/tmp/cvs-serv22161/ZServer Modified Files: Tag: Zope-2_4-branch FCGIServer.py PCGIServer.py Log Message: #185, #341 === Zope/ZServer/FCGIServer.py 1.12 => 1.12.32.1 === DebugLogger.log('E', id(self)) - + + if self.env.has_key('HTTP_USER_AGENT'): + user_agent=self.env['HTTP_USER_AGENT'] + else: + user_agent='' + if self.env.has_key('HTTP_REFERER'): + referer=self.env['HTTP_REFERER'] + else: + referer='' + if self.env.has_key('PATH_INFO'): path=self.env['PATH_INFO'] else: @@ -520,24 +529,26 @@ if self.addr: self.server.logger.log ( self.addr[0], - '%s - - [%s] "%s %s" %d %d' % ( + '%s - - [%s] "%s %s" %d %d "%s" "%s"' % ( self.addr[1], time.strftime ( '%d/%b/%Y:%H:%M:%S ', - time.gmtime(time.time()) + time.localtime(time.time()) ) + tz_for_log, - method, path, self.reply_code, bytes + method, path, self.reply_code, bytes, + referer, user_agent ) ) else: self.server.logger.log ( - '127.0.0.1', - '- - [%s] "%s %s" %d %d' % ( + '127.0.0.1 ', + '- - [%s] "%s %s" %d %d "%s" "%s"' % ( time.strftime ( '%d/%b/%Y:%H:%M:%S ', - time.gmtime(time.time()) + time.localtime(time.time()) ) + tz_for_log, - method, path, self.reply_code, bytes + method, path, self.reply_code, bytes, + referer, user_agent ) ) === Zope/ZServer/PCGIServer.py 1.20 => 1.20.32.1 === def log_request(self, bytes): + if self.env.has_key('HTTP_USER_AGENT'): + user_agent=self.env['HTTP_USER_AGENT'] + else: + user_agent='' + if self.env.has_key('HTTP_REFERER'): + referer=self.env['HTTP_REFERER'] + else: + referer='' + if self.env.has_key('PATH_INFO'): path=self.env['PATH_INFO'] else: @@ -225,24 +234,26 @@ if addr and type(addr) is TupleType: self.server.logger.log ( addr[0], - '%d - - [%s] "%s %s" %d %d' % ( + '%d - - [%s] "%s %s" %d %d "%s" "%s"' % ( addr[1], time.strftime ( '%d/%b/%Y:%H:%M:%S ', - time.gmtime(time.time()) + time.localtime(time.time()) ) + tz_for_log, - method, path, self.reply_code, bytes + method, path, self.reply_code, bytes, + referer, user_agent ) ) else: self.server.logger.log ( '127.0.0.1', - '- - [%s] "%s %s" %d %d' % ( + ' - - [%s] "%s %s" %d %d "%s" "%s"' % ( time.strftime ( '%d/%b/%Y:%H:%M:%S ', time.gmtime(time.time()) ) + tz_for_log, - method, path, self.reply_code, bytes + method, path, self.reply_code, bytes, + referer, user_agent ) ) From andreas@digicool.com Fri Apr 12 17:36:30 2002 From: andreas@digicool.com (Andreas Jung) Date: Fri, 12 Apr 2002 12:36:30 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - PropertySheets.py:1.84 Message-ID: <200204121636.g3CGaUm25638@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv25624/lib/python/OFS Modified Files: PropertySheets.py Log Message: - Propertysheets: Ids like 'values','keys' and 'values' are now forbidden as they break WebDAV functionality. Existing Propertysheets are not affected === Zope/lib/python/OFS/PropertySheets.py 1.83 => 1.84 === ) + __reserved_ids= ('values','items') + def property_extensible_schema__(self): """Return a flag indicating whether new properties may be added or removed.""" @@ -115,6 +117,11 @@ # Create a new property set, using the given id and namespace # string. The namespace string should be usable as an xml name- # space identifier. + + if id in self.__reserved_ids: + raise ValueError, "'%s' is a reserved Id (forbidden Ids are: %s) " % \ + (id, self.__reserved_ids) + self.id=id self._md=md or {} From andreas@digicool.com Fri Apr 12 17:36:30 2002 From: andreas@digicool.com (Andreas Jung) Date: Fri, 12 Apr 2002 12:36:30 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.462 Message-ID: <200204121636.g3CGaUt25637@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv25624/doc Modified Files: CHANGES.txt Log Message: - Propertysheets: Ids like 'values','keys' and 'values' are now forbidden as they break WebDAV functionality. Existing Propertysheets are not affected === Zope/doc/CHANGES.txt 1.461 => 1.462 === - Fixed a potential bug with cAccessControl's permission role deallocator which would try to decref things which - may not have been set, due to a change in the initializer - (which will bail out if it doesnt get called with a tuple - argument) + may not have been set, due to a change in the initializer + (which will bail out if it doesnt get called with a tuple + argument) - Collector #185, 341: PCGIServer and FCGIServer logs corrected and now output extended information like HTTPServer does. + + - Propertysheets: Ids like 'values','keys' and 'values' are + now forbidden as they break WebDAV functionality. Existing + Propertysheets are not affected + Zope 2.5.1 beta 1 From andreas@digicool.com Fri Apr 12 17:42:05 2002 From: andreas@digicool.com (Andreas Jung) Date: Fri, 12 Apr 2002 12:42:05 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - PropertySheets.py:1.81.4.1 Message-ID: <200204121642.g3CGg5X27071@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv26984/lib/python/OFS Modified Files: Tag: Zope-2_5-branch PropertySheets.py Log Message: - Propertysheets: Ids like 'values','keys' and 'values' are now forbidden as they break WebDAV functionality. Existing Propertysheets are not affected === Zope/lib/python/OFS/PropertySheets.py 1.81 => 1.81.4.1 === ) + __reserved_ids= ('values','items') + def property_extensible_schema__(self): """Return a flag indicating whether new properties may be added or removed.""" @@ -116,6 +118,11 @@ # Create a new property set, using the given id and namespace # string. The namespace string should be usable as an xml name- # space identifier. + + if id in self.__reserved_ids: + raise ValueError, "'%s' is a reserved Id (forbidden Ids are: %s)" % \ + (id, self.__reserved_ids) + self.id=id self._md=md or {} From andreas@digicool.com Fri Apr 12 17:42:05 2002 From: andreas@digicool.com (Andreas Jung) Date: Fri, 12 Apr 2002 12:42:05 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.406.2.46 Message-ID: <200204121642.g3CGg5i27069@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv26984/doc Modified Files: Tag: Zope-2_5-branch CHANGES.txt Log Message: - Propertysheets: Ids like 'values','keys' and 'values' are now forbidden as they break WebDAV functionality. Existing Propertysheets are not affected === Zope/doc/CHANGES.txt 1.406.2.45 => 1.406.2.46 === with overlong usernames. + - Propertysheets: Ids like 'values','keys' and 'values' are + now forbidden as they break WebDAV functionality. Existing + Propertysheets are not affected + - FTP: some passive FTP connections were blocking. Fixed. - Fix potential segfault with cAccessControl's permission role deallocator when the permisson role is constructed with a non-tuple - argument. + argument. - Collector #185, 341: PCGIServer and FCGIServer logs corrected and now output extended information like HTTPServer does. + Zope 2.5.0 Final From matt@zope.com Fri Apr 12 17:42:35 2002 From: matt@zope.com (Matthew T. Kromer) Date: Fri, 12 Apr 2002 12:42:35 -0400 Subject: [Zope-Checkins] CVS: Products/DCOracle2/src - dco2.c:1.106 Message-ID: <200204121642.g3CGgZs27101@cvs.baymountain.com> Update of /cvs-repository/Products/DCOracle2/src In directory cvs.zope.org:/tmp/cvs-serv27082/src Modified Files: dco2.c Log Message: Make isdst flag in mktime for date creation -1 as default (unknown DST) === Products/DCOracle2/src/dco2.c 1.105 => 1.106 === dateobject->tm.tm_wday = 0; dateobject->tm.tm_yday = 0; - dateobject->tm.tm_isdst = 0; + dateobject->tm.tm_isdst = -1; /* DST unknown */ #ifdef linux dateobject->tm.tm_gmtoff= 0; dateobject->tm.tm_zone = 0; From matt@zope.com Fri Apr 12 17:43:13 2002 From: matt@zope.com (Matthew T. Kromer) Date: Fri, 12 Apr 2002 12:43:13 -0400 Subject: [Zope-Checkins] CVS: Products/DCOracle2 - CHANGELOG:1.48 Message-ID: <200204121643.g3CGhD427190@cvs.baymountain.com> Update of /cvs-repository/Products/DCOracle2 In directory cvs.zope.org:/tmp/cvs-serv27183 Modified Files: CHANGELOG Log Message: Updated doc for isdst change === Products/DCOracle2/CHANGELOG 1.47 => 1.48 === output o Made SYNONYMs work with stored procedures for Mike Hewiett + o Made isdst flag for creation of OracleDates default to + unknown, rather than no DST Desired Features Not Yet Implemented: From andreas@digicool.com Fri Apr 12 18:22:45 2002 From: andreas@digicool.com (Andreas Jung) Date: Fri, 12 Apr 2002 13:22:45 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.463 ENVIRONMENT.txt:1.12 Message-ID: <200204121722.g3CHMjj04439@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv4425/doc Modified Files: CHANGES.txt ENVIRONMENT.txt Log Message: - new env. variable LOG_ZPUBLISHER_TRACEBACK (see doc/ENVIRONMENT.txt) === Zope/doc/CHANGES.txt 1.462 => 1.463 === - New implementation of ZODB object cache. + - new env. variable LOG_ZPUBLISHER_TRACEBACK + (see doc/ENVIRONMENT.txt) + Bugs: - Made repr of an HTTPRequest.record eval'able as a dict (Collector === Zope/doc/ENVIRONMENT.txt 1.11 => 1.12 === + LOG_ZPUBLISHER_TRACEBACK + + If set, Zope will log all ZPublisher traceback through + the stupid logger. (Default: unset) + + Misc. Z_REALM "your realm" From andreas@digicool.com Fri Apr 12 18:22:45 2002 From: andreas@digicool.com (Andreas Jung) Date: Fri, 12 Apr 2002 13:22:45 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/ZPublisher - HTTPResponse.py:1.58 Message-ID: <200204121722.g3CHMjm04436@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/ZPublisher In directory cvs.zope.org:/tmp/cvs-serv4425/lib/python/ZPublisher Modified Files: HTTPResponse.py Log Message: - new env. variable LOG_ZPUBLISHER_TRACEBACK (see doc/ENVIRONMENT.txt) === Zope/lib/python/ZPublisher/HTTPResponse.py 1.57 => 1.58 === +############################################################################# # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # @@ -16,6 +16,7 @@ __version__='$Revision$'[11:-2] import types, os, sys, re +import zLOG from string import translate, maketrans from types import StringType, InstanceType, LongType, UnicodeType from BaseResponse import BaseResponse @@ -175,7 +176,8 @@ if type(status) is types.StringType: status=status.lower() if status_codes.has_key(status): status=status_codes[status] - else: status=500 + else: + status=500 self.status=status if reason is None: if status_reasons.has_key(status): reason=status_reasons[status] @@ -607,6 +609,10 @@ (str(t), b + self._traceback(t,'(see above)', tb, 0)), is_error=1) del tb + + if os.environ.has_key('LOG_ZPUBLISHER_TRACEBACK'): + zLOG.LOG('zpublisher',zLOG.WARNING,'Traceback:',body) + return body _wrote=None From andreas@digicool.com Fri Apr 12 18:27:45 2002 From: andreas@digicool.com (Andreas Jung) Date: Fri, 12 Apr 2002 13:27:45 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/ZPublisher - HTTPResponse.py:1.59 Message-ID: <200204121727.g3CHRj705703@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/ZPublisher In directory cvs.zope.org:/tmp/cvs-serv5679/lib/python/ZPublisher Modified Files: HTTPResponse.py Log Message: reverted checkin for new env var LOG_ZPUBLISHER_TRACEBACK because Shanes traceback patches provide a much better functionality. === Zope/lib/python/ZPublisher/HTTPResponse.py 1.58 => 1.59 === import types, os, sys, re -import zLOG from string import translate, maketrans from types import StringType, InstanceType, LongType, UnicodeType from BaseResponse import BaseResponse @@ -609,10 +608,6 @@ (str(t), b + self._traceback(t,'(see above)', tb, 0)), is_error=1) del tb - - if os.environ.has_key('LOG_ZPUBLISHER_TRACEBACK'): - zLOG.LOG('zpublisher',zLOG.WARNING,'Traceback:',body) - return body _wrote=None From andreas@digicool.com Fri Apr 12 18:27:45 2002 From: andreas@digicool.com (Andreas Jung) Date: Fri, 12 Apr 2002 13:27:45 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.464 ENVIRONMENT.txt:1.13 Message-ID: <200204121727.g3CHRjc05706@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv5679/doc Modified Files: CHANGES.txt ENVIRONMENT.txt Log Message: reverted checkin for new env var LOG_ZPUBLISHER_TRACEBACK because Shanes traceback patches provide a much better functionality. === Zope/doc/CHANGES.txt 1.463 => 1.464 === - New implementation of ZODB object cache. - - new env. variable LOG_ZPUBLISHER_TRACEBACK - (see doc/ENVIRONMENT.txt) - Bugs: - Made repr of an HTTPRequest.record eval'able as a dict (Collector === Zope/doc/ENVIRONMENT.txt 1.12 => 1.13 === - LOG_ZPUBLISHER_TRACEBACK - - If set, Zope will log all ZPublisher traceback through - the stupid logger. (Default: unset) - - Misc. Z_REALM "your realm" From info@torped.se Fri Apr 12 18:29:21 2002 From: info@torped.se (Torped Strategy and Communications) Date: Fri, 12 Apr 2002 13:29:21 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS/tests - testTraverse.py:1.2 Message-ID: <200204121729.g3CHTLb05925@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS/tests In directory cvs.zope.org:/tmp/cvs-serv5685/tests Modified Files: testTraverse.py Log Message: === Zope/lib/python/OFS/tests/testTraverse.py 1.1 => 1.2 === from OFS.Image import manage_addFile from Testing.makerequest import makerequest -from webdav.common import rfc1123_date from AccessControl import SecurityManager from AccessControl.SecurityManagement import newSecurityManager from AccessControl.SecurityManagement import noSecurityManager From info@torped.se Fri Apr 12 18:30:23 2002 From: info@torped.se (Torped Strategy and Communications) Date: Fri, 12 Apr 2002 13:30:23 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - SimpleItem.py:1.98 Message-ID: <200204121730.g3CHUNe06036@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv6024 Modified Files: SimpleItem.py Log Message: Fix of issue #69: If standard_error_message is a method, it never gets called, because isinstance will raise an Exception first. I now catch this exception. === Zope/lib/python/OFS/SimpleItem.py 1.97 => 1.98 === 'error_traceback': error_tb, 'error_message': error_message} - if isinstance(s, HTML): + + try: + _isinstance=isinstance(s, HTML) + except TypeError: + _isinstance=None + + if _isinstance: v = s(client, REQUEST, **kwargs) elif callable(s): v = s(**kwargs) From andreas@digicool.com Fri Apr 12 19:21:54 2002 From: andreas@digicool.com (Andreas Jung) Date: Fri, 12 Apr 2002 14:21:54 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.465 Message-ID: <200204121821.g3CILsL21467@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv21460/doc Modified Files: CHANGES.txt Log Message: clearified === Zope/doc/CHANGES.txt 1.464 => 1.465 === and now output extended information like HTTPServer does. - - Propertysheets: Ids like 'values','keys' and 'values' are + - Propertysheets: Ids like 'values' and 'items' are now forbidden as they break WebDAV functionality. Existing Propertysheets are not affected From jeremy@zope.com Fri Apr 12 19:22:46 2002 From: jeremy@zope.com (Jeremy Hylton) Date: Fri, 12 Apr 2002 14:22:46 -0400 Subject: [Zope-Checkins] CVS: StandaloneZODB/ZODB/tests - testTransaction.py:1.6 Message-ID: <200204121822.g3CIMkI21560@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZODB/tests In directory cvs.zope.org:/tmp/cvs-serv21553 Modified Files: testTransaction.py Log Message: Cosmetic changes to ExceptionInSubAbortSub, including some use of assert/fail methods instead of assert stmt. === StandaloneZODB/ZODB/tests/testTransaction.py 1.5 => 1.6 === """ -import unittest - from types import TupleType +import unittest from ZODB import Transaction @@ -467,31 +466,32 @@ assert self.nosub1._p_jar.ctpc_abort == 1 def testExceptionInSubAbortSub(self): - self.sub1._p_jar = SubTransactionJar(errors='commit_sub') - self.sub1.modify(nojar=1) - get_transaction().commit(1) self.nosub1.modify() - self.sub2._p_jar = SubTransactionJar(errors='abort_sub') - self.sub2.modify(nojar=1) - get_transaction().commit(1) self.sub3.modify() try: get_transaction().commit() - except TestTxnException: pass + except TestTxnException, err: + pass + else: + self.fail("expected transaction to fail") + # The last commit failed. If the commit_sub() method was + # called, then tpc_abort() should be called to abort the + # actual transaction. If not, then calling abort_sub() is + # sufficient. if self.sub3._p_jar.ccommit_sub == 1: - assert self.sub3._p_jar.ctpc_abort == 1 + self.assertEqual(self.sub3._p_jar.ctpc_abort, 1) else: - assert self.sub3._p_jar.cabort_sub == 1 + self.assertEqual(self.sub3._p_jar.cabort_sub, 1) ### XXX def BUGtestExceptionInSubTpcBegin(self): @@ -603,15 +603,12 @@ self.ccommit_sub = 0 def check(self, method): - if self.tracing: print '%s calling method %s'%(str(self.tracing),method) - - if (type(self.errors) is TupleType and method in self.errors) or \ - method == self.errors: - - raise TestTxnException(" error %s"%method) + if ((type(self.errors) is TupleType and method in self.errors) + or method == self.errors): + raise TestTxnException("error %s" % method) ## basic jar txn interface From brian@zope.com Fri Apr 12 19:24:25 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 14:24:25 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - Management.py:1.57 Message-ID: <200204121824.g3CIOPh21778@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv21766 Modified Files: Management.py Log Message: Fixed bug #319. === Zope/lib/python/App/Management.py 1.56 => 1.57 === from Globals import DTMLFile, HTMLFile from AccessControl import getSecurityManager, Unauthorized +from AccessControl.SimpleObjectPolicies import _noroles class Tabs(ExtensionClass.Base): """Mix-in provides management folder tab support.""" @@ -54,7 +55,7 @@ if o is None: continue try: - if validate(None, self, None, o, None): + if validate(None, self, None, o, _noroles): result.append(d) except: if not hasattr(o, '__roles__'): From brian@zope.com Fri Apr 12 19:24:09 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 14:24:09 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - Management.py:1.55.16.1 Message-ID: <200204121824.g3CIO9e21759@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv21676 Modified Files: Tag: Zope-2_5-branch Management.py Log Message: Fixed bug #319. === Zope/lib/python/App/Management.py 1.55 => 1.55.16.1 === from string import split, join, find from AccessControl import getSecurityManager, Unauthorized +from AccessControl.SimpleObjectPolicies import _noroles class Tabs(ExtensionClass.Base): """Mix-in provides management folder tab support.""" @@ -55,7 +56,7 @@ if o is None: continue try: - if validate(None, self, None, o, None): + if validate(None, self, None, o, _noroles): result.append(d) except: if not hasattr(o, '__roles__'): From brian@zope.com Fri Apr 12 19:25:14 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 14:25:14 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - Management.py:1.48.4.2 Message-ID: <200204121825.g3CIPEg21872@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv21865 Modified Files: Tag: Zope-2_4-branch Management.py Log Message: Fixed bug #319. === Zope/lib/python/App/Management.py 1.48.4.1 => 1.48.4.2 === from string import split, join, find from AccessControl import getSecurityManager +from AccessControl.SimpleObjectPolicies import _noroles class Tabs(ExtensionClass.Base): """Mix-in provides management folder tab support.""" @@ -127,7 +128,7 @@ if o is None: continue try: - if validate(container=self, value=o): + if validate(None, self, None, o, _noroles): result.append(d) except: if not hasattr(o, '__roles__'): From brian@zope.com Fri Apr 12 19:27:50 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 14:27:50 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.406.2.47 Message-ID: <200204121827.g3CIRoQ22869@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv22862 Modified Files: Tag: Zope-2_5-branch CHANGES.txt Log Message: updated === Zope/doc/CHANGES.txt 1.406.2.46 => 1.406.2.47 === Bugs Fixed + - Fix for Collector #319: filtered_manage_options didn't + correctly filter tabs based on permission. + - Fix for Collector # 275: setPermissionDefault was not being propagated to actual security settings. From brian@zope.com Fri Apr 12 19:28:22 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 14:28:22 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.335.2.112 Message-ID: <200204121828.g3CISMs22963@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv22956 Modified Files: Tag: Zope-2_4-branch CHANGES.txt Log Message: updated === Zope/doc/CHANGES.txt 1.335.2.111 => 1.335.2.112 === Bugs Fixed + - Fix for Collector #319: filtered_manage_options didn't + correctly filter tabs based on permission. + - Collector #275: ClassSecurityInfo.setPermissionDefault broken From brian@zope.com Fri Apr 12 19:29:02 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 14:29:02 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.466 Message-ID: <200204121829.g3CIT2V23093@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv23073 Modified Files: CHANGES.txt Log Message: updated === Zope/doc/CHANGES.txt 1.465 => 1.466 === Bugs: + - Fix for Collector #319: filtered_manage_options didn't + correctly filter tabs based on permission. + - Made repr of an HTTPRequest.record eval'able as a dict (Collector #89). From jeremy@zope.com Fri Apr 12 19:29:16 2002 From: jeremy@zope.com (Jeremy Hylton) Date: Fri, 12 Apr 2002 14:29:16 -0400 Subject: [Zope-Checkins] CVS: StandaloneZODB/ZODB - Transaction.py:1.35 Message-ID: <200204121829.g3CITGG23113@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZODB In directory cvs.zope.org:/tmp/cvs-serv23104 Modified Files: Transaction.py Log Message: Wrap abort_sub() call in try/except that logs exception and continues. This fixes the transient failure in testExceptionInSubAbortSub() and is presumed to be correct, too. The old code had the comment: # This should never fail but did not to guarantee that it never failed. I'm assuming that the write fix is to log the error and ignore it, because that's what the call to tpc_abort() immediately above does. XXX commit() is a really long method. It would be nice to break it up into easier-to-understand chunks. === StandaloneZODB/ZODB/Transaction.py 1.34 => 1.35 === # Someone finished, so don't allow any more # work without at least a restart! - hosed=1 + hosed = 1 LOG('ZODB', PANIC, "A storage error occurred in the last phase of a " "two-phase commit. This shouldn\'t happen. " @@ -287,7 +287,7 @@ raise except: - t,v,tb=sys.exc_info() + t, v, tb = sys.exc_info() # Ugh, we got an got an error during commit, so we # have to clean up. @@ -295,32 +295,42 @@ # First, we have to abort any uncommitted objects. for o in objects[ncommitted:]: try: - j=getattr(o, '_p_jar', o) - if j is not None: j.abort(o, self) - except: pass + j = getattr(o, '_p_jar', o) + if j is not None: + j.abort(o, self) + except: + pass # Then, we unwind TPC for the jars that began it. if jarsv is None: jarsv = jars.values() for j in jarsv: - try: j.tpc_abort(self) # This should never fail + try: + j.tpc_abort(self) # This should never fail except: LOG('ZODB', ERROR, "A storage error occured during object abort " - "This shouldn\'t happen. ", + "This shouldn't happen. ", error=sys.exc_info()) # Ugh, we need to abort work done in sub-transactions. while subjars: - j=subjars.pop() - j.abort_sub(self) # This should never fail + j = subjars.pop() + try: + j.abort_sub(self) # This should never fail + except: + LOG('ZODB', ERROR, + "A storage error occured during sub-transaction " + "object abort. This shouldn't happen.", + error=sys.exc_info()) - raise t,v,tb + raise t, v, tb finally: - tb=None + tb = None del objects[:] # clear registered - if not subtransaction and self._id is not None: free_transaction() + if not subtransaction and self._id is not None: + free_transaction() def register(self,object): 'Register the given object for transaction control.' From matt@zope.com Fri Apr 12 19:29:17 2002 From: matt@zope.com (Matthew T. Kromer) Date: Fri, 12 Apr 2002 14:29:17 -0400 Subject: [Zope-Checkins] CVS: Products/DCOracle2 - CHANGELOG:1.49 Message-ID: <200204121829.g3CITHV23128@cvs.baymountain.com> Update of /cvs-repository/Products/DCOracle2 In directory cvs.zope.org:/tmp/cvs-serv23006 Modified Files: CHANGELOG Log Message: Add compare mechanism to OracleDates so you can sort them (Collector issue # 36) === Products/DCOracle2/CHANGELOG 1.48 => 1.49 === o Made isdst flag for creation of OracleDates default to unknown, rather than no DST + o Gave OracleDates a __cmp__ method so they can be compared Desired Features Not Yet Implemented: From matt@zope.com Fri Apr 12 19:29:46 2002 From: matt@zope.com (Matthew T. Kromer) Date: Fri, 12 Apr 2002 14:29:46 -0400 Subject: [Zope-Checkins] CVS: Products/DCOracle2/src - dco2.c:1.107 Message-ID: <200204121829.g3CITkN23143@cvs.baymountain.com> Update of /cvs-repository/Products/DCOracle2/src In directory cvs.zope.org:/tmp/cvs-serv23006/src Modified Files: dco2.c Log Message: Add compare mechanism to OracleDates so you can sort them (Collector issue # 36) === Products/DCOracle2/src/dco2.c 1.106 => 1.107 === static PyObject *OracleDate_str(OracleDate *self); static PyObject *OracleDate_repr(OracleDate *self); +static int OracleDate_cmp(OracleDate *left, OracleDate *right); static int OracleDate_coerce(PyObject **o1, PyObject **o2); static PyObject *OracleDate_int(OracleDate *self); static PyObject *OracleDate_long(OracleDate *self); @@ -857,7 +858,7 @@ (printfunc) NULL, /* tp_print */ (getattrfunc) OracleDate_getattr, /* obsolete tp_getattr */ (setattrfunc) NULL, /* obsolete tp_setattr */ - (cmpfunc) NULL, /* tp_compare */ + (cmpfunc) OracleDate_cmp, /* tp_compare */ (reprfunc) OracleDate_repr, /* tp_repr */ &OracleDateNumberMethods, /* tp_as_number */ NULL, /* tp_as_sequence */ @@ -4936,6 +4937,24 @@ TRACE(T_EXIT,("sA", "OracleDate_repr", self->repr)); return self->repr; +} + +/* +** OracleDate_cmp +** +*/ + +static int OracleDate_cmp(OracleDate *left, OracleDate *right) { + + int result; + + TRACE(T_ENTRY,("sAA", "OracleDate_cmp", left, right)); + + result = memcmp(left->ocidate, right->ocidate, sizeof(left->ocidate)); + + TRACE(T_ENTRY,("sd", "OracleDate_cmp", result)); + + return result; } /* From shane@cvs.zope.org Fri Apr 12 19:56:55 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 14:56:55 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - IReadFileSystem.py:1.1.2.6 Message-ID: <200204121856.g3CIutX01036@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv31781 Modified Files: Tag: Zope3-Server-Branch IReadFileSystem.py Log Message: Updated docstrings: IReadFileSystem should always expect POSIX paths, which it can translate to platform-dependent paths if needed. === Zope3/lib/python/Zope/Server/VFS/IReadFileSystem.py 1.1.2.5 => 1.1.2.6 === return a producer. + All paths are POSIX paths, even when run on Windows, + which mainly means that FS implementations always expect forward + slashes, and filenames are case-sensitive. + Note: A file system should *not* store any state! """ @@ -44,8 +48,8 @@ """Return a listing of the directory at 'path' The empty string indicates the current directory. If 'with_stats' is set, instead return a list of (name, stat_info) tuples. All file - names are filtered by the pattern, which is epected to be a regular - filesystem search pattern. + names are filtered by the globbing pattern. (See the 'glob' + module in the Python standard library.) """ return list(tuple(str, str)) From shane@cvs.zope.org Fri Apr 12 19:57:27 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 14:57:27 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - IWriteFileSystem.py:1.1.2.6 Message-ID: <200204121857.g3CIvRJ01973@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv1381 Modified Files: Tag: Zope3-Server-Branch IWriteFileSystem.py Log Message: check_writable should not need the mode. === Zope3/lib/python/Zope/Server/VFS/IWriteFileSystem.py 1.1.2.5 => 1.1.2.6 === """ - def check_writable(path, mode): + def check_writable(path): """Ensures a path is writable. Throws an IOError if not.""" From shane@cvs.zope.org Fri Apr 12 20:02:25 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 15:02:25 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - OSFileSystem.py:1.1.2.14 Message-ID: <200204121902.g3CJ2PU04308@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv4296 Modified Files: Tag: Zope3-Server-Branch OSFileSystem.py Log Message: Simplified away the path_module attribute and simplified path checking === Zope3/lib/python/Zope/Server/VFS/OSFileSystem.py 1.1.2.13 => 1.1.2.14 === __implements__ = IPosixFileSystem - path_module = os.path - copy_bytes = 65536 @@ -82,19 +80,19 @@ def exists(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' p = self.translate(path) - return self.path_module.exists(p) + return os.path.exists(p) def isdir(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' p = self.translate(path) - return self.path_module.isdir(p) + return os.path.isdir(p) def isfile(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' p = self.translate(path) - return self.path_module.isfile(p) + return os.path.isfile(p) def listdir(self, path, with_stats=0, pattern='*'): @@ -111,7 +109,7 @@ else: result = [] for file in ld: - path = self.path_module.join(p, file) + path = os.path.join(p, file) stat = safe_stat(path) if stat is not None: result.append((file, stat)) @@ -182,7 +180,7 @@ break outstream.write(data) - def check_writable(self, path, mode): + def check_writable(self, path): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' p = self.translate(path) if os.path.exists(p): @@ -202,11 +200,13 @@ def normalize (self, path): # watch for the ever-sneaky '/+' path element + # XXX It is unclear why "/+" is dangerous. It is definitely + # unexpected. path = re.sub('/+', '/', path) - # Someone is trying to get lower than the permitted root. - # We just ignore it. - path = self.path_module.normpath(path) - if path.startswith('..') or path.startswith('../'): + path = os.path.normpath(path) + if path.startswith('..'): + # Someone is trying to get lower than the permitted root. + # We just ignore it. path = '/' return path @@ -220,18 +220,16 @@ could attempt to a directory below root! """ # Normalize the directory - path = os.sep.join(path.split('/')) - path = self.normalize(self.path_module.join(path)) + path = self.normalize(path) # Prepare for joining with root - if path[0] == '/': + while path.startswith('/'): path = path[1:] # Join path with root - path = self.path_module.join(self.root, path) - return path + return os.path.join(self.root, path) def __repr__ (self): - return '' % self.root + return '' % self.root From shane@cvs.zope.org Fri Apr 12 20:04:30 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 15:04:30 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS/tests - PosixFilesystemTests.py:1.1.2.1 ReadFilesystemTests.py:1.1.2.1 WriteFilesystemTests.py:1.1.2.1 testOSFileSystem.py:1.1.2.10 Message-ID: <200204121904.g3CJ4Ur04531@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS/tests In directory cvs.zope.org:/tmp/cvs-serv4441 Modified Files: Tag: Zope3-Server-Branch testOSFileSystem.py Added Files: Tag: Zope3-Server-Branch PosixFilesystemTests.py ReadFilesystemTests.py WriteFilesystemTests.py Log Message: Split apart and expanded filesystem tests so they can be reused === Added File Zope3/lib/python/Zope/Server/VFS/tests/PosixFilesystemTests.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: PosixFilesystemTests.py,v 1.1.2.1 2002/04/12 19:04:30 shane Exp $ """ import stat from Interface.Verify import verifyClass from Zope.Server.VFS.IPosixFileSystem import IPosixFileSystem from WriteFilesystemTests import WriteFilesystemTests class PosixFilesystemTests (WriteFilesystemTests): """Tests of a writable and readable POSIX-compliant filesystem """ def testChmod(self): old_mode = self.filesystem.stat(self.file_name)[stat.ST_MODE] new_mode = old_mode ^ 0444 self.filesystem.chmod(self.file_name, new_mode) check_mode = self.filesystem.stat(self.file_name)[stat.ST_MODE] self.assertEqual(check_mode, new_mode) def testChown(self): self.filesystem.chown(self.file_name, 500, 500) s = self.filesystem.stat(self.file_name) self.assertEqual(s[stat.ST_UID], 500) self.assertEqual(s[stat.ST_GID], 500) def testMakeLink(self): self.filesystem.link(self.file_name, self.file_name + '.linked') self.failUnless(self.filesystem.exists(self.file_name + '.linked')) # Another test should test whether writing to one file # changes the other. def testMakeFifo(self): path = self.dir_name + '/fifo' self.filesystem.mkfifo(path) self.failUnless(self.filesystem.exists(path)) # Another test should test the behavior of the fifo. def testMakeSymlink(self): self.filesystem.symlink(self.file_name, self.file_name + '.symlink') self.failUnless(self.filesystem.exists(self.file_name + '.symlink')) # Another test should test whether writing to one file # changes the other. def testPosixInterface(self): class_ = self.filesystem.__class__ self.failUnless( IPosixFileSystem.isImplementedByInstancesOf(class_)) self.failUnless(verifyClass(IPosixFileSystem, class_)) def test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(OSFileSystemTest) if __name__=='__main__': unittest.TextTestRunner().run( test_suite() ) === Added File Zope3/lib/python/Zope/Server/VFS/tests/ReadFilesystemTests.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: ReadFilesystemTests.py,v 1.1.2.1 2002/04/12 19:04:30 shane Exp $ """ import stat from StringIO import StringIO from Interface.Verify import verifyClass from Zope.Server.VFS.IReadFileSystem import IReadFileSystem class ReadFilesystemTests: """Tests of a readable filesystem """ filesystem = None dir_name = '/dir' file_name = '/dir/file.txt' dir_contents = ['file.txt'] file_contents = 'Lengthen your stride' def testExists(self): self.failUnless(self.filesystem.exists(self.dir_name)) self.failUnless(self.filesystem.exists(self.file_name)) def testIsDir(self): self.failUnless(self.filesystem.isdir(self.dir_name)) self.failUnless(not self.filesystem.isdir(self.file_name)) def testIsFile(self): self.failUnless(self.filesystem.isfile(self.file_name)) self.failUnless(not self.filesystem.isfile(self.dir_name)) def testListDir(self): lst = self.filesystem.listdir(self.dir_name, 0) lst.sort() self.assertEqual(lst, self.dir_contents) def testReadFile(self): s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s) self.assertEqual(s.getvalue(), self.file_contents) def testReadPartOfFile(self): s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s, 2) self.assertEqual(s.getvalue(), self.file_contents[2:]) def testReadPartOfFile2(self): s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s, 1, 5) self.assertEqual(s.getvalue(), self.file_contents[1:5]) def testReadInterface(self): class_ = self.filesystem.__class__ self.failUnless( IReadFileSystem.isImplementedByInstancesOf(class_)) self.failUnless(verifyClass(IReadFileSystem, class_)) === Added File Zope3/lib/python/Zope/Server/VFS/tests/WriteFilesystemTests.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: WriteFilesystemTests.py,v 1.1.2.1 2002/04/12 19:04:30 shane Exp $ """ from StringIO import StringIO from Interface.Verify import verifyClass from Zope.Server.VFS.IWriteFileSystem import IWriteFileSystem from ReadFilesystemTests import ReadFilesystemTests class WriteFilesystemTests (ReadFilesystemTests): """Tests of a writable and readable filesystem """ def testRemove(self): self.failIf(not self.filesystem.exists(self.file_name)) self.filesystem.remove(self.file_name) self.failIf(self.filesystem.exists(self.file_name)) def testMkdir(self): path = self.dir_name + '/x' self.filesystem.mkdir(path) self.failUnless(self.filesystem.exists(path)) self.failUnless(self.filesystem.isdir(path)) def testRmdir(self): self.failIf(not self.filesystem.exists(self.dir_name)) self.filesystem.remove(self.file_name) self.filesystem.rmdir(self.dir_name) self.failIf(self.filesystem.exists(self.dir_name)) def testRename(self): self.filesystem.rename(self.file_name, self.file_name + '.bak') self.failIf(self.filesystem.exists(self.file_name)) self.failIf(not self.filesystem.exists(self.file_name + '.bak')) def testWriteFile(self): s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s) self.assertEqual(s.getvalue(), self.file_contents) data = 'Always ' + self.file_contents s = StringIO(data) self.filesystem.writefile(self.file_name, 'wb', s) s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s) self.assertEqual(s.getvalue(), data) def testAppendToFile(self): data = ' again' s = StringIO(data) self.filesystem.writefile(self.file_name, 'ab', s) s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s) self.assertEqual(s.getvalue(), self.file_contents + data) def testWritePartOfFile(self): data = '123' s = StringIO(data) self.filesystem.writefile(self.file_name, 'r+b', s, 3) expect = self.file_contents[:3] + data + self.file_contents[6:] s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s) self.assertEqual(s.getvalue(), expect) def testWriteBeyondEndOfFile(self): partlen = len(self.file_contents) - 6 data = 'daylight savings' s = StringIO(data) self.filesystem.writefile(self.file_name, 'r+b', s, partlen) expect = self.file_contents[:partlen] + data s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s) self.assertEqual(s.getvalue(), expect) def testWriteNewFile(self): s = StringIO(self.file_contents) self.filesystem.writefile(self.file_name + '.new', 'wb', s) s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s) self.assertEqual(s.getvalue(), self.file_contents) def testCheckWriteable(self): # Can't overwrite a directory. self.assertRaises( IOError, self.filesystem.check_writable, self.dir_name) # Can overwrite a file. try: self.filesystem.check_writable(self.file_name) except IOError, v: self.fail('%s should be writable. (%s)' % (self.file_name, v)) def testWriteInterface(self): class_ = self.filesystem.__class__ self.failUnless( IWriteFileSystem.isImplementedByInstancesOf(class_)) self.failUnless(verifyClass(IWriteFileSystem, class_)) def test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(OSFileSystemTest) if __name__=='__main__': unittest.TextTestRunner().run( test_suite() ) === Zope3/lib/python/Zope/Server/VFS/tests/testOSFileSystem.py 1.1.2.9 => 1.1.2.10 === import unittest import os -import stat +import shutil import tempfile from StringIO import StringIO -from Interface.Verify import verifyClass -from Zope.Server.VFS.IReadFileSystem import IReadFileSystem -from Zope.Server.VFS.IWriteFileSystem import IWriteFileSystem - from Zope.Server.VFS.OSFileSystem import OSFileSystem -class OSFileSystemTest(unittest.TestCase): +from WriteFilesystemTests import WriteFilesystemTests + + +def joinToRoot(root, name): + if name.startswith('/'): + name = name[1:] + return os.path.join(root, os.path.normpath(name)) + + +class OSFileSystemTests(unittest.TestCase, WriteFilesystemTests): """This test is constructed in a way that it builds up a directory structure, whcih is removed at the end. """ @@ -43,10 +48,15 @@ self.filesystem = self.filesystem_class(self.root) os.mkdir(self.root) + os.mkdir(joinToRoot(self.root, self.dir_name)) + f = open(joinToRoot(self.root, self.file_name), 'w') + f.write(self.file_contents) + f.close() def tearDown(self): - os.rmdir(self.root) + + shutil.rmtree(self.root) def testNormalize(self): @@ -75,175 +85,36 @@ self.assertEqual(self.filesystem.root, self.root) self.assertEqual(self.filesystem.translate('/foo/'), - self.filesystem.path_module.join(self.root, 'foo')) + os.path.join(self.root, 'foo')) self.assertEqual(self.filesystem.translate('/foo/bar'), - self.filesystem.path_module.join(self.root, - 'foo', 'bar')) + os.path.join(self.root, 'foo', 'bar')) self.assertEqual(self.filesystem.translate('foo/bar'), - self.filesystem.path_module.join(self.root, - 'foo', 'bar')) + os.path.join(self.root, 'foo', 'bar')) - def testExists(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('test') - self.failUnless(self.filesystem.exists('foo')) - os.remove(path) - - - def testIsDir(self): - path = os.path.join(self.root, 'foo') - os.mkdir(path) - self.failUnless(self.filesystem.isdir('foo')) - os.rmdir(path) - - - def testIsFile(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('test') - self.failUnless(self.filesystem.isfile('foo')) - os.remove(path) - - - def testListDir(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('test') - self.assertEqual(self.filesystem.listdir('/', 0), - ['foo']) - os.remove(path) - - - def testReadfile(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - s = StringIO() - self.filesystem.readfile('foo', 'r', s) - self.assertEqual(s.getvalue(), 'writing test') - os.remove(path) + def testStat(self): + stat = os.stat(joinToRoot(self.root, self.file_name)) + self.assertEqual(self.filesystem.stat(self.file_name), stat) - def testStat(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - self.assertEqual(self.filesystem.stat('foo'), os.stat(path)) - os.remove(path) - - - def testChmod(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - mode = 6*2**6 + 4*2**3 + 4*2**0 # 644 - self.filesystem.chmod('foo', mode) - self.assertEqual(('%o' %os.stat(path)[stat.ST_MODE])[-3:], '644') - os.remove(path) - - - def testChown(self): - # This test is disabled until we start using a RAM filesystem - # for testing. - return - path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - self.filesystem.chown('foo', 500, 500) - self.assertEqual(os.stat(path)[stat.ST_UID], 500) - self.assertEqual(os.stat(path)[stat.ST_GID], 500) - os.remove(path) - - - def testLink(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - self.filesystem.link('foo', 'foo1') - self.failUnless(os.path.exists(path+'1')) - os.remove(path) - os.remove(path+'1') - - - def testMkdir(self): - path = os.path.join(self.root, 'foo') - self.filesystem.mkdir('foo') - self.failUnless(os.path.exists(path)) - self.failUnless(os.path.isdir(path)) - os.rmdir(path) - - - def testFifo(self): - path = os.path.join(self.root, 'foo') - self.filesystem.mkfifo(path) - self.failUnless(os.path.exists(path)) - os.remove(path) - - - def testRemove(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - self.filesystem.remove('foo') - self.failIf(os.path.exists(path)) - - - def testRmdir(self): - path = os.path.join(self.root, 'foo') - os.mkdir(path) - self.filesystem.rmdir('foo') - self.failIf(os.path.exists(path)) - - - def testRename(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - self.filesystem.rename('foo', 'foo1') - self.failUnless(os.path.exists(path+'1')) - os.remove(path+'1') - - - def testSymlink(self): - path = os.path.join(self.root, 'foo') - open(path, 'w').write('writing test') - self.filesystem.symlink('foo', 'foo1') - self.failUnless(os.path.exists(path+'1')) - os.remove(path) - os.remove(path+'1') - - - def testWritefile(self): - s = StringIO('foo bar') - self.filesystem.writefile('foo', 'w', s) - path = os.path.join(self.root, 'foo') - file = open(path, 'r') - self.assertEqual(file.read(), 'foo bar') - file.close() - os.remove(path) - - - def testCheckWriteable(self): - s = StringIO() - dirpath = os.path.join(self.root, 'somename') - os.mkdir(dirpath) - try: - # Can't overwrite a directory. - self.assertRaises( - IOError, self.filesystem.writefile, 'somename', 'w', s) - finally: - os.rmdir(dirpath) - try: - # Now it's ok. - self.filesystem.writefile('somename', 'w', s) - finally: - os.remove(dirpath) - - - def testInterface(self): - self.failUnless( - IReadFileSystem.isImplementedByInstancesOf(self.filesystem_class)) - self.failUnless(verifyClass(IReadFileSystem, self.filesystem_class)) - - self.failUnless( - IWriteFileSystem.isImplementedByInstancesOf(self.filesystem_class)) - self.failUnless(verifyClass(IWriteFileSystem, self.filesystem_class)) + + +if 0 and os.name == 'posix': + + from PosixFilesystemTests import PosixFilesystemTests + + class OSPosixFilesystemTests(OSFileSystemTests, PosixFilesystemTests): + + def testChown(self): + # Disable this test, since it won't work unless you're root. + return + + OSFileSystemTests = OSPosixFilesystemTests + def test_suite(): loader = unittest.TestLoader() - return loader.loadTestsFromTestCase(OSFileSystemTest) + return loader.loadTestsFromTestCase(OSFileSystemTests) if __name__=='__main__': unittest.TextTestRunner().run( test_suite() ) From chrism@zope.com Fri Apr 12 20:11:50 2002 From: chrism@zope.com (Chris McDonough) Date: Fri, 12 Apr 2002 15:11:50 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/ZCatalog - CatalogPathAwareness.py:1.6.16.1 __init__.py:1.17.16.1 Message-ID: <200204121911.g3CJBo806785@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/ZCatalog In directory cvs.zope.org:/tmp/cvs-serv5764 Modified Files: Tag: Zope-2_5-branch CatalogPathAwareness.py __init__.py Log Message: Register CatalogPathAware (a bare subclass of CatalogPathAwareness .CatalogAware) as a ZClass base class. Its reason for existence is to make the name that shows up in the ZClass Product list different than 'ZCatalog: CatalogAware', which is the name registered by CatalogAwareness.CatalogAware. The fix should *really* be to change the product registry to keep the whole module/class path and to make the ZClass add UI show the whole path, but this is nontrivial, we don't want to spend a lot of time on ZClasses, and this works. Now when we tell people to use CatalogPathAware instead of CatalogAware, they will actually be able to do it without a lot of effort. The reason we can't replace CatalogAware with CatalogPathAware is backwards-compatibility and the desire to not force people to do data conversion on their existing instances. === Zope/lib/python/Products/ZCatalog/CatalogPathAwareness.py 1.6 => 1.6.16.1 === - - - - - - +class CatalogPathAware(CatalogAware): + """ + This is a stub class that gets registered in __init__.py as a + ZClass base class. Its reason for existance is to make the name + that shows up in the ZClass Product list different than 'ZCatalog: + CatalogAware', which is the name registered by + CatalogAwareness.CatalogAware. The fix should *really* be to + change the product registry to keep the whole module/class path + and to make the ZClass add UI show the whole path, but this is + nontrivial, we don't want to spend a lot of time on ZClasses, and + this works. + """ === Zope/lib/python/Products/ZCatalog/__init__.py 1.17 => 1.17.16.1 === """ZCatalog product""" -import ZCatalog, Catalog, CatalogAwareness, ZClasses +import ZCatalog, Catalog, CatalogAwareness, CatalogPathAwareness, ZClasses from Products.PluginIndexes.TextIndex import Vocabulary from ZClasses import createZClassForBase @@ -21,6 +21,8 @@ , 'ZCatalogBase', 'ZCatalog' ) createZClassForBase( CatalogAwareness.CatalogAware, globals() , 'CatalogAwareBase', 'CatalogAware' ) +createZClassForBase( CatalogPathAwareness.CatalogPathAware, globals() + , 'CatalogPathAwareBase', 'CatalogPathAware' ) def initialize(context): context.registerClass( From shane@cvs.zope.org Fri Apr 12 20:14:14 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 15:14:14 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - FTPServerChannel.py:1.1.2.25 Message-ID: <200204121914.g3CJEEd07081@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv6963 Modified Files: Tag: Zope3-Server-Branch FTPServerChannel.py Log Message: Always use posixpath instead of os.path, since we always want slashes in paths, even on Windows. === Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py 1.1.2.24 => 1.1.2.25 === """ -import os +import posixpath import stat import sys import socket @@ -382,7 +382,7 @@ # The actually write should be transactional without # holding up the application. fs = self._getFilesystem() - fs.check_writable(path, mode) + fs.check_writable(path) except OSError, err: self.reply('ERR_OPEN_WRITE', str(err)) return @@ -457,13 +457,10 @@ def _generatePath(self, args): """Convert relative paths to absolute paths.""" - if args.startswith('/'): - path = args - else: - path = os.path.join(self.cwd, args) - if path.startswith('..'): - path = '/' - return os.path.normpath(path) + # We use posixpath even on non-Posix platforms because we don't want + # slashes converted to backslashes. + path = posixpath.join(self.cwd, args) + return posixpath.normpath(path) def newPassiveAcceptor(self): @@ -498,7 +495,7 @@ else: dir = path_args[0] - dir = os.path.join(self.cwd, dir) + dir = self._generatePath(dir) return self.listdir(dir, long) From info@torped.se Fri Apr 12 20:15:28 2002 From: info@torped.se (Torped Strategy and Communications) Date: Fri, 12 Apr 2002 15:15:28 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - SimpleItem.py:1.99 Message-ID: <200204121915.g3CJFSc07343@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv7305/lib/python/OFS Modified Files: SimpleItem.py Log Message: Mistakenly commited to trunk. Reversing the change. === Zope/lib/python/OFS/SimpleItem.py 1.98 => 1.99 === 'error_message': error_message} - try: - _isinstance=isinstance(s, HTML) - except TypeError: - _isinstance=None - - if _isinstance: + if isinstance(s, HTML): v = s(client, REQUEST, **kwargs) elif callable(s): v = s(**kwargs) From chrism@zope.com Fri Apr 12 20:16:47 2002 From: chrism@zope.com (Chris McDonough) Date: Fri, 12 Apr 2002 15:16:47 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.406.2.48 Message-ID: <200204121916.g3CJGlC08602@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv8595 Modified Files: Tag: Zope-2_5-branch CHANGES.txt Log Message: === Zope/doc/CHANGES.txt 1.406.2.47 => 1.406.2.48 === Bugs Fixed + - Register CatalogPathAware as a ZClass base class in response + to Collector #33. + - Fix for Collector #319: filtered_manage_options didn't correctly filter tabs based on permission. From brian@zope.com Fri Apr 12 20:19:34 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 15:19:34 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - Management.py:1.55.16.2 Message-ID: <200204121919.g3CJJY610001@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv9955 Modified Files: Tag: Zope-2_5-branch Management.py Log Message: Change _noroles -> None === Zope/lib/python/App/Management.py 1.55.16.1 => 1.55.16.2 === try: - if validate(None, self, None, o, _noroles): + if validate(None, self, None, o, None): result.append(d) except: if not hasattr(o, '__roles__'): From brian@zope.com Fri Apr 12 20:20:12 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 15:20:12 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - Management.py:1.58 Message-ID: <200204121920.g3CJKCp10164@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv10124 Modified Files: Management.py Log Message: Changed _noroles -> None === Zope/lib/python/App/Management.py 1.57 => 1.58 === try: - if validate(None, self, None, o, _noroles): + if validate(None, self, None, o, None): result.append(d) except: if not hasattr(o, '__roles__'): From brian@zope.com Fri Apr 12 20:21:16 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 15:21:16 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - Management.py:1.48.4.3 Message-ID: <200204121921.g3CJLGp10763@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv10566 Modified Files: Tag: Zope-2_4-branch Management.py Log Message: Changed _noroles -> None === Zope/lib/python/App/Management.py 1.48.4.2 => 1.48.4.3 === try: - if validate(None, self, None, o, _noroles): + if validate(None, self, None, o, None): result.append(d) except: if not hasattr(o, '__roles__'): From casey@zope.com Fri Apr 12 20:25:18 2002 From: casey@zope.com (Casey Duncan) Date: Fri, 12 Apr 2002 15:25:18 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS/dtml - documentEdit.dtml:1.6 Message-ID: <200204121925.g3CJPIC12360@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS/dtml In directory cvs.zope.org:/tmp/cvs-serv12251/lib/python/OFS/dtml Modified Files: documentEdit.dtml Log Message: Fix for Bug#96: Narrower/Wider buttons now work in CSS browsers. This is only in affect for DTML thus far. === Zope/lib/python/OFS/dtml/documentEdit.dtml 1.5 => 1.6 ===

-
- -
+ + +
+ width="_.min(_.int(_.float(cols)/70.0 * 100.0),100)"> From shane@cvs.zope.org Fri Apr 12 20:37:18 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 15:37:18 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.406.2.49 Message-ID: <200204121937.g3CJbIA15911@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv15904 Modified Files: Tag: Zope-2_5-branch CHANGES.txt Log Message: Collector #167 === Zope/doc/CHANGES.txt 1.406.2.48 => 1.406.2.49 === and now output extended information like HTTPServer does. + - Collector #167: superValues() now includes items with duplicate + IDs + Zope 2.5.0 Final From brian@zope.com Fri Apr 12 20:39:19 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 15:39:19 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - Management.py:1.55.16.3 Message-ID: <200204121939.g3CJdJe16128@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv16116 Modified Files: Tag: Zope-2_5-branch Management.py Log Message: Ok, re-fixed tab filtering. === Zope/lib/python/App/Management.py 1.55.16.2 => 1.55.16.3 === try: - if validate(None, self, None, o, None): + if validate(None, self, None, o): result.append(d) except: if not hasattr(o, '__roles__'): From brian@zope.com Fri Apr 12 20:39:53 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 15:39:53 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - Management.py:1.59 Message-ID: <200204121939.g3CJdr616142@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv16135 Modified Files: Management.py Log Message: Ok, re-fixed tab filtering. === Zope/lib/python/App/Management.py 1.58 => 1.59 === try: - if validate(None, self, None, o, None): + if validate(None, self, None, o): result.append(d) except: if not hasattr(o, '__roles__'): From brian@zope.com Fri Apr 12 20:40:44 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 15:40:44 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - Management.py:1.48.4.4 Message-ID: <200204121940.g3CJeij16238@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv16230 Modified Files: Tag: Zope-2_4-branch Management.py Log Message: Ok, re-fixed tab filtering. === Zope/lib/python/App/Management.py 1.48.4.3 => 1.48.4.4 === try: - if validate(None, self, None, o, None): + if validate(None, self, None, o): result.append(d) except: if not hasattr(o, '__roles__'): From brian@zope.com Fri Apr 12 20:45:04 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 15:45:04 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - Management.py:1.48.4.5 Message-ID: <200204121945.g3CJj4517479@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv17472 Modified Files: Tag: Zope-2_4-branch Management.py Log Message: removed extra import === Zope/lib/python/App/Management.py 1.48.4.4 => 1.48.4.5 === from string import split, join, find from AccessControl import getSecurityManager -from AccessControl.SimpleObjectPolicies import _noroles class Tabs(ExtensionClass.Base): """Mix-in provides management folder tab support.""" From brian@zope.com Fri Apr 12 20:45:33 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 15:45:33 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - Management.py:1.60 Message-ID: <200204121945.g3CJjXl17494@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv17486 Modified Files: Management.py Log Message: removed extra import === Zope/lib/python/App/Management.py 1.59 => 1.60 === from Globals import DTMLFile, HTMLFile from AccessControl import getSecurityManager, Unauthorized -from AccessControl.SimpleObjectPolicies import _noroles class Tabs(ExtensionClass.Base): """Mix-in provides management folder tab support.""" From brian@zope.com Fri Apr 12 20:45:56 2002 From: brian@zope.com (Brian Lloyd) Date: Fri, 12 Apr 2002 15:45:56 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - Management.py:1.55.16.4 Message-ID: <200204121945.g3CJjuo17559@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv17552 Modified Files: Tag: Zope-2_5-branch Management.py Log Message: removed extra import === Zope/lib/python/App/Management.py 1.55.16.3 => 1.55.16.4 === from string import split, join, find from AccessControl import getSecurityManager, Unauthorized -from AccessControl.SimpleObjectPolicies import _noroles class Tabs(ExtensionClass.Base): """Mix-in provides management folder tab support.""" From shane@cvs.zope.org Fri Apr 12 20:46:33 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 15:46:33 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - ObjectManager.py:1.137.4.8 Message-ID: <200204121946.g3CJkXj18417@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv18405 Modified Files: Tag: Zope-2_4-branch ObjectManager.py Log Message: Collector #167 === Zope/lib/python/OFS/ObjectManager.py 1.137.4.7 => 1.137.4.8 === seen={} vals=[] + relativePhysicalPath = () have=seen.has_key x=0 while x < 100: @@ -456,13 +457,17 @@ for i in obj._objects: try: id=i['id'] - if (not have(id)) and (i['meta_type'] in t): + physicalPath = relativePhysicalPath + (id,) + if (not have(physicalPath)) and (i['meta_type'] in t): vals.append(get(id)) - seen[id]=1 + seen[physicalPath]=1 except: pass - if hasattr(obj,'aq_parent'): obj=obj.aq_parent - else: return vals + if hasattr(obj,'aq_parent'): + obj=obj.aq_parent + relativePhysicalPath = ('..',) + relativePhysicalPath + else: + return vals x=x+1 return vals From jeremy@zope.com Fri Apr 12 20:59:55 2002 From: jeremy@zope.com (Jeremy Hylton) Date: Fri, 12 Apr 2002 15:59:55 -0400 Subject: [Zope-Checkins] CVS: StandaloneZODB/ZODB - Transaction.py:1.36 Message-ID: <200204121959.g3CJxt526325@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZODB In directory cvs.zope.org:/tmp/cvs-serv26318 Modified Files: Transaction.py Log Message: Refactor the commit() method. Break up the logic into a bunch of helper methods: _commit_objects() _commit_subtrans() _finish_one() _finish_rest() and possibly _commit_error() As a result of the changes, the high-level logic of a commit fits into 28 lines inside a try/finally. There are lots of details hidden in the methods, but the names capture the high-level behavior of the helpers. === StandaloneZODB/ZODB/Transaction.py 1.35 => 1.36 === 'Finalize the transaction' - global hosed - - objects=self._objects - jars={} + objects = self._objects + jars = {} jarsv = None - subj=self._sub - subjars=() + subj = self._sub + subjars = () if subtransaction: - if subj is None: self._sub=subj={} + if subj is None: + self._sub = subj = {} else: if subj is not None: if objects: # Do an implicit sub-transaction commit: self.commit(1) - objects=[] - subjars=subj.values() - self._sub=None + # XXX What does this do? + objects = [] + subjars = subj.values() + self._sub = None # If not a subtransaction, then we need to add any non- # subtransaction-supporting objects that may have been # stowed away during subtransaction commits to _objects. if (subtransaction is None) and (self._non_st_objects is not None): - append=objects.append - for object in self._non_st_objects: - append(object) + objects.extend(self._non_st_objects) self._non_st_objects = None - t=v=tb=None - if (objects or subjars) and hosed: # Something really bad happened and we don't # trust the system state. - raise POSException.TransactionError, ( - - """A serious error, which was probably a system error, - occurred in a previous database transaction. This - application may be in an invalid state and must be - restarted before database updates can be allowed. - - Beware though that if the error was due to a serious - system problem, such as a disk full condition, then - the application may not come up until you deal with - the system problem. See your application log for - information on the error that lead to this problem. - """) + raise POSException.TransactionError, hosed_msg + # It's important that: + # + # - Every object in self._objects is either committed or + # aborted. + # + # - For each object that is committed we call tpc_begin on + # it's jar at least once + # + # - For every jar for which we've called tpc_begin on, we + # either call tpc_abort or tpc_finish. It is OK to call + # these multiple times, as the storage is required to ignore + # these calls if tpc_begin has not been called. try: - - # It's important that: - # - # - Every object in self._objects is either committed - # or aborted. - # - # - For each object that is committed - # we call tpc_begin on it's jar at least once - # - # - For every jar for which we've called tpc_begin on, - # we either call tpc_abort or tpc_finish. It is OK - # to call these multiple times, as the storage is - # required to ignore these calls if tpc_begin has not - # been called. - - ncommitted=0 + ncommitted = 0 try: - for o in objects: - j=getattr(o, '_p_jar', o) - if j is not None: - i=id(j) - if not jars.has_key(i): - jars[i]=j - if subtransaction: - - # If a jar does not support subtransactions, - # we need to save it away to be committed in - # the outer transaction. - try: j.tpc_begin(self, subtransaction) - except TypeError: - j.tpc_begin(self) - - if hasattr(j, 'commit_sub'): - subj[i]=j - else: - if self._non_st_objects is None: - self._non_st_objects = [] - self._non_st_objects.append(o) - continue - - else: - j.tpc_begin(self) - j.commit(o,self) - ncommitted=ncommitted+1 - - # Commit work done in subtransactions - while subjars: - j=subjars.pop() - i=id(j) - if not jars.has_key(i): - jars[i]=j - - j.commit_sub(self) + ncommitted += self._commit_objects(objects, jars, + subtransaction, subj) + + self._commit_subtrans(jars, subjars) jarsv = jars.values() for jar in jarsv: if not subtransaction: - try: jar=jar.tpc_vote - except: pass - else: jar(self) # last chance to bail - - try: - # Try to finish one jar, since we may be able to - # recover if the first one fails. - if jarsv: - jarsv[-1].tpc_finish(self) # This should never fail - jarsv.pop() # It didn't, so it's taken care of. - except: - # Bug if it does, we need to keep track of it - LOG('ZODB', ERROR, - "A storage error occurred in the last phase of a " - "two-phase commit. This shouldn\'t happen. ", - error=sys.exc_info()) - raise - - try: - while jarsv: - jarsv[-1].tpc_finish(self) # This should never fail - jarsv.pop() # It didn't, so it's taken care of. - except: - # Bug if it does, we need to yell FIRE! - # Someone finished, so don't allow any more - # work without at least a restart! - hosed = 1 - LOG('ZODB', PANIC, - "A storage error occurred in the last phase of a " - "two-phase commit. This shouldn\'t happen. " - "The application may be in a hosed state, so " - "transactions will not be allowed to commit " - "until the site/storage is reset by a restart. ", - error=sys.exc_info()) - raise - + try: + vote = jar.tpc_vote + except: + pass + else: + vote(self) # last chance to bail + + # Try to finish one jar, since we may be able to + # recover if the first one fails. + self._finish_one(jarsv) + # Once a single jar has finished, it's a fatal (hosed) + # error if another jar fails. + self._finish_rest(jarsv) except: - t, v, tb = sys.exc_info() - # Ugh, we got an got an error during commit, so we # have to clean up. - - # First, we have to abort any uncommitted objects. - for o in objects[ncommitted:]: - try: - j = getattr(o, '_p_jar', o) - if j is not None: - j.abort(o, self) - except: - pass - - # Then, we unwind TPC for the jars that began it. + exc_info = sys.exc_info() if jarsv is None: jarsv = jars.values() - for j in jarsv: - try: - j.tpc_abort(self) # This should never fail - except: - LOG('ZODB', ERROR, - "A storage error occured during object abort " - "This shouldn't happen. ", - error=sys.exc_info()) - - # Ugh, we need to abort work done in sub-transactions. - while subjars: - j = subjars.pop() - try: - j.abort_sub(self) # This should never fail - except: - LOG('ZODB', ERROR, - "A storage error occured during sub-transaction " - "object abort. This shouldn't happen.", - error=sys.exc_info()) - - raise t, v, tb - + self._commit_error(exc_info, objects, ncommitted, + jarsv, subjars) finally: - tb = None del objects[:] # clear registered if not subtransaction and self._id is not None: free_transaction() + def _commit_objects(self, objects, jars, subtransaction, subj): + # commit objects and return number of commits + ncommitted = 0 + for o in objects: + j = getattr(o, '_p_jar', o) + if j is not None: + i = id(j) + if not jars.has_key(i): + jars[i] = j + + if subtransaction: + # If a jar does not support subtransactions, + # we need to save it away to be committed in + # the outer transaction. + try: + j.tpc_begin(self, subtransaction) + except TypeError: + j.tpc_begin(self) + + if hasattr(j, 'commit_sub'): + subj[i] = j + else: + if self._non_st_objects is None: + self._non_st_objects = [] + self._non_st_objects.append(o) + continue + else: + j.tpc_begin(self) + j.commit(o, self) + ncommitted += 1 + return ncommitted + + def _commit_subtrans(self, jars, subjars): + # Commit work done in subtransactions + while subjars: + j = subjars.pop() + i = id(j) + if not jars.has_key(i): + jars[i] = j + j.commit_sub(self) + + def _finish_one(self, jarsv): + try: + if jarsv: + jarsv[-1].tpc_finish(self) # This should never fail + jarsv.pop() # It didn't, so it's taken care of. + except: + # Bug if it does, we need to keep track of it + LOG('ZODB', ERROR, + "A storage error occurred in the last phase of a " + "two-phase commit. This shouldn\'t happen. ", + error=sys.exc_info()) + raise + + def _finish_rest(self, jarsv): + global hosed + try: + while jarsv: + jarsv[-1].tpc_finish(self) # This should never fail + jarsv.pop() # It didn't, so it's taken care of. + except: + # Bug if it does, we need to yell FIRE! + # Someone finished, so don't allow any more + # work without at least a restart! + hosed = 1 + LOG('ZODB', PANIC, + "A storage error occurred in the last phase of a " + "two-phase commit. This shouldn\'t happen. " + "The application may be in a hosed state, so " + "transactions will not be allowed to commit " + "until the site/storage is reset by a restart. ", + error=sys.exc_info()) + raise + + def _commit_error(self, (t, v, tb), + objects, ncommitted, jarsv, subjars): + # handle an exception raised during commit + # takes sys.exc_info() as argument + + # First, we have to abort any uncommitted objects. + for o in objects[ncommitted:]: + try: + j = getattr(o, '_p_jar', o) + if j is not None: + j.abort(o, self) + except: + pass + + # Then, we unwind TPC for the jars that began it. + for j in jarsv: + try: + j.tpc_abort(self) # This should never fail + except: + LOG('ZODB', ERROR, + "A storage error occured during object abort. This " + "shouldn't happen. ", error=sys.exc_info()) + + # Ugh, we need to abort work done in sub-transactions. + while subjars: + j = subjars.pop() + try: + j.abort_sub(self) # This should never fail + except: + LOG('ZODB', ERROR, + "A storage error occured during sub-transaction " + "object abort. This shouldn't happen.", + error=sys.exc_info()) + + raise t, v, tb + def register(self,object): 'Register the given object for transaction control.' self._append(object) @@ -350,6 +353,20 @@ if ext is None: ext=self._extension={} ext[name]=value + +hosed_msg = \ +"""A serious error, which was probably a system error, +occurred in a previous database transaction. This +application may be in an invalid state and must be +restarted before database updates can be allowed. + +Beware though that if the error was due to a serious +system problem, such as a disk full condition, then +the application may not come up until you deal with +the system problem. See your application log for +information on the error that lead to this problem. +""" + ############################################################################ From fdrake@acm.org Fri Apr 12 21:09:05 2002 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Fri, 12 Apr 2002 16:09:05 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/PageTemplates - ZopePageTemplate.py:1.34 Message-ID: <200204122009.g3CK95h30214@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/PageTemplates In directory cvs.zope.org:/tmp/cvs-serv30207 Modified Files: ZopePageTemplate.py Log Message: Minor code cleanliness nit. === Zope/lib/python/Products/PageTemplates/ZopePageTemplate.py 1.33 => 1.34 === import os, AccessControl, Acquisition, sys +from types import StringType from Globals import DTMLFile, ImageFile, MessageDialog, package_home from zLOG import LOG, ERROR, INFO from OFS.SimpleItem import SimpleItem @@ -128,8 +129,8 @@ """Replace the document with the text in file.""" if SUPPORTS_WEBDAV_LOCKS and self.wl_isLocked(): raise ResourceLockedError, "File is locked via WebDAV" - - if type(file) is not type(''): + + if isinstance(file, StringType): if not file: raise ValueError, 'File not specified' file = file.read() From fdrake@acm.org Fri Apr 12 21:11:01 2002 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Fri, 12 Apr 2002 16:11:01 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/PageTemplates - ZopePageTemplate.py:1.35 Message-ID: <200204122011.g3CKB1i30388@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/PageTemplates In directory cvs.zope.org:/tmp/cvs-serv30360 Modified Files: ZopePageTemplate.py Log Message: But no need to introduce a bug in the process! === Zope/lib/python/Products/PageTemplates/ZopePageTemplate.py 1.34 => 1.35 === raise ResourceLockedError, "File is locked via WebDAV" - if isinstance(file, StringType): + if not isinstance(file, StringType): if not file: raise ValueError, 'File not specified' file = file.read() From casey@zope.com Fri Apr 12 21:19:03 2002 From: casey@zope.com (Casey Duncan) Date: Fri, 12 Apr 2002 16:19:03 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - DTMLMethod.py:1.77 Message-ID: <200204122019.g3CKJ3H32718@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv32529/OFS Modified Files: DTMLMethod.py Log Message: New wider/narrower implementation. Allows you to alternately use percentages or absolute column widths. You can set this in the standard prefs. Still only works for editing DTML right now. === Zope/lib/python/OFS/DTMLMethod.py 1.76 => 1.77 === dr,dc = self._size_changes[SUBMIT] - rows=max(1,int(dtpref_rows)+dr) - cols=max(35,int(dtpref_cols)+dc) + rows=str(max(1,int(dtpref_rows)+dr)) + + if dtpref_cols[-1]=='%': + cols= str(min(100, max(25,int(dtpref_cols[:-1])+dc)))+'%' + else: + cols=str(max(35,int(dtpref_cols)+dc)) + e=(DateTime('GMT') + 365).rfc822() resp=REQUEST['RESPONSE'] resp.setCookie('dtpref_rows',str(rows),path='/',expires=e) @@ -231,7 +236,7 @@ self,REQUEST,title=title,__str__=self.quotedHTML(data), dtpref_cols=cols,dtpref_rows=rows) - def manage_edit(self,data,title,SUBMIT='Change',dtpref_cols='70', + def manage_edit(self,data,title,SUBMIT='Change',dtpref_cols='100%', dtpref_rows='20',REQUEST=None): """ Replaces a Documents contents with Data, Title with Title. From casey@zope.com Fri Apr 12 21:19:03 2002 From: casey@zope.com (Casey Duncan) Date: Fri, 12 Apr 2002 16:19:03 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS/dtml - documentEdit.dtml:1.8 Message-ID: <200204122019.g3CKJ3k32726@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS/dtml In directory cvs.zope.org:/tmp/cvs-serv32529/OFS/dtml Modified Files: documentEdit.dtml Log Message: New wider/narrower implementation. Allows you to alternately use percentages or absolute column widths. You can set this in the standard prefs. Still only works for editing DTML right now. === Zope/lib/python/OFS/dtml/documentEdit.dtml 1.7 => 1.8 ===
- - + + + + + +
@@ -78,8 +80,7 @@
- " size="6" /> +
- " size="6" /> +
@@ -100,14 +100,19 @@ -

+

+ + + + + +
- - -

+ From shane@cvs.zope.org Fri Apr 12 21:51:14 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 16:51:14 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS/tests - testPublisherFilesystem.py:1.1.2.1 ReadFilesystemTests.py:1.1.2.2 WriteFilesystemTests.py:1.1.2.2 Message-ID: <200204122051.g3CKpE508782@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS/tests In directory cvs.zope.org:/tmp/cvs-serv8322/VFS/tests Modified Files: Tag: Zope3-Server-Branch ReadFilesystemTests.py WriteFilesystemTests.py Added Files: Tag: Zope3-Server-Branch testPublisherFilesystem.py Log Message: Functioning, tested VFS publication === Added File Zope3/lib/python/Zope/Server/VFS/tests/testPublisherFilesystem.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: testPublisherFilesystem.py,v 1.1.2.1 2002/04/12 20:51:13 shane Exp $ """ import unittest from StringIO import StringIO from Zope.Server.VFS.PublisherFileSystem import PublisherFileSystem from Zope.Publisher.VFS.VFSRequest import VFSRequest from Zope.Publisher.DefaultPublication import DefaultPublication from Zope.Publisher.VFS.IVFSFilePublisher import IVFSFilePublisher from Zope.Publisher.VFS.IVFSDirectoryPublisher import IVFSDirectoryPublisher from Zope.Publisher.mapply import mapply from WriteFilesystemTests import WriteFilesystemTests class VFSPublication (DefaultPublication): # This class will not be needed if we move callObject(). def callObject(self, request, ob): method = getattr(ob, request.method) return mapply(method, request.getPositionalArguments(), request) def traverseName(self, request, ob, name): return ob.publishTraverse(request, name) class TestFile: __implements__ = IVFSFilePublisher def __init__(self, data=''): self.data = data def publishTraverse(self, request, name): """See IVFSPublisher.""" raise OSError, 'Cannot traverse TestFiles' def isdir(self): """See IVFSObjectPublisher.""" return 0 def isfile(self): """See IVFSObjectPublisher.""" return 1 def stat(self): """See IVFSObjectPublisher.""" raise NotImplementedError def read(self, mode, outstream, start=0, end=-1): """See IVFSFilePublisher.""" if end >= 0: s = self.data[start:end] else: s = self.data[start:] outstream.write(s) def write(self, mode, instream, start=0): """See IVFSFilePublisher.""" s = instream.read() if 'a' in mode: self.data = self.data + s else: self.data = self.data[:start] + s + self.data[start + len(s):] class TestDirectory: __implements__ = IVFSDirectoryPublisher def __init__(self, items={}): self.items = items.copy() def publishTraverse(self, request, name): """See IVFSPublisher.""" return self.items[name] def isdir(self): """See IVFSObjectPublisher.""" return 1 def isfile(self): """See IVFSObjectPublisher.""" return 0 def stat(self): """See IVFSObjectPublisher.""" raise NotImplementedError def exists(self, name): """See IVFSDirectoryPublisher.""" return self.items.has_key(name) def listdir(self, with_stats=0, pattern='*'): """See IVFSDirectoryPublisher.""" if with_stats or pattern != '*': raise NotImplementedError return self.items.keys() def mkdir(self, name, mode=0777): """See IVFSDirectoryPublisher.""" self.items[name] = TestDirectory() def remove(self, name): """See IVFSDirectoryPublisher.""" del self.items[name] def rmdir(self, name): """See IVFSDirectoryPublisher.""" del self.items[name] def rename(self, old, new): """See IVFSDirectoryPublisher.""" if self.items.has_key(new): raise OSError, 'Name conflict' self.items[new] = self.items[old] del self.items[old] def writefile(self, name, mode, instream, start=0): """See IVFSDirectoryPublisher.""" if not self.items.has_key(name): self.items[name] = TestFile() self.items[name].write(mode, instream, start) def check_writable(self, name): """See IVFSDirectoryPublisher.""" if not self.items.has_key(name): return 1 return self.items[name].isfile() class PublisherFileSystemTests(unittest.TestCase, WriteFilesystemTests): """This test is constructed in a way that it builds up a directory structure, whcih is removed at the end. """ filesystem_class = PublisherFileSystem # XXX for now, the publisher always eats exceptions. check_exceptions = 0 def setUp(self): app = TestDirectory() pub = VFSPublication(app) def request_factory(input_stream, output_steam, env): request = VFSRequest(input_stream, output_steam, env) request.setPublication(pub) return request self.filesystem = PublisherFileSystem(None, request_factory) self.filesystem.mkdir(self.dir_name) s = StringIO(self.file_contents) self.filesystem.writefile(self.file_name, 'w', s) def tearDown(self): pass def test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(PublisherFileSystemTests) if __name__=='__main__': unittest.TextTestRunner().run( test_suite() ) === Zope3/lib/python/Zope/Server/VFS/tests/ReadFilesystemTests.py 1.1.2.1 => 1.1.2.2 === file_contents = 'Lengthen your stride' + check_exceptions = 1 + def testExists(self): self.failUnless(self.filesystem.exists(self.dir_name)) === Zope3/lib/python/Zope/Server/VFS/tests/WriteFilesystemTests.py 1.1.2.1 => 1.1.2.2 === - def testCheckWriteable(self): - # Can't overwrite a directory. - self.assertRaises( - IOError, self.filesystem.check_writable, self.dir_name) + def testCheckWritable(self): + if self.check_exceptions: + # Can't overwrite a directory. + self.assertRaises( + IOError, self.filesystem.check_writable, self.dir_name) # Can overwrite a file. try: self.filesystem.check_writable(self.file_name) From shane@cvs.zope.org Fri Apr 12 21:51:13 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 16:51:13 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - PublisherFileSystem.py:1.1.2.10 Message-ID: <200204122051.g3CKpDi08776@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv8322/VFS Modified Files: Tag: Zope3-Server-Branch PublisherFileSystem.py Log Message: Functioning, tested VFS publication === Zope3/lib/python/Zope/Server/VFS/PublisherFileSystem.py 1.1.2.9 => 1.1.2.10 === + +class NoOutput: + """An output stream lookalike that warns you if you try to + dump anything into it.""" + + def write(self, data): + raise RuntimeError, "Not a writable stream" + + def flush(self): + pass + + close = flush + + + class PublisherFileSystem: """Generic Publisher FileSystem implementation. """ __implements__ = IReadFileSystem, IWriteFileSystem - path_module = os.path - def __init__ (self, credentials, request_factory): self.credentials = credentials self.request_factory = request_factory @@ -48,7 +61,8 @@ env['command'] = command env['path'] = path env['credentials'] = self.credentials - request = self.request_factory(StringIO(''), StringIO(), env) + # NoOutput avoids creating a black hole. + request = self.request_factory(StringIO(''), NoOutput(), env) # Note that publish() calls close() on request, which deletes the # response from the request, so that we need to keep track of it. response = request.getResponse() @@ -73,7 +87,7 @@ def isdir(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) - return self._execute(path, 'isdir', env) + return self._execute(path, 'isdir') def isfile(self, path): @@ -158,10 +172,11 @@ return self._execute(path, 'writefile', env) - def check_writable(self, path, mode): + def check_writable(self, path): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' path = self.translate(path) - env = {'mode': mode} + path, name = os.path.split(path) + env = {'name' : name} return self._execute(path, 'check_writable', env) # @@ -169,34 +184,12 @@ # utility methods - def normalize(self, path): - # watch for the ever-sneaky '/+' path element - path = re.sub('/+', '/', path) - # Someone is trying to get lower than the permitted root. - # We just ignore it. + def translate (self, path): + # Normalize path = os.path.normpath(path) if path.startswith('..'): + # Someone is trying to get lower than the permitted root. + # We just ignore it. path = '/' return path - - def translate(self, path): - """We need to join together three separate path components, - and do it safely. / - use the operating system's path separator. - - We need to be extremly careful to include the cases where a hacker - could attempt to a directory below root! - """ - # Normalize the directory - path = os.sep.join(path.split('/')) - path = self.normalize(self.path_module.join(path)) - # Prepare for joining with root - if not path.startswith('/'): - path = '/' + path - - return path - - - def __repr__(self): - return '' From shane@cvs.zope.org Fri Apr 12 21:52:27 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 16:52:27 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/VFS - IVFSCredentials.py:1.1.2.2 IVFSDirectoryPublisher.py:1.1.2.4 IVFSFilePublisher.py:1.1.2.3 VFSRequest.py:1.1.2.6 InfoPublisher.py:NONE Message-ID: <200204122052.g3CKqRW09362@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/VFS In directory cvs.zope.org:/tmp/cvs-serv9268/VFS Modified Files: Tag: Zope3-Server-Branch IVFSCredentials.py IVFSDirectoryPublisher.py IVFSFilePublisher.py VFSRequest.py Removed Files: Tag: Zope3-Server-Branch InfoPublisher.py Log Message: Minor updates to comments. Also moved the check_writable method to IVFSDirectoryPublisher for now. === Zope3/lib/python/Zope/Publisher/VFS/IVFSCredentials.py 1.1.2.1 => 1.1.2.2 === class IVFSCredentials(Interface): - # XXX Eventially this will be a different method + # XXX Eventually this will be a different method def _authUserPW(): """Return (login, password) if there are basic credentials; return None if there aren't.""" === Zope3/lib/python/Zope/Publisher/VFS/IVFSDirectoryPublisher.py 1.1.2.3 => 1.1.2.4 === """ - def mkdir(name, mode=777): + def mkdir(name, mode=0777): """Create a container with name in this object. """ @@ -49,4 +49,8 @@ """Write a file to the container. If the object does not exist, inspect the content and the file name to create the right object type. + """ + + def check_writable(name): + """Check whether we can write to a subobject. """ === Zope3/lib/python/Zope/Publisher/VFS/IVFSFilePublisher.py 1.1.2.2 => 1.1.2.3 === """Write data specified in instream to object. """ - - def check_writable(mode): - """Check whether we can write to this object. - """ === Zope3/lib/python/Zope/Publisher/VFS/VFSRequest.py 1.1.2.5 => 1.1.2.6 === def _authUserPW(self): 'See Zope.Publisher.VFS.IVFSCredentials.IVFSCredentials' + # XXX This is wrong. Instead of _authUserPW() there should + # be a method of all requests called getCredentials() which + # returns an ICredentials instance. credentials = self._environ['credentials'] return credentials.getUserName(), credentials.getPassword() @@ -83,12 +86,9 @@ else: self._endswithslash = 0 - if path.startswith('/'): - path = path[1:] # XXX Why? Not sure - clean = [] for item in path.split('/'): - if item == '.': + if not item or item == '.': continue elif item == '..': try: del clean[-1] === Removed File Zope3/lib/python/Zope/Publisher/VFS/InfoPublisher.py === From shane@cvs.zope.org Fri Apr 12 22:04:41 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:04:41 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/Views/VFS - VFSContainerView.py:1.1.2.4 Message-ID: <200204122104.g3CL4fs12375@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Views/VFS In directory cvs.zope.org:/tmp/cvs-serv12365/lib/python/Zope/App/OFS/Container/Views/VFS Modified Files: Tag: Zope3-Server-Branch VFSContainerView.py Log Message: Added a cheesy check_writable() and stripped CRs === Zope3/lib/python/Zope/App/OFS/Container/Views/VFS/VFSContainerView.py 1.1.2.3 => 1.1.2.4 === -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -""" - -$Id$ -""" -import fnmatch -import time - -from Zope.ComponentArchitecture import getView -from Zope.Publisher.VFS.IVFSPublisher import IVFSPublisher - -from Zope.Publisher.VFS.IVFSDirectoryPublisher import IVFSDirectoryPublisher -from Zope.App.OFS.Container.IContainer import IContainer - -# XXX hard coded object types. -from Zope.App.OFS.Content.File.File import File -from Zope.App.OFS.Folder.Folder import Folder - -class VFSContainerView: - - __implements__ = IVFSDirectoryPublisher - - - def __init__(self, context): - """ """ - self._container = context - - - ############################################################ - # Implementation methods for interface - # Zope.Publisher.VFS.IVFSDirectoryPublisher - - def exists(self, name): - 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' - return self._container.hasObject(name) - - - def listdir(self, with_stats=0, pattern='*'): - 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' - t = time.time() - file_list = self._container.objectIds() - # filter them using the pattern - file_list = list( - filter(lambda f, p=pattern, fnm=fnmatch.fnmatch: fnm(f, p), - file_list)) - # sort them alphabetically - file_list.sort() - if not with_stats: - result = file_list - else: - result = [] - for file in file_list: - obj = self._container.getObject(file) - size = 0 - # XXX Should be much nicer - if IContainer.isImplementedBy(obj): - dir_mode = 16384 - else: - dir_mode = 0 - if hasattr(obj, 'getSize'): - size = obj.getSize() - stat = (dir_mode, 0, 0, 0, 0, 0, size, t, t, t) - if stat is not None: - result.append((file, stat)) - return result - - - def mkdir(self, name, mode=777): - 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' - if not self._container.hasObject(name): - obj = Folder() - self._container.setObject(name, obj) - - def remove(self, name): - 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' - return self._container.delObject(name) - - def rmdir(self, name): - 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' - return self._container.delObject(name) - - def rename(self, old, new): - 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' - obj = self._container.getObject(old) - self._container.delObject(old) - self._container.setObject(new, obj) - - - def writefile(self, name, mode, instream, start=0): - 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' - # XXX This should become much, much smarter later. Based on the - # data and the file ending, it should pick the right object type. - # *** Waiting for Jim's file extension proposal and code to land *** - if not self._container.hasObject(name): - obj = File() - self._container.setObject(name, obj) - else: - obj = self._container.getObject(name) - - vfs_view = getView(obj, 'vfs', IVFSPublisher) - vfs_view.write(mode, instream, start) - - - ###################################### - # from: Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher - - def isdir(self): - 'See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher' - return 1 - - def isfile(self): - 'See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher' - return 0 - - def stat(self): - 'See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher' - dir_mode = 16384 - t = time.time() - uid = 0 - gid = 0 - return (dir_mode+0, 0, 0, 0, uid, gid, 4096, t, t, t) - - - ###################################### - # from: Zope.Publisher.VFS.IVFSPublisher.IVFSPublisher - - def publishTraverse(self, request, name): - 'See Zope.Publisher.VFS.IVFSPublisher.IVFSPublisher' - return getattr(self, name) - - # - ############################################################ +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" + +$Id$ +""" +import fnmatch +import time + +from Zope.ComponentArchitecture import getView +from Zope.Publisher.VFS.IVFSPublisher import IVFSPublisher + +from Zope.Publisher.VFS.IVFSDirectoryPublisher import IVFSDirectoryPublisher +from Zope.App.OFS.Container.IContainer import IContainer + +# XXX hard coded object types. +from Zope.App.OFS.Content.File.File import File +from Zope.App.OFS.Folder.Folder import Folder + +class VFSContainerView: + + __implements__ = IVFSDirectoryPublisher + + + def __init__(self, context): + """ """ + self._container = context + + + ############################################################ + # Implementation methods for interface + # Zope.Publisher.VFS.IVFSDirectoryPublisher + + def exists(self, name): + 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' + return self._container.hasObject(name) + + + def listdir(self, with_stats=0, pattern='*'): + 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' + t = time.time() + file_list = self._container.objectIds() + # filter them using the pattern + file_list = list( + filter(lambda f, p=pattern, fnm=fnmatch.fnmatch: fnm(f, p), + file_list)) + # sort them alphabetically + file_list.sort() + if not with_stats: + result = file_list + else: + result = [] + for file in file_list: + obj = self._container.getObject(file) + size = 0 + # XXX Should be much nicer + if IContainer.isImplementedBy(obj): + dir_mode = 16384 + else: + dir_mode = 0 + if hasattr(obj, 'getSize'): + size = obj.getSize() + stat = (dir_mode, 0, 0, 0, 0, 0, size, t, t, t) + if stat is not None: + result.append((file, stat)) + return result + + + def mkdir(self, name, mode=777): + 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' + if not self._container.hasObject(name): + obj = Folder() + self._container.setObject(name, obj) + + def remove(self, name): + 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' + return self._container.delObject(name) + + def rmdir(self, name): + 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' + return self._container.delObject(name) + + def rename(self, old, new): + 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' + obj = self._container.getObject(old) + self._container.delObject(old) + self._container.setObject(new, obj) + + + def writefile(self, name, mode, instream, start=0): + 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' + # XXX This should become much, much smarter later. Based on the + # data and the file ending, it should pick the right object type. + # *** Waiting for Jim's file extension proposal and code to land *** + if not self._container.hasObject(name): + obj = File() + self._container.setObject(name, obj) + else: + obj = self._container.getObject(name) + + vfs_view = getView(obj, 'vfs', IVFSPublisher) + vfs_view.write(mode, instream, start) + + def check_writable(self, name): + 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' + # XXX Cheesy band aid :-) + return 1 + + + ###################################### + # from: Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher + + def isdir(self): + 'See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher' + return 1 + + def isfile(self): + 'See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher' + return 0 + + def stat(self): + 'See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher' + dir_mode = 16384 + t = time.time() + uid = 0 + gid = 0 + return (dir_mode+0, 0, 0, 0, uid, gid, 4096, t, t, t) + + + ###################################### + # from: Zope.Publisher.VFS.IVFSPublisher.IVFSPublisher + + def publishTraverse(self, request, name): + 'See Zope.Publisher.VFS.IVFSPublisher.IVFSPublisher' + return getattr(self, name) + + # + ############################################################ From shane@cvs.zope.org Fri Apr 12 22:30:49 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:30:49 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container/Views/VFS - VFSContainerView.py:1.1.4.1 __init__.py:1.1.4.1 Message-ID: <200204122130.g3CLUng20890@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container/Views/VFS In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/App/OFS/Container/Views/VFS Added Files: Tag: Zope-3x-branch VFSContainerView.py __init__.py Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/App/OFS/Container/Views/VFS/VFSContainerView.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: VFSContainerView.py,v 1.1.4.1 2002/04/12 21:30:48 shane Exp $ """ import fnmatch import time from Zope.ComponentArchitecture import getView from Zope.Publisher.VFS.IVFSPublisher import IVFSPublisher from Zope.Publisher.VFS.IVFSDirectoryPublisher import IVFSDirectoryPublisher from Zope.App.OFS.Container.IContainer import IContainer # XXX hard coded object types. from Zope.App.OFS.Content.File.File import File from Zope.App.OFS.Folder.Folder import Folder class VFSContainerView: __implements__ = IVFSDirectoryPublisher def __init__(self, context): """ """ self._container = context ############################################################ # Implementation methods for interface # Zope.Publisher.VFS.IVFSDirectoryPublisher def exists(self, name): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' return self._container.hasObject(name) def listdir(self, with_stats=0, pattern='*'): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' t = time.time() file_list = self._container.objectIds() # filter them using the pattern file_list = list( filter(lambda f, p=pattern, fnm=fnmatch.fnmatch: fnm(f, p), file_list)) # sort them alphabetically file_list.sort() if not with_stats: result = file_list else: result = [] for file in file_list: obj = self._container.getObject(file) size = 0 # XXX Should be much nicer if IContainer.isImplementedBy(obj): dir_mode = 16384 else: dir_mode = 0 if hasattr(obj, 'getSize'): size = obj.getSize() stat = (dir_mode, 0, 0, 0, 0, 0, size, t, t, t) if stat is not None: result.append((file, stat)) return result def mkdir(self, name, mode=777): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' if not self._container.hasObject(name): obj = Folder() self._container.setObject(name, obj) def remove(self, name): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' return self._container.delObject(name) def rmdir(self, name): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' return self._container.delObject(name) def rename(self, old, new): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' obj = self._container.getObject(old) self._container.delObject(old) self._container.setObject(new, obj) def writefile(self, name, mode, instream, start=0): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' # XXX This should become much, much smarter later. Based on the # data and the file ending, it should pick the right object type. # *** Waiting for Jim's file extension proposal and code to land *** if not self._container.hasObject(name): obj = File() self._container.setObject(name, obj) else: obj = self._container.getObject(name) vfs_view = getView(obj, 'vfs', IVFSPublisher) vfs_view.write(mode, instream, start) def check_writable(self, name): 'See Zope.Publisher.VFS.IVFSDirectoryPublisher.IVFSDirectoryPublisher' # XXX Cheesy band aid :-) return 1 ###################################### # from: Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher def isdir(self): 'See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher' return 1 def isfile(self): 'See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher' return 0 def stat(self): 'See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher' dir_mode = 16384 t = time.time() uid = 0 gid = 0 return (dir_mode+0, 0, 0, 0, uid, gid, 4096, t, t, t) ###################################### # from: Zope.Publisher.VFS.IVFSPublisher.IVFSPublisher def publishTraverse(self, request, name): 'See Zope.Publisher.VFS.IVFSPublisher.IVFSPublisher' return getattr(self, name) # ############################################################ === Added File Zope3/lib/python/Zope/App/OFS/Container/Views/VFS/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## From shane@cvs.zope.org Fri Apr 12 22:30:50 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:30:50 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/File/Views/VFS - VFSFileView.py:1.1.4.1 __init__.py:1.1.4.1 vfs.zcml:1.1.4.1 Message-ID: <200204122130.g3CLUol20934@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File/Views/VFS In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/App/OFS/Content/File/Views/VFS Added Files: Tag: Zope-3x-branch VFSFileView.py __init__.py vfs.zcml Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/App/OFS/Content/File/Views/VFS/VFSFileView.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: VFSFileView.py,v 1.1.4.1 2002/04/12 21:30:49 shane Exp $ """ import time from Zope.Publisher.VFS.IVFSFilePublisher import IVFSFilePublisher class VFSFileView: __implements__ = IVFSFilePublisher def __init__(self, context): """ """ self._object = context ############################################################ # Implementation methods for interface # Zope.Publisher.VFS.IVFSFilePublisher. def read(self, mode, outstream, start = 0, end = -1): """See Zope.Publisher.VFS.IVFSFilePublisher.IVFSFilePublisher""" data = self._object.getData() try: if start != 0: data = data[start:] if end != -1: data = data[:end] except TypeError: pass outstream.write(data) def write(self, mode, instream, start = 0): """See Zope.Publisher.VFS.IVFSFilePublisher.IVFSFilePublisher""" try: instream.seek(start) except: pass self._object.setData(instream.read()) def check_writable(self, mode): """See Zope.Publisher.VFS.IVFSFilePublisher.IVFSFilePublisher""" return 1 ###################################### # from: Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher def isdir(self): """See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher""" return 0 def isfile(self): """See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher""" return 1 def stat(self): """See Zope.Publisher.VFS.IVFSObjectPublisher.IVFSObjectPublisher""" t = time.time() size = 0 if hasattr(self._object, 'getSize'): size = self._object.getSize() uid = 0 gid = 0 return (0, 0, 0, 0, uid, gid, size, t, t, t) ###################################### # from: Zope.Publisher.VFS.IVFSPublisher.IVFSPublisher def publishTraverse(self, request, name): """See Zope.Publisher.VFS.IVFSPublisher.IVFSPublisher""" return getattr(self, name) # ############################################################ === Added File Zope3/lib/python/Zope/App/OFS/Content/File/Views/VFS/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.4.1 2002/04/12 21:30:49 shane Exp $ """ === Added File Zope3/lib/python/Zope/App/OFS/Content/File/Views/VFS/vfs.zcml === From shane@cvs.zope.org Fri Apr 12 22:30:51 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:30:51 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Folder/Views/VFS - __init__.py:1.1.4.1 vfs.zcml:1.1.4.1 Message-ID: <200204122130.g3CLUpU20953@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Folder/Views/VFS In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/App/OFS/Folder/Views/VFS Added Files: Tag: Zope-3x-branch __init__.py vfs.zcml Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/App/OFS/Folder/Views/VFS/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.4.1 2002/04/12 21:30:50 shane Exp $ """ === Added File Zope3/lib/python/Zope/App/OFS/Folder/Views/VFS/vfs.zcml === From shane@cvs.zope.org Fri Apr 12 22:30:53 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:30:53 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication/VFS - Publication.py:1.1.4.1 __init__.py:1.1.6.1 Message-ID: <200204122130.g3CLUr520980@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/VFS In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/App/ZopePublication/VFS Added Files: Tag: Zope-3x-branch Publication.py __init__.py Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/App/ZopePublication/VFS/Publication.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ $Id: Publication.py,v 1.1.4.1 2002/04/12 21:30:52 shane Exp $ """ from Zope.App.ZopePublication.ZopePublication import ZopePublication from Zope.ComponentArchitecture import getRequestView from Zope.Publisher.Exceptions import NotFound from Zope.Publisher.mapply import mapply class VFSPublication(ZopePublication): """The Publication will do all the work for the VFS""" def callObject(self, request, ob): view = getRequestView(ob, 'vfs', request, self) if view is not self: method = getattr(view, request.method) else: raise NotFound(ob, 'vfs', request) return mapply(method, request.getPositionalArguments(), request) === Added File Zope3/lib/python/Zope/App/ZopePublication/VFS/__init__.py === From shane@cvs.zope.org Fri Apr 12 22:30:55 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:30:55 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/VFS/tests - __init__.py:1.1.4.1 Message-ID: <200204122130.g3CLUtC21018@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/VFS/tests In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Publisher/VFS/tests Added Files: Tag: Zope-3x-branch __init__.py Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/Publisher/VFS/tests/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.4.1 2002/04/12 21:30:53 shane Exp $ """ From shane@cvs.zope.org Fri Apr 12 22:30:55 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:30:55 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/VFS - IVFSCredentials.py:1.1.4.1 IVFSDirectoryPublisher.py:1.1.4.1 IVFSFilePublisher.py:1.1.4.1 IVFSObjectPublisher.py:1.1.4.1 IVFSPublisher.py:1.1.4.1 VFSRequest.py:1.1.4.1 VFSResponse.py:1.1.4.1 __init__.py:1.1.4.1 metaConfigure.py:1.1.4.1 vfs-meta.zcml:1.1.4.1 Message-ID: <200204122130.g3CLUtH21030@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/VFS In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Publisher/VFS Added Files: Tag: Zope-3x-branch IVFSCredentials.py IVFSDirectoryPublisher.py IVFSFilePublisher.py IVFSObjectPublisher.py IVFSPublisher.py VFSRequest.py VFSResponse.py __init__.py metaConfigure.py vfs-meta.zcml Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/Publisher/VFS/IVFSCredentials.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IVFSCredentials.py,v 1.1.4.1 2002/04/12 21:30:53 shane Exp $ """ from Interface import Interface class IVFSCredentials(Interface): # XXX Eventually this will be a different method def _authUserPW(): """Return (login, password) if there are basic credentials; return None if there aren't.""" def unauthorized(challenge): """Issue a 401 Unauthorized error (asking for login/password). The challenge is the value of the WWW-Authenticate header.""" === Added File Zope3/lib/python/Zope/Publisher/VFS/IVFSDirectoryPublisher.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IVFSDirectoryPublisher.py,v 1.1.4.1 2002/04/12 21:30:53 shane Exp $ """ from IVFSObjectPublisher import IVFSObjectPublisher class IVFSDirectoryPublisher(IVFSObjectPublisher): """ """ def exists(name): """Checks whether the name exists. """ def listdir(with_stats=0, pattern='*'): """Returns a sequence of names ot (name, stat) """ def mkdir(name, mode=0777): """Create a container with name in this object. """ def remove(name): """Remove file with naem from this container. """ def rmdir(name): """Remove the container name from this container. """ def rename(old, new): """Rename an object from old name to new name. """ def writefile(name, mode, instream, start=0): """Write a file to the container. If the object does not exist, inspect the content and the file name to create the right object type. """ def check_writable(name): """Check whether we can write to a subobject. """ === Added File Zope3/lib/python/Zope/Publisher/VFS/IVFSFilePublisher.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IVFSFilePublisher.py,v 1.1.4.1 2002/04/12 21:30:53 shane Exp $ """ from IVFSObjectPublisher import IVFSObjectPublisher class IVFSFilePublisher(IVFSObjectPublisher): """This interface describes the necessary methods a VFS view has to implement in order to be used by teh VFS. """ def read(mode, outstream, start=0, end=-1): """Read the content of this object. """ def write(mode, instream, start=0): """Write data specified in instream to object. """ === Added File Zope3/lib/python/Zope/Publisher/VFS/IVFSObjectPublisher.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IVFSObjectPublisher.py,v 1.1.4.1 2002/04/12 21:30:53 shane Exp $ """ from IVFSPublisher import IVFSPublisher class IVFSObjectPublisher(IVFSPublisher): """ """ def isdir(): """Returns true, if the object is a container, namely implements IContainer. For all other cases it returns false. """ def isfile(): """Returns always the oposite of isdir() for the same reasons. """ def stat(): """This method should return the typical file stat information: (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) """ === Added File Zope3/lib/python/Zope/Publisher/VFS/IVFSPublisher.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IVFSPublisher.py,v 1.1.4.1 2002/04/12 21:30:53 shane Exp $ """ from Interface import Interface class IVFSPublisher(Interface): def publishTraverse(request, name): """Lookup a name The request argument is the publisher request object. """ === Added File Zope3/lib/python/Zope/Publisher/VFS/VFSRequest.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ $Id: VFSRequest.py,v 1.1.4.1 2002/04/12 21:30:53 shane Exp $ """ from Zope.Publisher.BaseRequest import BaseRequest from IVFSPublisher import IVFSPublisher from IVFSCredentials import IVFSCredentials from VFSResponse import VFSResponse class VFSRequest(BaseRequest): __implements__ = BaseRequest.__implements__, IVFSCredentials # _viewtype is overridden from the BaseRequest # to implement IVFSPublisher _viewtype = IVFSPublisher def __init__(self, body_instream, outstream, environ, response=None): """ """ super(VFSRequest, self).__init__( body_instream, outstream, environ, response) self._environ = environ self.method = '' self.__setupPath() def _createResponse(self, outstream): """Create a specific XML-RPC response object.""" return VFSResponse(outstream) ############################################################ # Implementation methods for interface # Zope.Publisher.VFS.IVFSCredentials. def _authUserPW(self): 'See Zope.Publisher.VFS.IVFSCredentials.IVFSCredentials' # XXX This is wrong. Instead of _authUserPW() there should # be a method of all requests called getCredentials() which # returns an ICredentials instance. credentials = self._environ['credentials'] return credentials.getUserName(), credentials.getPassword() def unauthorized(self, challenge): 'See Zope.Publisher.VFS.IVFSCredentials.IVFSCredentials' pass # ############################################################ ###################################### # from: Zope.Publisher.IPublisherRequest.IPublisherRequest def processInputs(self): 'See Zope.Publisher.IPublisherRequest.IPublisherRequest' if self._environ.has_key('command'): self.method = self._environ['command'] # ############################################################ def __setupPath(self): path = self.get('path', '/').strip() if path.endswith('/'): path = path[:-1] # XXX Why? Not sure self._endswithslash = 1 else: self._endswithslash = 0 clean = [] for item in path.split('/'): if not item or item == '.': continue elif item == '..': try: del clean[-1] except IndexError: raise NotFound('..') else: clean.append(item) clean.reverse() self.setTraversalStack(clean) self._path_suffix = None def __repr__(self): # Returns a *short* string. return '<%s instance at 0x%x, path=%s>' % ( str(self.__class__), id(self), '/'.join(self._traversal_stack)) === Added File Zope3/lib/python/Zope/Publisher/VFS/VFSResponse.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ $Id: VFSResponse.py,v 1.1.4.1 2002/04/12 21:30:53 shane Exp $ """ from Zope.Publisher.BaseResponse import BaseResponse class VFSResponse(BaseResponse): """VFS response """ def setBody(self, body): """Sets the body of the response It is very important to note that in this case the body may not be just a astring, but any Python object. """ # XXX: Handle exceptions self._body = body def outputBody(self): 'See Zope.Publisher.IPublisherResponse.IPublisherResponse' pass def getResult(self): """ """ return self._getBody() def handleException(self, exc_info): """ """ t, value = exc_info[:2] import traceback traceback.print_tb(exc_info[2]) print t print value self.setBody(value) === Added File Zope3/lib/python/Zope/Publisher/VFS/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.4.1 2002/04/12 21:30:53 shane Exp $ """ === Added File Zope3/lib/python/Zope/Publisher/VFS/metaConfigure.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: metaConfigure.py,v 1.1.4.1 2002/04/12 21:30:53 shane Exp $ """ from Zope.ComponentArchitecture import provideView, setDefaultViewName from Zope.Configuration.Action import Action from IVFSPublisher import IVFSPublisher def view(_context, name, factory, for_=None, layer=''): if for_ is not None: for_ = _context.resolve(for_) factory = map(_context.resolve, factory.split(' ')) return [ Action( discriminator = ('defaultViewName', for_, name, IVFSPublisher), callable = setDefaultViewName, args = (for_, IVFSPublisher, name), ), Action( discriminator = ('view', for_, name, IVFSPublisher, layer), callable = provideView, args = (for_, name, IVFSPublisher, factory, layer), ) ] === Added File Zope3/lib/python/Zope/Publisher/VFS/vfs-meta.zcml === From shane@cvs.zope.org Fri Apr 12 22:30:57 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:30:57 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP/tests - __init__.py:1.1.4.1 testFTPServer.py:1.1.4.1 Message-ID: <200204122130.g3CLUum21056@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP/tests In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/FTP/tests Added Files: Tag: Zope-3x-branch __init__.py testFTPServer.py Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/Server/FTP/tests/__init__.py === # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. """ Unit tests for Zope.Server """ === Added File Zope3/lib/python/Zope/Server/FTP/tests/testFTPServer.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: testFTPServer.py,v 1.1.4.1 2002/04/12 21:30:55 shane Exp $ """ import unittest import tempfile import os from asyncore import socket_map, poll import socket from types import StringType from StringIO import StringIO from threading import Thread from Zope.Server.TaskThreads import ThreadedTaskDispatcher from Zope.Server.FTP.FTPServer import FTPServer from Zope.Server.FTP.FTPStatusMessages import status_msgs from Zope.Server.Adjustments import Adjustments from Zope.Server.ITask import ITask from Zope.Server.VFS.OSFileSystem import OSFileSystem from Zope.Server.FTP.TestFilesystemAccess import TestFilesystemAccess import ftplib from time import sleep, time td = ThreadedTaskDispatcher() LOCALHOST = '127.0.0.1' SERVER_PORT = 0 # Set these port numbers to 0 to auto-bind, or CONNECT_TO_PORT = 0 # use specific numbers to inspect using TCPWatch. my_adj = Adjustments() def retrlines(ftpconn, cmd): res = [] ftpconn.retrlines(cmd, res.append) return ''.join(res) class Tests(unittest.TestCase): def setUp(self): td.setThreadCount(1) self.orig_map_size = len(socket_map) self.root_dir = tempfile.mktemp() os.mkdir(self.root_dir) os.mkdir(os.path.join(self.root_dir, 'test')) fs = OSFileSystem(self.root_dir) fs_access = TestFilesystemAccess(fs) self.server = FTPServer(LOCALHOST, SERVER_PORT, fs_access, task_dispatcher=td, adj=my_adj) if CONNECT_TO_PORT == 0: self.port = self.server.socket.getsockname()[1] else: self.port = CONNECT_TO_PORT self.run_loop = 1 self.counter = 0 self.thread = Thread(target=self.loop) self.thread.start() sleep(0.1) # Give the thread some time to start. def tearDown(self): self.run_loop = 0 self.thread.join() td.shutdown() self.server.close() # Make sure all sockets get closed by asyncore normally. timeout = time() + 2 while 1: if len(socket_map) == self.orig_map_size: # Clean! break if time() >= timeout: self.fail('Leaked a socket: %s' % `socket_map`) break poll(0.1, socket_map) def loop(self): while self.run_loop: self.counter = self.counter + 1 # print 'loop', self.counter poll(0.1, socket_map) def getFTPConnection(self, login=1): ftp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ftp.connect((LOCALHOST, self.port)) result = ftp.recv(10000) self.assertEqual(result, status_msgs['SERVER_READY'] %( 'localhost.localdomain') + '\r\n') if login: ftp.send('USER foo\r\n') self.assertEqual(ftp.recv(1024), status_msgs['PASS_REQUIRED'] +'\r\n') ftp.send('PASS bar\r\n') self.assertEqual(ftp.recv(1024), status_msgs['LOGIN_SUCCESS'] +'\r\n') return ftp def execute(self, commands, login=1): ftp = self.getFTPConnection(login) try: if type(commands) is StringType: commands = (commands,) for command in commands: ftp.send('%s\r\n' %command) result = ftp.recv(10000) #print result[:-2] self.failUnless(result.endswith('\r\n')) finally: ftp.close() return result[:-2] def testABOR(self): self.assertEqual(self.execute('ABOR', 1), status_msgs['TRANSFER_ABORTED']) def testCDUP(self): self.assertEqual(self.execute(('CWD test', 'CDUP'), 1), status_msgs['SUCCESS_250'] %'CDUP') self.assertEqual(self.execute('CDUP', 1), status_msgs['SUCCESS_250'] %'CDUP') def testCWD(self): self.assertEqual(self.execute('CWD test', 1), status_msgs['SUCCESS_250'] %'CWD') self.assertEqual(self.execute('CWD foo', 1), status_msgs['ERR_NO_DIR'] %'/foo') def testDELE(self): open(os.path.join(self.root_dir, 'foo'), 'w').write('blah') self.assertEqual(self.execute('DELE foo', 1), status_msgs['SUCCESS_250'] %'DELE') res = self.execute('DELE bar', 1).split()[0] self.assertEqual(res, '550') self.assertEqual(self.execute('DELE', 1), status_msgs['ERR_ARGS']) def testHELP(self): result = status_msgs['HELP_START'] #+ '\r\n' #result += 'Help goes here somewhen.\r\n' #result += status_msgs['HELP_END'] self.assertEqual(self.execute('HELP', 1), result) def testLIST(self): conn = ftplib.FTP() try: conn.connect(LOCALHOST, self.port) conn.login('foo', 'bar') self.assertRaises(ftplib.Error, retrlines, conn, 'LIST /foo') listing = retrlines(conn, 'LIST') self.assert_(len(listing) > 0) finally: conn.close() # Make sure no garbage was left behind. self.testNOOP() def testNOOP(self): self.assertEqual(self.execute('NOOP', 0), status_msgs['SUCCESS_200'] %'NOOP') self.assertEqual(self.execute('NOOP', 1), status_msgs['SUCCESS_200'] %'NOOP') def testPASS(self): self.assertEqual(self.execute('PASS', 0), status_msgs['LOGIN_MISMATCH']) self.assertEqual(self.execute(('USER blah', 'PASS bar'), 0), status_msgs['LOGIN_MISMATCH']) def testQUIT(self): self.assertEqual(self.execute('QUIT', 0), status_msgs['GOODBYE']) self.assertEqual(self.execute('QUIT', 1), status_msgs['GOODBYE']) def testSTOR(self): conn = ftplib.FTP() try: conn.connect(LOCALHOST, self.port) conn.login('foo', 'bar') fp = StringIO('Speak softly') # Can't overwrite directory self.assertRaises( ftplib.error_perm, conn.storbinary, 'STOR /test', fp) fp = StringIO('Charity never faileth') # Successful write conn.storbinary('STOR /stuff', fp) finally: conn.close() # Make sure no garbage was left behind. self.testNOOP() def testUSER(self): self.assertEqual(self.execute('USER foo', 0), status_msgs['PASS_REQUIRED']) self.assertEqual(self.execute('USER', 0), status_msgs['ERR_ARGS']) def test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(Tests) if __name__=='__main__': unittest.TextTestRunner().run( test_suite() ) From shane@cvs.zope.org Fri Apr 12 22:30:58 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:30:58 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/LineReceiver/tests - __init__.py:1.1.4.1 Message-ID: <200204122130.g3CLUwY21121@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/LineReceiver/tests In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/LineReceiver/tests Added Files: Tag: Zope-3x-branch __init__.py Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/Server/LineReceiver/tests/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.4.1 2002/04/12 21:30:57 shane Exp $ """ From shane@cvs.zope.org Fri Apr 12 22:30:58 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:30:58 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/HTTP/tests - __init__.py:1.1.4.1 testHTTPServer.py:1.1.4.1 testPublisherServer.py:1.1.4.1 Message-ID: <200204122130.g3CLUw921106@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/HTTP/tests In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/HTTP/tests Added Files: Tag: Zope-3x-branch __init__.py testHTTPServer.py testPublisherServer.py Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/Server/HTTP/tests/__init__.py === # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. """ Unit tests for Zope.Server """ === Added File Zope3/lib/python/Zope/Server/HTTP/tests/testHTTPServer.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: testHTTPServer.py,v 1.1.4.1 2002/04/12 21:30:56 shane Exp $ """ import unittest from asyncore import socket_map, poll import socket from threading import Thread from Zope.Server.TaskThreads import ThreadedTaskDispatcher from Zope.Server.HTTP.HTTPServer import HTTPServer from Zope.Server.Adjustments import Adjustments from Zope.Server.ITask import ITask from httplib import HTTPConnection from httplib import HTTPResponse as ClientHTTPResponse from time import sleep, time td = ThreadedTaskDispatcher() LOCALHOST = '127.0.0.1' SERVER_PORT = 0 # Set these port numbers to 0 to auto-bind, or CONNECT_TO_PORT = 0 # use specific numbers to inspect using TCPWatch. my_adj = Adjustments() # Reduce overflows to make testing easier. my_adj.outbuf_overflow = 10000 my_adj.inbuf_overflow = 10000 class EchoHTTPServer(HTTPServer): def executeRequest(self, task): headers = task.request_data.headers if headers.has_key('CONTENT_LENGTH'): cl = headers['CONTENT_LENGTH'] task.response_headers['Content-Length'] = cl instream = task.request_data.getBodyStream() while 1: data = instream.read(8192) if not data: break task.write(data) class SleepingTask: __implements__ = ITask def service(self): sleep(0.2) def cancel(self): pass def defer(self): pass class Tests(unittest.TestCase): def setUp(self): td.setThreadCount(4) self.orig_map_size = len(socket_map) self.server = EchoHTTPServer(LOCALHOST, SERVER_PORT, task_dispatcher=td, adj=my_adj) if CONNECT_TO_PORT == 0: self.port = self.server.socket.getsockname()[1] else: self.port = CONNECT_TO_PORT self.run_loop = 1 self.counter = 0 self.thread = Thread(target=self.loop) self.thread.start() sleep(0.1) # Give the thread some time to start. def tearDown(self): self.run_loop = 0 self.thread.join() td.shutdown() self.server.close() # Make sure all sockets get closed by asyncore normally. timeout = time() + 5 while 1: if len(socket_map) == self.orig_map_size: # Clean! break if time() >= timeout: self.fail('Leaked a socket: %s' % `socket_map`) poll(0.1, socket_map) def loop(self): while self.run_loop: self.counter = self.counter + 1 #print 'loop', self.counter poll(0.1, socket_map) def testEchoResponse(self, h=None, add_headers=None, body=''): if h is None: h = HTTPConnection(LOCALHOST, self.port) h.putrequest('GET', '/') h.putheader('Accept', 'text/plain') if add_headers: for k, v in add_headers.items(): h.putheader(k, v) if body: h.putheader('Content-Length', str(int(len(body)))) h.endheaders() if body: h.send(body) response = h.getresponse() self.failUnlessEqual(int(response.status), 200) length = int(response.getheader('Content-Length', '0')) response_body = response.read() self.failUnlessEqual(length, len(response_body)) self.failUnlessEqual(response_body, body) def testMultipleRequestsWithoutBody(self): # Tests the use of multiple requests in a single connection. h = HTTPConnection(LOCALHOST, self.port) for n in range(3): self.testEchoResponse(h) self.testEchoResponse(h, {'Connection': 'close'}) def testMultipleRequestsWithBody(self): # Tests the use of multiple requests in a single connection. h = HTTPConnection(LOCALHOST, self.port) for n in range(3): self.testEchoResponse(h, body='Hello, world!') self.testEchoResponse(h, {'Connection': 'close'}) def testPipelining(self): # Tests the use of several requests issued at once. s = ("GET / HTTP/1.0\r\n" "Connection: %s\r\n" "Content-Length: %d\r\n" "\r\n" "%s") to_send = '' count = 25 for n in range(count): body = "Response #%d\r\n" % (n + 1) if n + 1 < count: conn = 'keep-alive' else: conn = 'close' to_send += s % (conn, len(body), body) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((LOCALHOST, self.port)) sock.send(to_send) for n in range(count): expect_body = "Response #%d\r\n" % (n + 1) response = ClientHTTPResponse(sock) response.begin() self.failUnlessEqual(int(response.status), 200) length = int(response.getheader('Content-Length', '0')) response_body = response.read(length) self.failUnlessEqual(length, len(response_body)) self.failUnlessEqual(response_body, expect_body) def testWithoutCRLF(self): # Tests the use of just newlines rather than CR/LFs. data = "Echo\nthis\r\nplease" s = ("GET / HTTP/1.0\n" "Connection: close\n" "Content-Length: %d\n" "\n" "%s") % (len(data), data) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((LOCALHOST, self.port)) sock.send(s) response = ClientHTTPResponse(sock) response.begin() self.failUnlessEqual(int(response.status), 200) length = int(response.getheader('Content-Length', '0')) response_body = response.read(length) self.failUnlessEqual(length, len(data)) self.failUnlessEqual(response_body, data) def testLargeBody(self): # Tests the use of multiple requests in a single connection. h = HTTPConnection(LOCALHOST, self.port) s = 'This string has 32 characters.\r\n' * 32 # 1024 characters. self.testEchoResponse(h, body=(s * 1024)) # 1 MB self.testEchoResponse(h, {'Connection': 'close'}, body=(s * 100)) # 100 KB def testManyClients(self): conns = [] for n in range(50): # Linux kernel (2.4.8) doesn't like > 128 ? #print 'open', n, clock() h = HTTPConnection(LOCALHOST, self.port) #h.debuglevel = 1 h.putrequest('GET', '/') h.putheader('Accept', 'text/plain') h.endheaders() conns.append(h) # If you uncomment the next line, you can raise the # number of connections much higher without running # into delays. #sleep(0.01) responses = [] for h in conns: response = h.getresponse() self.failUnlessEqual(response.status, 200) responses.append(response) for response in responses: response.read() def testThreading(self): # Ensures the correct number of threads keep running. for n in range(4): td.addTask(SleepingTask()) # Try to confuse the task manager. td.setThreadCount(2) td.setThreadCount(1) sleep(0.5) # There should be 1 still running. self.failUnlessEqual(len(td.threads), 1) def testChunkingRequestWithoutContent(self): h = HTTPConnection(LOCALHOST, self.port) h.putrequest('GET', '/') h.putheader('Accept', 'text/plain') h.putheader('Transfer-Encoding', 'chunked') h.endheaders() h.send("0\r\n\r\n") response = h.getresponse() self.failUnlessEqual(int(response.status), 200) response_body = response.read() self.failUnlessEqual(response_body, '') def testChunkingRequestWithContent(self): control_line="20;\r\n" # 20 hex = 32 dec s = 'This string has 32 characters.\r\n' expect = s * 12 h = HTTPConnection(LOCALHOST, self.port) h.putrequest('GET', '/') h.putheader('Accept', 'text/plain') h.putheader('Transfer-Encoding', 'chunked') h.endheaders() for n in range(12): h.send(control_line) h.send(s) h.send("0\r\n\r\n") response = h.getresponse() self.failUnlessEqual(int(response.status), 200) response_body = response.read() self.failUnlessEqual(response_body, expect) def test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(Tests) if __name__=='__main__': unittest.TextTestRunner().run( test_suite() ) === Added File Zope3/lib/python/Zope/Server/HTTP/tests/testPublisherServer.py === ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 1.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. ############################################################################## """ $Id: testPublisherServer.py,v 1.1.4.1 2002/04/12 21:30:56 shane Exp $ """ import unittest from asyncore import socket_map, poll import sys from threading import Thread from Zope.Server.TaskThreads import ThreadedTaskDispatcher from Zope.Server.HTTP.PublisherHTTPServer import PublisherHTTPServer from Zope.Publisher.Browser.BrowserRequest import BrowserRequest from Zope.Publisher.DefaultPublication import DefaultPublication from Zope.Publisher.Exceptions import Redirect, Retry from Zope.Publisher.HTTP import HTTPRequest from httplib import HTTPConnection from time import sleep, time td = ThreadedTaskDispatcher() LOCALHOST = '127.0.0.1' HTTPRequest.STAGGER_RETRIES = 0 # Don't pause. class Conflict (Exception): """ Pseudo ZODB conflict error. """ class PublicationWithConflict(DefaultPublication): def handleException(self, request, exc_info, retry_allowed=1): if exc_info[0] is Conflict and retry_allowed: # This simulates a ZODB retry. raise Retry(exc_info) else: DefaultPublication.handleException(self, request, exc_info, retry_allowed) class tested_object: " " tries = 0 def __call__(self, REQUEST): return 'URL invoked: %s' % REQUEST.URL def redirect_method(self, REQUEST): "Generates a redirect using the redirect() method." REQUEST.getResponse().redirect("http://somewhere.com/redirect") def redirect_exception(self): "Generates a redirect using an exception." raise Redirect("http://somewhere.com/exception") def conflict(self, REQUEST, wait_tries): """ Returns 202 status only after (wait_tries) tries. """ if self.tries >= int(wait_tries): raise "Accepted" else: self.tries += 1 raise Conflict class Tests(unittest.TestCase): def setUp(self): obj = tested_object() obj.folder = tested_object() obj.folder.item = tested_object() obj._protected = tested_object() pub = PublicationWithConflict(obj) def request_factory(input_stream, output_steam, env): request = BrowserRequest(input_stream, output_steam, env) request.setPublication(pub) return request td.setThreadCount(4) # Bind to any port on localhost. self.server = PublisherHTTPServer(request_factory, 'Browser', LOCALHOST, 0, task_dispatcher=td) self.port = self.server.socket.getsockname()[1] self.run_loop = 1 self.thread = Thread(target=self.loop) self.thread.start() sleep(0.1) # Give the thread some time to start. def tearDown(self): self.run_loop = 0 self.thread.join() td.shutdown() self.server.close() def loop(self): while self.run_loop: poll(0.1, socket_map) def testResponse(self, path='/', status_expected=200, add_headers=None, request_body=''): h = HTTPConnection(LOCALHOST, self.port) h.putrequest('GET', path) h.putheader('Accept', 'text/plain') if add_headers: for k, v in add_headers.items(): h.putheader(k, v) if request_body: h.putheader('Content-Length', str(int(len(request_body)))) h.endheaders() if request_body: h.send(request_body) response = h.getresponse() length = int(response.getheader('Content-Length', '0')) if length: response_body = response.read(length) else: response_body = '' # Please do not disable the status code check. It must work. self.failUnlessEqual(int(response.status), status_expected) self.failUnlessEqual(length, len(response_body)) if (status_expected == 200): if path == '/': path = '' expect_response = 'URL invoked: http://%s:%d%s' % (LOCALHOST, self.port, path) self.failUnlessEqual(response_body, expect_response) def testDeeperPath(self): self.testResponse(path='/folder/item') def testNotFound(self): self.testResponse(path='/foo/bar', status_expected=404) def testUnauthorized(self): self.testResponse(path='/_protected', status_expected=401) def testRedirectMethod(self): self.testResponse(path='/redirect_method', status_expected=302) def testRedirectException(self): self.testResponse(path='/redirect_exception', status_expected=302) self.testResponse(path='/folder/redirect_exception', status_expected=302) def testConflictRetry(self): # Expect the "Accepted" response since the retries will succeed. self.testResponse(path='/conflict?wait_tries=2', status_expected=202) def testFailedConflictRetry(self): # Expect a "Conflict" response since there will be too many # conflicts. self.testResponse(path='/conflict?wait_tries=10', status_expected=409) def test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(Tests) if __name__=='__main__': unittest.TextTestRunner().run( test_suite() ) From shane@cvs.zope.org Fri Apr 12 22:30:58 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:30:58 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/LineReceiver - LineCommandParser.py:1.1.4.1 LineServerChannel.py:1.1.4.1 LineTask.py:1.1.4.1 __init__.py:1.1.4.1 Message-ID: <200204122130.g3CLUwH21119@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/LineReceiver In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/LineReceiver Added Files: Tag: Zope-3x-branch LineCommandParser.py LineServerChannel.py LineTask.py __init__.py Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/Server/LineReceiver/LineCommandParser.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: LineCommandParser.py,v 1.1.4.1 2002/04/12 21:30:57 shane Exp $ """ from Zope.Server.IStreamConsumer import IStreamConsumer class LineCommandParser: """Line Command parser. Arguments are left alone for now.""" __implements__ = IStreamConsumer # See Zope.Server.IStreamConsumer.IStreamConsumer completed = 0 inbuf = '' cmd = '' args = '' empty = 0 max_line_length = 1024 # Not a hard limit def __init__(self, adj): """ adj is an Adjustments object. """ self.adj = adj ############################################################ # Implementation methods for interface # Zope.Server.IStreamConsumer def received(self, data): 'See Zope.Server.IStreamConsumer.IStreamConsumer' if self.completed: return 0 # Can't consume any more. pos = data.find('\n') datalen = len(data) if pos < 0: self.inbuf = self.inbuf + data if len(self.inbuf) > self.max_line_length: # Don't accept any more. self.completed = 1 return datalen else: # Line finished. s = data[:pos + 1] self.inbuf = self.inbuf + s self.completed = 1 line = self.inbuf.strip() self.parseLine(line) return len(s) # ############################################################ def parseLine(self, line): parts = line.split(' ', 1) if len(parts) == 2: self.cmd, self.args = parts else: self.cmd = parts[0] === Added File Zope3/lib/python/Zope/Server/LineReceiver/LineServerChannel.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: LineServerChannel.py,v 1.1.4.1 2002/04/12 21:30:57 shane Exp $ """ import os import stat import socket import sys import time from Zope.Server.ServerChannelBase import ServerChannelBase from LineCommandParser import LineCommandParser from LineTask import LineTask DEBUG = os.environ.get('ZOPE_SERVER_DEBUG') class LineServerChannel(ServerChannelBase): """The Line Server Channel represents a connection to a particular client. We can therefore store information here.""" __implements__ = ServerChannelBase.__implements__ # Wrapper class that is used to execute a command in a different thread task_class = LineTask # Class that is being initialized to parse the input parser_class = LineCommandParser # List of commands that are always available special_commands = ('cmd_quit') # Commands that are run in a separate thread thread_commands = () # Define the authentication status of the channel. Note that only the # "special commands" can be executed without having authenticated. authenticated = 0 # Define the reply code for non-authenticated responses not_auth_reply = 'LOGIN_REQUIRED' # Define the reply code for an unrecognized command unknown_reply = 'CMD_UNKNOWN' # Define the error message that occurs, when the reply code was not found. reply_error = '500 Unknown Reply Code: %s.' # Define the status messages status_messages = { 'CMD_UNKNOWN' : "500 '%s': command not understood.", 'INTERNAL_ERROR' : "500 Internal error: %s", 'LOGIN_REQUIRED' : '530 Please log in with USER and PASS', } def process_request(self, command): """Processes a command. Some commands use an alternate thread. """ assert isinstance(command, LineCommandParser) cmd = command.cmd method = 'cmd_' + cmd.lower() if ( not self.authenticated and method not in self.special_commands): # The user is not logged in, therefore don't allow anything self.reply(self.not_auth_reply) elif method in self.thread_commands: # Process in another thread. return self.task_class(self, command, method) elif hasattr(self, method): try: getattr(self, method)(command.args) except: self.exception() else: self.reply(self.unknown_reply, cmd.upper()) return None def reply(self, code, args=(), flush=1): """ """ try: msg = self.status_messages[code] %args except: msg = self.reply_error %code self.write('%s\r\n' %msg) if flush: self.flush(0) # XXX: Some logging should go on here. def exception(self): if DEBUG: import traceback traceback.print_exc() t, v = sys.exc_info()[:2] try: info = '%s: %s' % (getattr(t, '__name__', t), v) except: info = str(t) self.reply('INTERNAL_ERROR', info) self.handle_error() === Added File Zope3/lib/python/Zope/Server/LineReceiver/LineTask.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: LineTask.py,v 1.1.4.1 2002/04/12 21:30:57 shane Exp $ """ import socket import time from Zope.Server.ITask import ITask class LineTask: """This is a generic task that can be used with command line protocols to handle commands in a separate thread. """ __implements__ = ITask def __init__(self, channel, command, m_name): self.channel = channel self.m_name = m_name self.args = command.args self.close_on_finish = 0 ############################################################ # Implementation methods for interface # Zope.Server.ITask def service(self): """Called to execute the task. """ try: try: self.start() getattr(self.channel, self.m_name)(self.args) self.finish() except socket.error: self.close_on_finish = 1 if self.channel.adj.log_socket_errors: raise except: self.channel.exception() finally: self.channel.end_task(self.close_on_finish) def cancel(self): 'See Zope.Server.ITask.ITask' self.channel.close_when_done() def defer(self): 'See Zope.Server.ITask.ITask' pass # ############################################################ def start(self): now = time.time() self.start_time = now def finish(self): hit_log = self.channel.server.hit_log if hit_log is not None: hit_log.log(self) === Added File Zope3/lib/python/Zope/Server/LineReceiver/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.4.1 2002/04/12 21:30:57 shane Exp $ """ From shane@cvs.zope.org Fri Apr 12 22:30:57 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:30:57 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/FTP - CommonFTPActivityLogger.py:1.1.4.1 FTPServer.py:1.1.4.1 FTPServerChannel.py:1.1.4.1 FTPStatusMessages.py:1.1.4.1 IFTPCommandHandler.py:1.1.4.1 OSEmulators.py:1.1.4.1 PassiveAcceptor.py:1.1.4.1 PublisherFTPServer.py:1.1.4.1 PublisherFTPServerChannel.py:1.1.4.1 PublisherFTPTask.py:1.1.4.1 PublisherFilesystemAccess.py:1.1.4.1 RecvChannel.py:1.1.4.1 TestFilesystemAccess.py:1.1.4.1 XmitChannel.py:1.1.4.1 __init__.py:1.1.4.1 Message-ID: <200204122130.g3CLUvP21073@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/FTP In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/FTP Added Files: Tag: Zope-3x-branch CommonFTPActivityLogger.py FTPServer.py FTPServerChannel.py FTPStatusMessages.py IFTPCommandHandler.py OSEmulators.py PassiveAcceptor.py PublisherFTPServer.py PublisherFTPServerChannel.py PublisherFTPTask.py PublisherFilesystemAccess.py RecvChannel.py TestFilesystemAccess.py XmitChannel.py __init__.py Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/Server/FTP/CommonFTPActivityLogger.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: CommonFTPActivityLogger.py,v 1.1.4.1 2002/04/12 21:30:55 shane Exp $ """ import time import sys from Zope.Server.Logger.FileLogger import FileLogger from Zope.Server.Logger.ResolvingLogger import ResolvingLogger from Zope.Server.Logger.UnresolvingLogger import UnresolvingLogger class CommonFTPActivityLogger: """Outputs hits in common HTTP log format. """ def __init__(self, logger_object=None, resolver=None): if logger_object is None: logger_object = FileLogger(sys.stdout) if resolver is not None: self.output = ResolvingLogger(resolver, logger_object) else: self.output = UnresolvingLogger(logger_object) def log(self, task): """ Receives a completed task and logs it in the common log format. """ now = time.localtime(time.time()) message = '%s [%s] "%s %s"' %(task.channel.username, time.strftime('%Y/%m/%d %H:%M', now), task.m_name[4:].upper(), task.channel.cwd, ) self.output.log('127.0.0.1', message) === Added File Zope3/lib/python/Zope/Server/FTP/FTPServer.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: FTPServer.py,v 1.1.4.1 2002/04/12 21:30:55 shane Exp $ """ import asyncore from FTPServerChannel import FTPServerChannel from Zope.Server.ServerBase import ServerBase from Zope.Server.VFS.IFilesystemAccess import IFilesystemAccess class FTPServer(ServerBase): """Generic FTP Server""" channel_class = FTPServerChannel SERVER_IDENT = 'Zope.Server.FTPServer' def __init__(self, ip, port, fs_access, *args, **kw): assert IFilesystemAccess.isImplementedBy(fs_access) self.fs_access = fs_access super(FTPServer, self).__init__(ip, port, *args, **kw) if __name__ == '__main__': from Zope.Server.TaskThreads import ThreadedTaskDispatcher from Zope.Server.VFS.OSFileSystem import OSFileSystem from Zope.Server.VFS.TestFilesystemAccess import TestFilesystemAccess td = ThreadedTaskDispatcher() td.setThreadCount(4) fs = OSFileSystem('/') fs_access = TestFilesystemAccess(fs) FTPServer('', 8021, fs_access, task_dispatcher=td) try: while 1: asyncore.poll(5) print 'active channels:', FTPServerChannel.active_channels except KeyboardInterrupt: print 'shutting down...' td.shutdown() === Added File Zope3/lib/python/Zope/Server/FTP/FTPServerChannel.py === (432/532 lines abridged) ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: FTPServerChannel.py,v 1.1.4.1 2002/04/12 21:30:55 shane Exp $ """ import posixpath import stat import sys import socket import time from Zope.Server.LineReceiver.LineServerChannel import LineServerChannel from FTPStatusMessages import status_msgs from OSEmulators import unix_longify as longify from IFTPCommandHandler import IFTPCommandHandler from PassiveAcceptor import PassiveAcceptor from RecvChannel import RecvChannel from XmitChannel import XmitChannel, ApplicationXmitStream from Zope.Server.VFS.UsernamePassword import UsernamePassword from Zope.Exceptions import Unauthorized class FTPServerChannel(LineServerChannel): """The FTP Server Channel represents a connection to a particular client. We can therefore store information here.""" __implements__ = LineServerChannel.__implements__, IFTPCommandHandler # List of commands that are always available special_commands = ('cmd_quit', 'cmd_type', 'cmd_noop', 'cmd_user', 'cmd_pass') # These are the commands that are accessing the filesystem. # Since this could be also potentially a longer process, these commands # are also the ones that are executed in a different thread. [-=- -=- -=- 432 lines omitted -=- -=- -=-] def getDirectoryList(self, args, long=0): # we need to scan the command line for arguments to '/bin/ls'... path_args = [] for arg in args: if arg[0] != '-': path_args.append (arg) else: # ignore arguments pass if len(path_args) < 1: dir = '.' else: dir = path_args[0] dir = self._generatePath(dir) return self.listdir(dir, long) def connectDataChannel(self, cdc): pa = self.passive_acceptor if pa: # PASV mode. if pa.ready: # a connection has already been made. conn, addr = pa.ready cdc.set_socket (conn) cdc.connected = 1 self.passive_acceptor.close() self.passive_acceptor = None # else we're still waiting for a connect to the PASV port. # FTP Explorer is known to do this. else: # not in PASV mode. ip, port = self.client_addr cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) if self.bind_local_minus_one: cdc.bind(('', self.server.port - 1)) try: cdc.connect((ip, port)) except socket.error, err: cdc.close('NO_DATA_CONN') def notifyClientDCClosing(self, *reply_args): if self.client_dc is not None: self.client_dc = None if reply_args: self.reply(*reply_args) === Added File Zope3/lib/python/Zope/Server/FTP/FTPStatusMessages.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: FTPStatusMessages.py,v 1.1.4.1 2002/04/12 21:30:55 shane Exp $ """ status_msgs = { 'OPEN_DATA_CONN' : '150 Opening %s mode data connection for file list', 'OPEN_CONN' : '150 Opening %s connection for %s', 'SUCCESS_200' : '200 %s command successful.', 'TYPE_SET_OK' : '200 Type set to %s.', 'STRU_OK' : '200 STRU F Ok.', 'MODE_OK' : '200 MODE S Ok.', 'FILE_DATE' : '213 %4d%02d%02d%02d%02d%02d', 'FILE_SIZE' : '213 %d Bytes', 'HELP_START' : '214-The following commands are recognized', 'HELP_END' : '214 Help done.', 'SERVER_TYPE' : '215 %s Type: %s', 'SERVER_READY' : '220 %s FTP server (Zope Async/Thread V0.1) ready.', 'GOODBYE' : '221 Goodbye.', 'SUCCESS_226' : '226 %s command successful.', 'TRANS_SUCCESS' : '226 Transfer successful.', 'PASV_MODE_MSG' : '227 Entering Passive Mode (%s,%d,%d)', 'LOGIN_SUCCESS' : '230 Login Successful.', 'SUCCESS_250' : '250 %s command successful.', 'SUCCESS_257' : '257 %s command successful.', 'ALREADY_CURRENT' : '257 "%s" is the current directory.', 'PASS_REQUIRED' : '331 Password required', 'RESTART_TRANSFER' : '350 Restarting at %d. Send STORE or ' 'RETRIEVE to initiate transfer.', 'READY_FOR_DEST' : '350 File exists, ready for destination.', 'NO_DATA_CONN' : "425 Can't build data connection", 'TRANSFER_ABORTED' : '426 Connection closed; transfer aborted.', 'CMD_UNKNOWN' : "500 '%s': command not understood.", 'INTERNAL_ERROR' : "500 Internal error: %s", 'ERR_ARGS' : '500 Bad command arguments', 'MODE_UNKOWN' : '502 Unimplemented MODE type', 'WRONG_BYTE_SIZE' : '504 Byte size must be 8', 'STRU_UNKNOWN' : '504 Unimplemented STRU type', 'NOT_AUTH' : "530 You are not authorized to perform the " "'%s' command", 'LOGIN_REQUIRED' : '530 Please log in with USER and PASS', 'LOGIN_MISMATCH' : '530 The username and password do not match.', 'ERR_NO_LIST' : '550 Could not list directory: %s', 'ERR_NO_DIR' : '550 "%s": No such directory.', 'ERR_NO_FILE' : '550 "%s": No such file.', 'ERR_IS_NOT_FILE' : '550 "%s": Is not a file', 'ERR_CREATE_FILE' : '550 Error creating file.', 'ERR_CREATE_DIR' : '550 Error creating directory: %s', 'ERR_DELETE_FILE' : '550 Error deleting file: %s', 'ERR_DELETE_DIR' : '550 Error removing directory: %s', 'ERR_OPEN_READ' : '553 Could not open file for reading: %s', 'ERR_OPEN_WRITE' : '553 Could not open file for writing: %s', 'ERR_IO' : '553 I/O Error: %s', 'ERR_RENAME' : '560 Could not rename "%s" to "%s": %s', 'ERR_RNFR_SOURCE' : '560 No source filename specify. Call RNFR first.', } === Added File Zope3/lib/python/Zope/Server/FTP/IFTPCommandHandler.py === from Interface import Interface class IFTPCommandHandler(Interface): """This interface defines all the FTP commands that are supported by the server. Every command takes the command line as first arguments, since it is responsible """ def cmd_abor(args): """Abort operation. No read access required. """ def cmd_appe(args): """Append to a file. Write access required. """ def cmd_cdup(args): """Change to parent of current working directory. """ def cmd_cwd(args): """Change working directory. """ def cmd_dele(args): """Delete a file. Write access required. """ def cmd_help(args): """Give help information. No read access required. """ def cmd_list(args): """Give list files in a directory. """ def cmd_mdtm(args): """Show last modification time of file. Example output: 213 19960301204320 Geez, there seems to be a second syntax for this fiel, where one can also set the modification time using: MDTM datestring pathname """ def cmd_mkd(args): """Make a directory. Write access required. """ def cmd_mode(args): """Set file transfer mode. No read access required. Obselete. """ def cmd_nlst(args): """Give name list of files in directory. """ def cmd_noop(args): """Do nothing. No read access required. """ def cmd_pass(args): """Specify password. """ def cmd_pasv(args): """Prepare for server-to-server transfer. No read access required. """ def cmd_port(args): """Specify data connection port. No read access required. """ def cmd_pwd(args): """Print the current working directory. """ def cmd_quit(args): """Terminate session. No read access required. """ def cmd_rest(args): """Restart incomplete transfer. """ def cmd_retr(args): """Retrieve a file. """ def cmd_rmd(args): """Remove a directory. Write access required. """ def cmd_rnfr(args): """Specify rename-from file name. Write access required. """ def cmd_rnto(args): """Specify rename-to file name. Write access required. """ def cmd_size(args): """Return size of file. """ def cmd_stat(args): """Return status of server. No read access required. """ def cmd_stor(args): """Store a file. Write access required. """ def cmd_stru(args): """Set file transfer structure. Obselete.""" def cmd_syst(args): """Show operating system type of server system. No read access required. Replying to this command is of questionable utility, because this server does not behave in a predictable way w.r.t. the output of the LIST command. We emulate Unix ls output, but on win32 the pathname can contain drive information at the front Currently, the combination of ensuring that os.sep == '/' and removing the leading slash when necessary seems to work. [cd'ing to another drive also works] This is how wuftpd responds, and is probably the most expected. The main purpose of this reply is so that the client knows to expect Unix ls-style LIST output. one disadvantage to this is that some client programs assume they can pass args to /bin/ls. a few typical responses: 215 UNIX Type: L8 (wuftpd) 215 Windows_NT version 3.51 215 VMS MultiNet V3.3 500 'SYST': command not understood. (SVR4) """ def cmd_type(args): """Specify data transfer type. No read access required. """ def cmd_user(args): """Specify user name. No read access required. """ # this is the command list from the wuftpd man page # '!' requires write access # not_implemented_commands = { 'acct': 'specify account (ignored)', 'allo': 'allocate storage (vacuously)', 'site': 'non-standard commands (see next section)', 'stou': 'store a file with a unique name', #! 'xcup': 'change to parent of current working directory (deprecated)', 'xcwd': 'change working directory (deprecated)', 'xmkd': 'make a directory (deprecated)', #! 'xpwd': 'print the current working directory (deprecated)', 'xrmd': 'remove a directory (deprecated)', #! } === Added File Zope3/lib/python/Zope/Server/FTP/OSEmulators.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: OSEmulators.py,v 1.1.4.1 2002/04/12 21:30:55 shane Exp $ """ import stat import time import pwd, grp months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] mode_table = { '0':'---', '1':'--x', '2':'-w-', '3':'-wx', '4':'r--', '5':'r-x', '6':'rw-', '7':'rwx' } def unix_longify((file, stat_info)): # for now, only pay attention to the lower bits try: username = pwd.getpwuid(int(stat_info[stat.ST_UID]))[0] except: username = stat_info[stat.ST_UID] try: grpname = grp.getgrgid(int(stat_info[stat.ST_GID]))[0] except: grpname = stat_info[stat.ST_GID] mode = ('%o' % stat_info[stat.ST_MODE])[-3:] mode = ''.join(map (lambda x: mode_table[x], mode)) if stat.S_ISDIR (stat_info[stat.ST_MODE]): dirchar = 'd' else: dirchar = '-' date = ls_date (long(time.time()), stat_info[stat.ST_MTIME]) return '%s%s %3d %-8s %-8s %8d %s %s' % ( dirchar, mode, stat_info[stat.ST_NLINK], username, grpname, stat_info[stat.ST_SIZE], date, file ) def ls_date (now, t): """Emulate the unix 'ls' command's date field. it has two formats - if the date is more than 180 days in the past, then it's like this: Oct 19 1995 otherwise, it looks like this: Oct 19 17:33 """ try: info = time.gmtime(t) except: info = time.gmtime(0) # 15,600,000 == 86,400 * 180 if (now - t) > 15600000: return '%s %2d %d' % ( months[info[1]-1], info[2], info[0] ) else: return '%s %2d %02d:%02d' % ( months[info[1]-1], info[2], info[3], info[4] ) def msdos_longify((file, stat_info)): """This matches the output of NT's ftp server (when in MSDOS mode) exactly. """ if stat.S_ISDIR(stat_info[stat.ST_MODE]): dir = '' else: dir = ' ' date = msdos_date(stat_info[stat.ST_MTIME]) return '%s %s %8d %s' % (date, dir, stat_info[stat.ST_SIZE], file) def msdos_date(t): try: info = time.gmtime(t) except: info = time.gmtime(0) # year, month, day, hour, minute, second, ... if info[3] > 11: merid = 'PM' info[3] = info[3] - 12 else: merid = 'AM' return '%02d-%02d-%02d %02d:%02d%s' % ( info[1], info[2], info[0]%100, info[3], info[4], merid ) === Added File Zope3/lib/python/Zope/Server/FTP/PassiveAcceptor.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: PassiveAcceptor.py,v 1.1.4.1 2002/04/12 21:30:55 shane Exp $ """ import asyncore import socket class PassiveAcceptor(asyncore.dispatcher): """This socket accepts a data connection, used when the server has been placed in passive mode. Although the RFC implies that we ought to be able to use the same acceptor over and over again, this presents a problem: how do we shut it off, so that we are accepting connections only when we expect them? [we can't] wuftpd, and probably all the other servers, solve this by allowing only one connection to hit this acceptor. They then close it. Any subsequent data-connection command will then try for the default port on the client side [which is of course never there]. So the 'always-send-PORT/PASV' behavior seems required. Another note: wuftpd will also be listening on the channel as soon as the PASV command is sent. It does not wait for a data command first. --- we need to queue up a particular behavior: 1) xmit : queue up producer[s] 2) recv : the file object It would be nice if we could make both channels the same. Hmmm..""" __implements__ = asyncore.dispatcher.__implements__ ready = None def __init__ (self, control_channel): asyncore.dispatcher.__init__ (self) self.control_channel = control_channel self.create_socket(socket.AF_INET, socket.SOCK_STREAM) # bind to an address on the interface that the # control connection is coming from. self.bind ( (self.control_channel.getsockname()[0], 0) ) self.addr = self.getsockname() self.listen(1) def log (self, *ignore): pass def handle_accept (self): conn, addr = self.accept() conn.setblocking(0) dc = self.control_channel.client_dc if dc is not None: dc.set_socket(conn) dc.addr = addr dc.connected = 1 self.control_channel.passive_acceptor = None else: self.ready = conn, addr self.close() === Added File Zope3/lib/python/Zope/Server/FTP/PublisherFTPServer.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: PublisherFTPServer.py,v 1.1.4.1 2002/04/12 21:30:55 shane Exp $ """ from FTPServer import FTPServer from Zope.Server.FTP.PublisherFilesystemAccess import PublisherFilesystemAccess class PublisherFTPServer(FTPServer): """Generic FTP Server""" def __init__(self, request_factory, name, ip, port, *args, **kw): self.request_factory = request_factory fs_access = PublisherFilesystemAccess(request_factory) super(PublisherFTPServer, self).__init__(ip, port, fs_access, *args, **kw) === Added File Zope3/lib/python/Zope/Server/FTP/PublisherFTPServerChannel.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: PublisherFTPServerChannel.py,v 1.1.4.1 2002/04/12 21:30:55 shane Exp $ """ from FTPServerChannel import FTPServerChannel class PublisherFTPServerChannel(FTPServerChannel): """The FTP Server Channel represents a connection to a particular client. We can therefore store information here.""" __implements__ = FTPServerChannel.__implements__ def authenticate(self): if self._getFilesystem()._authenticate(): return 1, 'User successfully authenticated.' else: return 0, 'User could not be authenticated.' === Added File Zope3/lib/python/Zope/Server/FTP/PublisherFTPTask.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: PublisherFTPTask.py,v 1.1.4.1 2002/04/12 21:30:55 shane Exp $ """ from FTPTask import FTPTask from Zope.Publisher.Publish import publish class PublisherFTPTask(FTPTask): """ """ __implements__ = FTPTask.__implements__ def execute(self): """ """ server = self.channel.server env = self.create_environment() instream = self.request_data.getBodyStream() request = server.request_factory(instream, self, env) publish(request) def create_environment(self): request_data = self.request_data channel = self.channel server = channel.server # This should probably change to reflect calling the FileSystem # methods env = {'command': request_data.command 'args': request_data.args } return env === Added File Zope3/lib/python/Zope/Server/FTP/PublisherFilesystemAccess.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Implementation of IFilesystemAccess intended only for testing. $Id: PublisherFilesystemAccess.py,v 1.1.4.1 2002/04/12 21:30:55 shane Exp $ """ from cStringIO import StringIO from Zope.Exceptions import Unauthorized from Zope.App.Security.PrincipalRegistry import principalRegistry from Zope.Server.VFS.PublisherFileSystem import PublisherFileSystem from Zope.Server.VFS.IFilesystemAccess import IFilesystemAccess from Zope.Server.VFS.IUsernamePassword import IUsernamePassword class PublisherFilesystemAccess: __implements__ = IFilesystemAccess def __init__(self, request_factory): self.request_factory = request_factory def authenticate(self, credentials): assert IUsernamePassword.isImplementedBy(credentials) env = {'credentials' : credentials} request = self.request_factory(StringIO(''), StringIO(), env) id = principalRegistry.authenticate(request) if id is None: raise Unauthorized def open(self, credentials): return PublisherFileSystem(credentials, self.request_factory) === Added File Zope3/lib/python/Zope/Server/FTP/RecvChannel.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: RecvChannel.py,v 1.1.4.1 2002/04/12 21:30:55 shane Exp $ """ from Zope.Server.ServerChannelBase import ChannelBaseClass from Zope.Server.Buffers import OverflowableBuffer from Zope.Server.ITask import ITask class RecvChannel(ChannelBaseClass): """ """ complete_transfer = 0 _fileno = None # provide a default for asyncore.dispatcher._fileno def __init__ (self, control_channel, finish_args): self.control_channel = control_channel self.finish_args = finish_args self.inbuf = OverflowableBuffer(control_channel.adj.inbuf_overflow) ChannelBaseClass.__init__(self, None, None, control_channel.adj) # Note that this channel starts out in async mode. def writable (self): return 0 def handle_connect (self): pass def received (self, data): if data: self.inbuf.append(data) def handle_close (self): """Client closed, indicating EOF.""" c = self.control_channel task = FinishedRecvTask(c, self.inbuf, self.finish_args) self.complete_transfer = 1 self.close() c.start_task(task) def close(self, *reply_args): try: c = self.control_channel if c is not None: self.control_channel = None if not self.complete_transfer and not reply_args: # Not all data transferred reply_args = ('TRANSFER_ABORTED',) c.notifyClientDCClosing(*reply_args) finally: if self.socket is not None: # XXX asyncore.dispatcher.close() doesn't like socket == None ChannelBaseClass.close(self) class FinishedRecvTask: __implements__ = ITask def __init__(self, control_channel, inbuf, finish_args): self.control_channel = control_channel self.inbuf = inbuf self.finish_args = finish_args ############################################################ # Implementation methods for interface # Zope.Server.ITask def service(self): """Called to execute the task. """ close_on_finish = 0 c = self.control_channel try: try: c.finishedRecv(self.inbuf, self.finish_args) except socket.error: close_on_finish = 1 if c.adj.log_socket_errors: raise finally: c.end_task(close_on_finish) def cancel(self): 'See Zope.Server.ITask.ITask' self.control_channel.close_when_done() def defer(self): 'See Zope.Server.ITask.ITask' pass # ############################################################ === Added File Zope3/lib/python/Zope/Server/FTP/TestFilesystemAccess.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Implementation of IFilesystemAccess intended only for testing. $Id: TestFilesystemAccess.py,v 1.1.4.1 2002/04/12 21:30:55 shane Exp $ """ from Zope.Server.VFS.IFilesystemAccess import IFilesystemAccess from Zope.Server.VFS.IUsernamePassword import IUsernamePassword from Zope.Exceptions import Unauthorized class TestFilesystemAccess: __implements__ = IFilesystemAccess passwords = {'foo': 'bar'} def __init__(self, fs): self.fs = fs def authenticate(self, credentials): if not IUsernamePassword.isImplementedBy(credentials): raise Unauthorized name = credentials.getUserName() if not self.passwords.has_key(name): raise Unauthorized if credentials.getPassword() != self.passwords[name]: raise Unauthorized def open(self, credentials): self.authenticate(credentials) return self.fs === Added File Zope3/lib/python/Zope/Server/FTP/XmitChannel.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: XmitChannel.py,v 1.1.4.1 2002/04/12 21:30:55 shane Exp $ """ from Zope.Server.ServerChannelBase import ChannelBaseClass class XmitChannel(ChannelBaseClass): opened = 0 _fileno = None # provide a default for asyncore.dispatcher._fileno def __init__ (self, control_channel, ok_reply_args): self.control_channel = control_channel self.ok_reply_args = ok_reply_args self.set_sync() ChannelBaseClass.__init__(self, None, None, control_channel.adj) def _open(self): """Signal the client to open the connection.""" self.opened = 1 self.control_channel.reply(*self.ok_reply_args) self.control_channel.connectDataChannel(self) def write(self, data): if self.control_channel is None: raise IOError, 'Client FTP connection closed' if not self.opened: self._open() ChannelBaseClass.write(self, data) def readable(self): return not self.connected def handle_read(self): # This is only called when making the connection. try: self.recv(1) except: # The connection failed. self.close('NO_DATA_CONN') def handle_connect(self): pass def handle_comm_error(self): self.close('TRANSFER_ABORTED') def close(self, *reply_args): try: c = self.control_channel if c is not None: self.control_channel = None if not reply_args: if not len(self.outbuf): # All data transferred if not self.opened: # Zero-length file self._open() reply_args = ('TRANS_SUCCESS',) else: # Not all data transferred reply_args = ('TRANSFER_ABORTED',) c.notifyClientDCClosing(*reply_args) finally: if self.socket is not None: # XXX asyncore.dispatcher.close() doesn't like socket == None ChannelBaseClass.close(self) class ApplicationXmitStream: """Provide stream output, remapping close() to close_when_done(). """ def __init__(self, xmit_channel): self.write = xmit_channel.write self.flush = xmit_channel.flush self.close = xmit_channel.close_when_done === Added File Zope3/lib/python/Zope/Server/FTP/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.4.1 2002/04/12 21:30:55 shane Exp $ """ From shane@cvs.zope.org Fri Apr 12 22:30:59 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:30:59 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/Thread - SelectTrigger.py:1.1.4.1 __init__.py:1.1.4.1 Message-ID: <200204122130.g3CLUxF21143@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/Thread In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/Thread Added Files: Tag: Zope-3x-branch SelectTrigger.py __init__.py Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/Server/Thread/SelectTrigger.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## # -*- Mode: Python; tab-width: 4 -*- VERSION_STRING = "$Id: SelectTrigger.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $" import asyncore import asynchat import os import socket import string import thread if os.name == 'posix': class Trigger(asyncore.file_dispatcher): "Wake up a call to select() running in the main thread" # This is useful in a context where you are using Medusa's I/O # subsystem to deliver data, but the data is generated by another # thread. Normally, if Medusa is in the middle of a call to # select(), new output data generated by another thread will have # to sit until the call to select() either times out or returns. # If the trigger is 'pulled' by another thread, it should immediately # generate a READ event on the trigger object, which will force the # select() invocation to return. # A common use for this facility: letting Medusa manage I/O for a # large number of connections; but routing each request through a # thread chosen from a fixed-size thread pool. When a thread is # acquired, a transaction is performed, but output data is # accumulated into buffers that will be emptied more efficiently # by Medusa. [picture a server that can process database queries # rapidly, but doesn't want to tie up threads waiting to send data # to low-bandwidth connections] # The other major feature provided by this class is the ability to # move work back into the main thread: if you call pull_trigger() # with a thunk argument, when select() wakes up and receives the # event it will call your thunk from within that thread. The main # purpose of this is to remove the need to wrap thread locks around # Medusa's data structures, which normally do not need them. [To see # why this is true, imagine this scenario: A thread tries to push some # new data onto a channel's outgoing data queue at the same time that # the main thread is trying to remove some] def __init__ (self): r, w = os.pipe() self.trigger = w asyncore.file_dispatcher.__init__ (self, r) self.lock = thread.allocate_lock() self.thunks = [] def __repr__ (self): return '' % id(self) def readable (self): return 1 def writable (self): return 0 def handle_connect (self): pass def pull_trigger (self, thunk=None): # print 'PULL_TRIGGER: ', len(self.thunks) if thunk: try: self.lock.acquire() self.thunks.append (thunk) finally: self.lock.release() os.write (self.trigger, 'x') def handle_read (self): self.recv (8192) try: self.lock.acquire() for thunk in self.thunks: try: thunk() except: (file, fun, line), t, v, tbinfo = \ asyncore.compact_traceback() print 'exception in trigger thunk: (%s:%s %s)' % ( t, v, tbinfo) self.thunks = [] finally: self.lock.release() else: # win32-safe version class Trigger (asyncore.dispatcher): address = ('127.9.9.9', 19999) def __init__ (self): a = socket.socket (socket.AF_INET, socket.SOCK_STREAM) w = socket.socket (socket.AF_INET, socket.SOCK_STREAM) # set TCP_NODELAY to true to avoid buffering w.setsockopt(socket.IPPROTO_TCP, 1, 1) # tricky: get a pair of connected sockets host='127.0.0.1' port=19999 while 1: try: self.address=(host, port) a.bind(self.address) break except: if port <= 19950: raise 'Bind Error', 'Cannot bind trigger!' port=port - 1 a.listen (1) w.setblocking (0) try: w.connect (self.address) except: pass r, addr = a.accept() a.close() w.setblocking (1) self.trigger = w asyncore.dispatcher.__init__ (self, r) self.lock = thread.allocate_lock() self.thunks = [] self._trigger_connected = 0 def __repr__ (self): return '' % id(self) def readable (self): return 1 def writable (self): return 0 def handle_connect (self): pass def pull_trigger (self, thunk=None): if thunk: try: self.lock.acquire() self.thunks.append (thunk) finally: self.lock.release() self.trigger.send ('x') def handle_read (self): self.recv (8192) try: self.lock.acquire() for thunk in self.thunks: try: thunk() except: (file, fun, line), t, v, tbinfo = asyncore.compact_traceback() print 'exception in trigger thunk: (%s:%s %s)' % (t, v, tbinfo) self.thunks = [] finally: self.lock.release() the_trigger = None class TriggerFile: "A 'triggered' file object" buffer_size = 4096 def __init__ (self, parent): global the_trigger if the_trigger is None: the_trigger = trigger() self.parent = parent self.buffer = '' def write (self, data): self.buffer = self.buffer + data if len(self.buffer) > self.buffer_size: d, self.buffer = self.buffer, '' the_trigger.pull_trigger ( lambda d=d,p=self.parent: p.push (d) ) def writeline (self, line): self.write (line+'\r\n') def writelines (self, lines): self.write ( string.joinfields ( lines, '\r\n' ) + '\r\n' ) def flush (self): if self.buffer: d, self.buffer = self.buffer, '' the_trigger.pull_trigger ( lambda p=self.parent,d=d: p.push (d) ) def softspace (self, *args): pass def close (self): # in a derived class, you may want to call trigger_close() instead. self.flush() self.parent = None def trigger_close (self): d, self.buffer = self.buffer, '' p, self.parent = self.parent, None the_trigger.pull_trigger ( lambda p=p,d=d: (p.push(d), p.close_when_done()) ) if __name__ == '__main__': import time def thread_function (output_file, i, n): print 'entering thread_function' while n: time.sleep (5) output_file.write ('%2d.%2d %s\r\n' % (i, n, output_file)) output_file.flush() n = n - 1 output_file.close() print 'exiting thread_function' class thread_parent (asynchat.async_chat): def __init__ (self, conn, addr): self.addr = addr asynchat.async_chat.__init__ (self, conn) self.set_terminator ('\r\n') self.buffer = '' self.count = 0 def collect_incoming_data (self, data): self.buffer = self.buffer + data def found_terminator (self): data, self.buffer = self.buffer, '' if not data: asyncore.close_all() print "done" return n = string.atoi (string.split (data)[0]) tf = TriggerFile (self) self.count = self.count + 1 thread.start_new_thread (thread_function, (tf, self.count, n)) class ThreadServer(asyncore.dispatcher): def __init__ (self, family=socket.AF_INET, address=('', 9003)): asyncore.dispatcher.__init__ (self) self.create_socket (family, socket.SOCK_STREAM) self.set_reuse_addr() self.bind (address) self.listen (5) def handle_accept (self): conn, addr = self.accept() tp = thread_parent (conn, addr) ThreadServer() #asyncore.loop(1.0, use_poll=1) try: asyncore.loop () except: asyncore.close_all() === Added File Zope3/lib/python/Zope/Server/Thread/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ From shane@cvs.zope.org Fri Apr 12 22:31:02 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:02 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/demo - publish.py:NONE Message-ID: <200204122131.g3CLV2W21215@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/demo In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/medusa/demo Removed Files: Tag: Zope-3x-branch publish.py Log Message: Merged Zope3-Server-Branch. === Removed File Zope3/lib/python/Zope/Server/medusa/demo/publish.py === From shane@cvs.zope.org Fri Apr 12 22:31:24 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:24 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/HTTP - DefaultPublisher.py:1.1.2.3 HTTPRequest.py:1.1.2.26 HTTPResponse.py:1.1.2.18 Message-ID: <200204122131.g3CLVNC22171@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/HTTP In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Publisher/HTTP Modified Files: Tag: Zope-3x-branch DefaultPublisher.py HTTPRequest.py HTTPResponse.py Log Message: Merged Zope3-Server-Branch. === Zope3/lib/python/Zope/Publisher/HTTP/DefaultPublisher.py 1.1.2.2 => 1.1.2.3 === # ############################################################################## -""" - -$Id$ -""" -from IHTTPPublisher import IHTTPPublisher - - -class DefaultPublisher: - - __implements__ = IHTTPPublisher - - ############################################################ - # Implementation methods for interface - # Zope.Publisher.HTTP.IHTTPPublisher - - def publishTraverse(self, request, name): - 'See Zope.Publisher.HTTP.IHTTPPublisher.IHTTPPublisher' - - return getattr(self, name) - - # - ############################################################ +"""blisher.py,v 1.1.2.2 2002/04/02 02:20:33 srichter Exp $ +""" +from IHTTPPublisher import IHTTPPublisher + + +class DefaultPublisher: + + __implements__ = IHTTPPublisher + + ############################################################ + # Implementation methods for interface + # Zope.Publisher.HTTP.IHTTPPublisher + + def publishTraverse(self, request, name): + 'See Zope.Publisher.HTTP.IHTTPPublisher.IHTTPPublisher' + + return getattr(self, name) + + # + ############################################################ === Zope3/lib/python/Zope/Publisher/HTTP/HTTPRequest.py 1.1.2.25 => 1.1.2.26 === '_app_server', # The server path of the application url '_orig_env', # The original environment - '_endswithslash' # Does the given path end with / + '_endswithslash', # Does the given path end with / ) retry_max_count = 3 # How many times we're willing to retry - def __init__(self, body_instream, outstream, environ): + def __init__(self, body_instream, outstream, environ, response=None): - super(HTTPRequest, self).__init__(body_instream, outstream, environ) + super(HTTPRequest, self).__init__( + body_instream, outstream, environ, response) self._orig_env = environ environ = sane_environment(environ) @@ -293,22 +294,27 @@ def supportsRetry(self): 'See Zope.Publisher.IPublisherRequest.IPublisherRequest' - if self._retry_count < self.retry_max_count: + count = getattr(self, '_retry_count', 0) + if count < self.retry_max_count: if STAGGER_RETRIES: - time.sleep(random.uniform(0, 2**(self.retry_count))) + time.sleep(random.uniform(0, 2**(count))) return 1 def retry(self): 'See Zope.Publisher.IPublisherRequest.IPublisherRequest' - self.retry_count = self.retry_count + 1 - self.body_instream.seek(0) + count = getattr(self, '_retry_count', 0) + self._retry_count = count + 1 + self._body_instream.seek(0) + new_response = self.getResponse().retry() request = self.__class__( - body_instream = self._body_instream, - outstream = self.getResponse().getOutputStream(), - environ = self._orig_env + body_instream=self._body_instream, + outstream=None, + environ=self._orig_env, + response=new_response, ) - request.retry_count = self.retry_count + request.setPublication(self.getPublication()) + request._retry_count = self._retry_count return request === Zope3/lib/python/Zope/Publisher/HTTP/HTTPResponse.py 1.1.2.17 => 1.1.2.18 === '_wrote_headers', '_streaming', - '_status', # The response status (usually an integer) - '_reason' # The reason that goes with the status + '_status', # The response status (usually an integer) + '_reason', # The reason that goes with the status + '_status_set', # Boolean: status explicitly set ) @@ -121,8 +122,9 @@ self._accumulated_headers = [] self._wrote_headers = 0 self._streaming = 0 - self._status = 200 - self._reason = 'Ok' + self._status = 599 + self._reason = 'No status set' + self._status_set = 0 def setHeaderOutput(self, header_output): @@ -143,7 +145,7 @@ if status_codes.has_key(status): status = status_codes[status] else: - status=500 + status = 500 self._status = status if reason is None: @@ -154,6 +156,7 @@ else: reason = 'Unknown' self._reason = reason + self._status_set = 1 def getStatus(self): @@ -261,6 +264,11 @@ ###################################### # from: Zope.Publisher.IPublisherResponse.IPublisherResponse + def setBody(self, body): + self._body = body + if not self._status_set: + self.setStatus(200) + def handleException(self, exc_info): """ Calls self.setBody() with an error response. @@ -283,6 +291,11 @@ self.setBody(body) + def internalError(self): + 'See Zope.Publisher.IPublisherResponse.IPublisherResponse' + self.setStatus(500, "The engines can't take any more, Jim!") + + def _html(self, title, content): t = escape(title) return ( @@ -292,9 +305,6 @@ "\n" % (t, t, content) ) - - - def retry(self): From shane@cvs.zope.org Fri Apr 12 22:31:35 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:35 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/tests - __init__.py:1.1.2.3 testHTTPServer.py:NONE testPublisherServer.py:NONE Message-ID: <200204122131.g3CLVZT22201@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/tests In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/tests Modified Files: Tag: Zope-3x-branch __init__.py Removed Files: Tag: Zope-3x-branch testHTTPServer.py testPublisherServer.py Log Message: Merged Zope3-Server-Branch. === Zope3/lib/python/Zope/Server/tests/__init__.py 1.1.2.2 => 1.1.2.3 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ Unit tests for Zope.Server """ === Removed File Zope3/lib/python/Zope/Server/tests/testHTTPServer.py === === Removed File Zope3/lib/python/Zope/Server/tests/testPublisherServer.py === From shane@cvs.zope.org Fri Apr 12 22:30:58 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:30:58 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/HTTP - Chunking.py:1.1.4.1 CommonHitLogger.py:1.1.4.1 HTTPRequestParser.py:1.1.4.1 HTTPServer.py:1.1.4.1 HTTPServerChannel.py:1.1.4.1 HTTPTask.py:1.1.4.1 PublisherHTTPServer.py:1.1.4.1 __init__.py:1.1.4.1 http_date.py:1.1.4.1 Message-ID: <200204122130.g3CLUwU21107@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/HTTP In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/HTTP Added Files: Tag: Zope-3x-branch Chunking.py CommonHitLogger.py HTTPRequestParser.py HTTPServer.py HTTPServerChannel.py HTTPTask.py PublisherHTTPServer.py __init__.py http_date.py Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/Server/HTTP/Chunking.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: Chunking.py,v 1.1.4.1 2002/04/12 21:30:55 shane Exp $ """ from Zope.Server.Utilities import find_double_newline from Zope.Server.IStreamConsumer import IStreamConsumer class ChunkedReceiver: __implements__ = IStreamConsumer chunk_remainder = 0 control_line = '' all_chunks_received = 0 trailer = '' completed = 0 # max_control_line = 1024 # max_trailer = 65536 def __init__(self, buf): self.buf = buf def received(self, s): # Returns the number of bytes consumed. if self.completed: return 0 orig_size = len(s) while s: rm = self.chunk_remainder if rm > 0: # Receive the remainder of a chunk. to_write = s[:rm] self.buf.append(to_write) written = len(to_write) s = s[written:] self.chunk_remainder -= written elif not self.all_chunks_received: # Receive a control line. s = self.control_line + s pos = s.find('\n') if pos < 0: # Control line not finished. self.control_line = s s = '' else: # Control line finished. line = s[:pos] s = s[pos + 1:] self.control_line = '' line = line.strip() if line: # Begin a new chunk. semi = line.find(';') if semi >= 0: # discard extension info. line = line[:semi] sz = int(line.strip(), 16) # hexadecimal if sz > 0: # Start a new chunk. self.chunk_remainder = sz else: # Finished chunks. self.all_chunks_received = 1 # else expect a control line. else: # Receive the trailer. trailer = self.trailer + s if trailer.startswith('\r\n'): # No trailer. self.completed = 1 return orig_size - (len(trailer) - 2) elif trailer.startswith('\n'): # No trailer. self.completed = 1 return orig_size - (len(trailer) - 1) pos = find_double_newline(trailer) if pos < 0: # Trailer not finished. self.trailer = trailer s = '' else: # Finished the trailer. self.completed = 1 self.trailer = trailer[:pos] return orig_size - (len(trailer) - pos) return orig_size def getfile(self): return self.buf.getfile() === Added File Zope3/lib/python/Zope/Server/HTTP/CommonHitLogger.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: CommonHitLogger.py,v 1.1.4.1 2002/04/12 21:30:55 shane Exp $ """ import time import sys from http_date import monthname from Zope.Server.Logger.FileLogger import FileLogger from Zope.Server.Logger.ResolvingLogger import ResolvingLogger from Zope.Server.Logger.UnresolvingLogger import UnresolvingLogger class CommonHitLogger: """Outputs hits in common HTTP log format. """ def __init__(self, logger_object=None, resolver=None): if logger_object is None: logger_object = FileLogger(sys.stdout) if resolver is not None: self.output = ResolvingLogger(resolver, logger_object) else: self.output = UnresolvingLogger(logger_object) def compute_timezone_for_log(self, tz): if tz > 0: neg = 1 else: neg = 0 tz = -tz h, rem = divmod (tz, 3600) m, rem = divmod (rem, 60) if neg: return '-%02d%02d' % (h, m) else: return '+%02d%02d' % (h, m) tz_for_log = None tz_for_log_alt = None def log_date_string(self, when): logtime = time.localtime(when) Y, M, D, h, m, s = logtime[:6] if not time.daylight: tz = self.tz_for_log if tz is None: tz = self.compute_timezone_for_log(time.timezone) self.tz_for_log = tz else: tz = self.tz_for_log_alt if tz is None: tz = self.compute_timezone_for_log(time.altzone) self.tz_for_log_alt = tz return '%d/%s/%02d:%02d:%02d:%02d %s' % ( Y, monthname[M], D, h, m, s, tz) def log(self, task): """ Receives a completed task and logs it in the common log format. """ now = time.time() request_data = task.request_data req_headers = request_data.headers user_name = task.auth_user_name or 'anonymous' user_agent = req_headers.get('USER_AGENT', '') referer = req_headers.get('REFERER', '') self.output.log( task.channel.addr[0], ' - %s [%s] "%s" %s %d "%s" "%s"\n' % ( user_name, self.log_date_string(now), request_data.first_line, task.status, task.bytes_written, referer, user_agent ) ) === Added File Zope3/lib/python/Zope/Server/HTTP/HTTPRequestParser.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ This server uses asyncore to accept connections and do initial processing but threads to do work. $Id: HTTPRequestParser.py,v 1.1.4.1 2002/04/12 21:30:56 shane Exp $ """ import re from urllib import unquote from Zope.Server.FixedStreamReceiver import FixedStreamReceiver from Zope.Server.Buffers import OverflowableBuffer from Zope.Server.Utilities import find_double_newline from Zope.Server.IStreamConsumer import IStreamConsumer try: from cStringIO import StringIO except ImportError: from StringIO import StringIO class HTTPRequestParser: """A structure that collects the HTTP request. Once the stream is completed, the instance is passed to a server task constructor. """ __implements__ = IStreamConsumer completed = 0 # Set once request is completed. empty = 0 # Set if no request was made. header_plus = '' chunked = 0 content_length = 0 body_rcv = None # Other attributes: first_line, header, headers, command, uri, version, # path, query, fragment # headers is a mapping containing keys translated to uppercase # with dashes turned into underscores. def __init__(self, adj): """ adj is an Adjustments object. """ self.headers = {} self.adj = adj def received(self, data): """ Receives the HTTP stream for one request. Returns the number of bytes consumed. Sets the completed flag once both the header and the body have been received. """ if self.completed: return 0 # Can't consume any more. datalen = len(data) br = self.body_rcv if br is None: # In header. s = self.header_plus + data index = find_double_newline(s) if index >= 0: # Header finished. header_plus = s[:index] consumed = len(data) - (len(s) - index) self.in_header = 0 # Remove preceeding blank lines. header_plus = header_plus.lstrip() if not header_plus: self.empty = 1 self.completed = 1 else: self.parse_header(header_plus) if self.body_rcv is None: self.completed = 1 return consumed else: # Header not finished yet. self.header_plus = s return datalen else: # In body. consumed = br.received(data) if br.completed: self.completed = 1 return consumed def parse_header(self, header_plus): """ Parses the header_plus block of text (the headers plus the first line of the request). """ index = header_plus.find('\n') if index >= 0: first_line = header_plus[:index].rstrip() header = header_plus[index + 1:] else: first_line = header_plus.rstrip() header = '' self.first_line = first_line self.header = header lines = self.get_header_lines() headers = self.headers for line in lines: index = line.find(':') if index > 0: key = line[:index] value = line[index + 1:].strip() key1 = key.upper().replace('-', '_') headers[key1] = value # else there's garbage in the headers? command, uri, version = self.crack_first_line() self.command = str(command) if uri and '%' in uri: uri = unquote(uri) self.uri = str(uri) self.version = version self.split_uri() if version == '1.1': te = headers.get('TRANSFER_ENCODING', '') if te == 'chunked': from Chunking import ChunkedReceiver self.chunked = 1 buf = OverflowableBuffer(self.adj.inbuf_overflow) self.body_rcv = ChunkedReceiver(buf) if not self.chunked: cl = int(headers.get('CONTENT_LENGTH', 0)) self.content_length = cl if cl > 0: buf = OverflowableBuffer(self.adj.inbuf_overflow) self.body_rcv = FixedStreamReceiver(cl, buf) def get_header_lines(self): """ Splits the header into lines, putting multi-line headers together. """ r = [] lines = self.header.split('\n') for line in lines: if line and line[0] in ' \t': r[-1] = r[-1] + line[1:] else: r.append(line) return r first_line_re = re.compile ( '([^ ]+) (?:[^ :?#]+://[^ ?#/]*)?([^ ]+)(( HTTP/([0-9.]+))$|$)') def crack_first_line(self): r = self.first_line m = self.first_line_re.match (r) if m is not None and m.end() == len(r): if m.group(3): version = m.group(5) else: version = None return m.group(1).upper(), m.group(2), version else: return None, None, None path_regex = re.compile ( # path query fragment r'([^?#]*)(\?[^#]*)?(#.*)?' ) def split_uri(self): m = self.path_regex.match (self.uri) if m.end() != len(self.uri): raise ValueError, "Broken URI" else: self.path, query, self.fragment = m.groups() if query: query = query[1:] self.query = query def getBodyStream(self): body_rcv = self.body_rcv if body_rcv is not None: return body_rcv.getfile() else: return StringIO('') === Added File Zope3/lib/python/Zope/Server/HTTP/HTTPServer.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ This server uses asyncore to accept connections and do initial processing but threads to do work. $Id: HTTPServer.py,v 1.1.4.1 2002/04/12 21:30:56 shane Exp $ """ from Zope.Server.ServerBase import ServerBase from HTTPServerChannel import HTTPServerChannel class HTTPServer(ServerBase): """This is a generic HTTP Server.""" __implements__ = ServerBase.__implements__ channel_class = HTTPServerChannel SERVER_IDENT = 'Zope.Server.HTTPServer' def executeRequest(self, task): """Execute an HTTP request.""" # This is a default implementation, meant to be overridden. body = "The HTTP server is running!\r\n" * 10 task.response_headers['Content-Type'] = 'text/plain' task.response_headers['Content-Length'] = str(len(body)) task.write(body) if __name__ == '__main__': from Zope.Server.TaskThreads import ThreadedTaskDispatcher td = ThreadedTaskDispatcher() td.setThreadCount(4) HTTPServer('', 8080, task_dispatcher=td) try: import asyncore while 1: asyncore.poll(5) except KeyboardInterrupt: print 'shutting down...' td.shutdown() === Added File Zope3/lib/python/Zope/Server/HTTP/HTTPServerChannel.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: HTTPServerChannel.py,v 1.1.4.1 2002/04/12 21:30:56 shane Exp $ """ from Zope.Server.ServerChannelBase import ServerChannelBase from HTTPTask import HTTPTask from HTTPRequestParser import HTTPRequestParser class HTTPServerChannel(ServerChannelBase): """HTTP-specific Server Channel""" __implements__ = ServerChannelBase.__implements__ task_class = HTTPTask parser_class = HTTPRequestParser === Added File Zope3/lib/python/Zope/Server/HTTP/HTTPTask.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ This server uses asyncore to accept connections and do initial processing but threads to do work. $Id: HTTPTask.py,v 1.1.4.1 2002/04/12 21:30:56 shane Exp $ """ import socket import time from http_date import build_http_date from Zope.Server.IHeaderOutput import IHeaderOutput from Zope.Server.ITask import ITask rename_headers = { 'CONTENT_LENGTH' : 'CONTENT_LENGTH', 'CONTENT_TYPE' : 'CONTENT_TYPE', 'CONNECTION' : 'CONNECTION_TYPE', } class HTTPTask: """An HTTP task accepts a request and writes to a channel. Subclass this and override the execute() method. """ __implements__ = ITask, IHeaderOutput #, IOutputStream instream = None close_on_finish = 1 status = '200' reason = 'Ok' wrote_header = 0 accumulated_headers = None bytes_written = 0 auth_user_name = '' cgi_env = None def __init__(self, channel, request_data): self.channel = channel self.request_data = request_data self.response_headers = { 'Server': channel.server.SERVER_IDENT, } version = request_data.version if version not in ('1.0', '1.1'): # fall back to a version we support. version = '1.0' self.version = version ############################################################ # Implementation methods for interface # Zope.Server.ITask def service(self): 'See Zope.Server.ITask.ITask' try: try: self.start() self.channel.server.executeRequest(self) self.finish() except socket.error: self.close_on_finish = 1 if self.channel.adj.log_socket_errors: raise finally: self.channel.end_task(self.close_on_finish) def cancel(self): 'See Zope.Server.ITask.ITask' self.channel.close_when_done() def defer(self): 'See Zope.Server.ITask.ITask' pass # ############################################################ def setResponseStatus(self, status, reason): """See the IHeaderOutput interface.""" self.status = status self.reason = reason def setResponseHeaders(self, mapping): """See the IHeaderOutput interface.""" self.response_headers.update(mapping) def appendResponseHeaders(self, lst): """See the IHeaderOutput interface.""" accum = self.accumulated_headers if accum is None: self.accumulated_headers = accum = [] accum.extend(lst) def wroteResponseHeader(self): """See the IHeaderOutput interface.""" return self.wrote_header def setAuthUserName(self, name): """See the IHeaderOutput interface.""" self.auth_user_name = name def prepareResponseHeaders(self): version = self.version # Figure out whether the connection should be closed. connection = self.request_data.headers.get('CONNECTION', '').lower() close_it = 0 response_headers = self.response_headers if version == '1.0': if connection == 'keep-alive': if not response_headers.has_key('Content-Length'): close_it = 1 else: response_headers['Connection'] = 'Keep-Alive' else: close_it = 1 elif version == '1.1': if connection == 'close': close_it = 1 elif response_headers.has_key ('Transfer-Encoding'): if not response_headers['Transfer-Encoding'] == 'chunked': close_it = 1 elif self.status == '304': # Replying with headers only. pass elif not response_headers.has_key ('Content-Length'): close_it = 1 else: # Close if unrecognized HTTP version. close_it = 1 self.close_on_finish = close_it if close_it: self.response_headers['Connection'] = 'close' def buildResponseHeader(self): self.prepareResponseHeaders() first_line = 'HTTP/%s %s %s' % (self.version, self.status, self.reason) lines = [first_line] + map( lambda hv: '%s: %s' % hv, self.response_headers.items()) accum = self.accumulated_headers if accum is not None: lines.extend(accum) res = '%s\r\n\r\n' % '\r\n'.join(lines) return res def getCGIEnvironment(self): """Returns a CGI-like environment.""" env = self.cgi_env if env is not None: # Return the cached copy. return env request_data = self.request_data path = request_data.path channel = self.channel server = channel.server while path and path.startswith('/'): path = path[1:] env = {} env['REQUEST_METHOD'] = request_data.command.upper() env['SERVER_PORT'] = str(server.port) env['SERVER_NAME'] = server.server_name env['SERVER_SOFTWARE'] = server.SERVER_IDENT env['SERVER_PROTOCOL'] = "HTTP/%s" % self.version env['CHANNEL_CREATION_TIME'] = channel.creation_time env['SCRIPT_NAME']='' env['PATH_INFO']='/' + path query = request_data.query if query: env['QUERY_STRING'] = query env['GATEWAY_INTERFACE'] = 'CGI/1.1' addr = channel.addr[0] env['REMOTE_ADDR'] = addr # If the server has a resolver, try to get the # remote host from the resolver's cache. resolver = getattr(server, 'resolver', None) if resolver is not None: dns_cache = resolver.cache if dns_cache.has_key(addr): remote_host = dns_cache[addr][2] if remote_host is not None: env['REMOTE_HOST'] = remote_host env_has = env.has_key for key, value in request_data.headers.items(): value = value.strip() mykey = rename_headers.get(key, None) if mykey is None: mykey = 'HTTP_%s' % key if not env_has(mykey): env[mykey] = value self.cgi_env = env return env def start(self): now = time.time() self.start_time = now self.response_headers['Date'] = build_http_date (now) def finish(self): if not self.wrote_header: self.write('') hit_log = self.channel.server.hit_log if hit_log is not None: hit_log.log(self) def write(self, data): channel = self.channel if not self.wrote_header: rh = self.buildResponseHeader() channel.write(rh) self.bytes_written += len(rh) self.wrote_header = 1 if data: channel.write(data) self.bytes_written += len(data) def flush(self): self.channel.flush() === Added File Zope3/lib/python/Zope/Server/HTTP/PublisherHTTPServer.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: PublisherHTTPServer.py,v 1.1.4.1 2002/04/12 21:30:56 shane Exp $ """ from HTTPServer import HTTPServer from Zope.Publisher.Publish import publish class PublisherHTTPServer(HTTPServer): """Zope Publisher-specific HTTP Server""" __implements__ = HTTPServer.__implements__ def __init__(self, request_factory, sub_protocol=None, *args, **kw): self.request_factory = request_factory # An HTTP server is not limited to server up HTML; it can be # used for other protocols, like XML-RPC, SOAP and so as well # Here we just allow the logger to output the sub-protocol type. if sub_protocol: self.SERVER_IDENT += ' (%s)' %sub_protocol HTTPServer.__init__(self, *args, **kw) def executeRequest(self, task): """Overrides HTTPServer.executeRequest().""" env = task.getCGIEnvironment() instream = task.request_data.getBodyStream() request = self.request_factory(instream, task, env) response = request.getResponse() response.setHeaderOutput(task) publish(request) === Added File Zope3/lib/python/Zope/Server/HTTP/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.4.1 2002/04/12 21:30:56 shane Exp $ """ === Added File Zope3/lib/python/Zope/Server/HTTP/http_date.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: http_date.py,v 1.1.4.1 2002/04/12 21:30:56 shane Exp $ """ import re import string import time def concat (*args): return ''.join (args) def join (seq, field=' '): return field.join (seq) def group (s): return '(' + s + ')' short_days = ['sun','mon','tue','wed','thu','fri','sat'] long_days = ['sunday','monday','tuesday','wednesday', 'thursday','friday','saturday'] short_day_reg = group(join (short_days, '|')) long_day_reg = group(join (long_days, '|')) daymap = {} for i in range(7): daymap[short_days[i]] = i daymap[long_days[i]] = i hms_reg = join (3 * [group('[0-9][0-9]')], ':') months = ['jan','feb','mar','apr','may','jun','jul', 'aug','sep','oct','nov','dec'] monmap = {} for i in range(12): monmap[months[i]] = i+1 months_reg = group (join (months, '|')) # From draft-ietf-http-v11-spec-07.txt/3.3.1 # Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 # Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 # Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format # rfc822 format rfc822_date = join ( [concat (short_day_reg,','), # day group('[0-9][0-9]?'), # date months_reg, # month group('[0-9]+'), # year hms_reg, # hour minute second 'gmt' ], ' ' ) rfc822_reg = re.compile (rfc822_date) def unpack_rfc822 (m): g = m.group a = string.atoi return ( a(g(4)), # year monmap[g(3)], # month a(g(2)), # day a(g(5)), # hour a(g(6)), # minute a(g(7)), # second 0, 0, 0 ) # rfc850 format rfc850_date = join ( [concat (long_day_reg,','), join ( [group ('[0-9][0-9]?'), months_reg, group ('[0-9]+') ], '-' ), hms_reg, 'gmt' ], ' ' ) rfc850_reg = re.compile (rfc850_date) # they actually unpack the same way def unpack_rfc850 (m): g = m.group a = string.atoi return ( a(g(4)), # year monmap[g(3)], # month a(g(2)), # day a(g(5)), # hour a(g(6)), # minute a(g(7)), # second 0, 0, 0 ) # parsdate.parsedate - ~700/sec. # parse_http_date - ~1333/sec. weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] monthname = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] def build_http_date (when): year, month, day, hh, mm, ss, wd, y, z = time.gmtime(when) return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % ( weekdayname[wd], day, monthname[month], year, hh, mm, ss) def parse_http_date (d): d = string.lower (d) tz = time.timezone m = rfc850_reg.match (d) if m and m.end() == len(d): retval = int (time.mktime (unpack_rfc850(m)) - tz) else: m = rfc822_reg.match (d) if m and m.end() == len(d): retval = int (time.mktime (unpack_rfc822(m)) - tz) else: return 0 # Thanks to Craig Silverstein for pointing # out the DST discrepancy if time.daylight and time.localtime(retval)[-1] == 1: # DST correction retval = retval + (tz - time.altzone) return retval From shane@cvs.zope.org Fri Apr 12 22:31:01 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:01 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/contrib - bobo_handler.py:NONE sample_cgi.py:NONE Message-ID: <200204122131.g3CLV1G21194@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/contrib In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/medusa/contrib Removed Files: Tag: Zope-3x-branch bobo_handler.py sample_cgi.py Log Message: Merged Zope3-Server-Branch. === Removed File Zope3/lib/python/Zope/Server/medusa/contrib/bobo_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/contrib/sample_cgi.py === From shane@cvs.zope.org Fri Apr 12 22:31:03 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:03 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/docs - README.html:NONE composing_producers.gif:NONE data_flow.gif:NONE data_flow.html:NONE producers.gif:NONE proxy_notes.txt:NONE Message-ID: <200204122131.g3CLV3c21249@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/docs In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/medusa/docs Removed Files: Tag: Zope-3x-branch README.html composing_producers.gif data_flow.gif data_flow.html producers.gif proxy_notes.txt Log Message: Merged Zope3-Server-Branch. === Removed File Zope3/lib/python/Zope/Server/medusa/docs/README.html === === Removed File Zope3/lib/python/Zope/Server/medusa/docs/composing_producers.gif === === Removed File Zope3/lib/python/Zope/Server/medusa/docs/data_flow.gif === === Removed File Zope3/lib/python/Zope/Server/medusa/docs/data_flow.html === === Removed File Zope3/lib/python/Zope/Server/medusa/docs/producers.gif === === Removed File Zope3/lib/python/Zope/Server/medusa/docs/proxy_notes.txt === From shane@cvs.zope.org Fri Apr 12 22:31:00 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:00 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - IFilesystemAccess.py:1.1.4.1 IPosixFileSystem.py:1.1.4.1 IReadFileSystem.py:1.1.4.1 IUsernamePassword.py:1.1.4.1 IWriteFileSystem.py:1.1.4.1 OSFileSystem.py:1.1.4.1 PublisherFileSystem.py:1.1.4.1 TestFilesystemAccess.py:1.1.4.1 UsernamePassword.py:1.1.4.1 __init__.py:1.1.4.1 Message-ID: <200204122131.g3CLV0T21179@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/VFS Added Files: Tag: Zope-3x-branch IFilesystemAccess.py IPosixFileSystem.py IReadFileSystem.py IUsernamePassword.py IWriteFileSystem.py OSFileSystem.py PublisherFileSystem.py TestFilesystemAccess.py UsernamePassword.py __init__.py Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/Server/VFS/IFilesystemAccess.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IFilesystemAccess.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ from Interface import Interface # XXX This interface should be in a more central location. class IFilesystemAccess(Interface): """Provides authenticated access to a filesystem. """ def authenticate(credentials): """Verifies filesystem access based on the presented credentials. Should raise Unauthorized if the user can not be authenticated. This method only checks general access and is not used for each call to open(). Rather, open() should do its own verification. """ def open(credentials): """Returns an IReadFilesystem or IWriteFilesystem. Should raise Unauthorized if the user can not be authenticated. """ === Added File Zope3/lib/python/Zope/Server/VFS/IPosixFileSystem.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IPosixFileSystem.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ from IWriteFileSystem import IWriteFileSystem from IReadFileSystem import IReadFileSystem class IPosixFileSystem(IWriteFileSystem, IReadFileSystem): """ """ def chmod(path, mode): """Change the access permissions of a file. """ def chown(path, uid, gid): """Change the owner and group id of path to numeric uid and gid. """ def link(src, dst): """Create a heard link to a file. """ def mkfifo(path, mode=777): """Create a FIFO (a POSIX named pipe). """ def symlink(src, dst): """Create a symbolic link at dst pointing to src. """ === Added File Zope3/lib/python/Zope/Server/VFS/IReadFileSystem.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IReadFileSystem.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ from Interface import Interface class IReadFileSystem(Interface): """We want to provide a complete wrapper around any and all read filesystem operations. Opening files for reading, and listing directories, should return a producer. All paths are POSIX paths, even when run on Windows, which mainly means that FS implementations always expect forward slashes, and filenames are case-sensitive. Note: A file system should *not* store any state! """ def exists(path): """Test whether a path exists. """ def isdir(path): """Test whether a path is a directory. """ def isfile(path): """Test whether a path is a file. """ def listdir(path, with_stats=0, pattern='*'): """Return a listing of the directory at 'path' The empty string indicates the current directory. If 'with_stats' is set, instead return a list of (name, stat_info) tuples. All file names are filtered by the globbing pattern. (See the 'glob' module in the Python standard library.) """ return list(tuple(str, str)) def readfile(path, mode, outstream, start=0, end=-1): """Outputs the file at path to a stream. """ def stat(path): """Return the equivalent of os.stat() on the given path: (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) """ === Added File Zope3/lib/python/Zope/Server/VFS/IUsernamePassword.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IUsernamePassword.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ from Interface import Interface # XXX These interfaces should be located in a more central location. # (so I don't mind putting them together in one module for now ;-) ) class ICredentials(Interface): """Base interface for presentation of authentication credentials. Different kinds of credentials include username/password, client certificate, IP address and port, etc., including combinations. """ class IUsernamePassword(ICredentials): """A type of authentication credentials consisting of user name and password. The most recognized form of credentials. """ def getUserName(): """Returns the user name presented for authentication. """ def getPassword(): """Returns the password presented for authentication. """ === Added File Zope3/lib/python/Zope/Server/VFS/IWriteFileSystem.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IWriteFileSystem.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ from Interface import Interface class IWriteFileSystem(Interface): """We want to provide a complete wrapper around any and all write filesystem operations. Notes: - A file system should *not* store any state! - Most of the commands copy the functionality given in os. """ def mkdir(path, mode=777): """Create a directory. """ def remove(path): """Remove a file. Same as unlink. """ def rmdir(path): """Remove a directory. """ def rename(old, new): """Rename a file or directory. """ def writefile(path, mode, instream, start=0): """Write data to a file. """ def check_writable(path): """Ensures a path is writable. Throws an IOError if not.""" === Added File Zope3/lib/python/Zope/Server/VFS/OSFileSystem.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: OSFileSystem.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ import os import re import stat import time import fnmatch from IPosixFileSystem import IPosixFileSystem class OSFileSystem(object): """Generic OS FileSystem implementation. The root of this file system is a string describing the path to the directory used as root. """ __implements__ = IPosixFileSystem copy_bytes = 65536 def __init__ (self, root): self.root = root ############################################################ # Implementation methods for interface # Zope.Server.VFS.IPosixFileSystem.IPosixFileSystem def chmod(self, path, mode): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' p = self.translate (path) return os.chmod(p, mode) def chown(self, path, uid, gid): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' p = self.translate (path) return os.chown(p, uid, gid) def link(self, src, dst): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' src = self.translate(src) dst = self.translate(dst) return os.link(src, dst) def mkfifo(self, path, mode=6*2**6): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' return os.mkfifo(path, mode) def symlink(self, src, dst): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' src = self.translate(src) dst = self.translate(dst) return os.symlink(src, dst) ###################################### # from: Zope.Server.VFS.IReadFileSystem.IReadFileSystem def exists(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' p = self.translate(path) return os.path.exists(p) def isdir(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' p = self.translate(path) return os.path.isdir(p) def isfile(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' p = self.translate(path) return os.path.isfile(p) def listdir(self, path, with_stats=0, pattern='*'): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' p = self.translate(path) # list the directory's files ld = os.listdir(p) # filter them using the pattern ld = filter(lambda f, p=pattern, fnm=fnmatch.fnmatch: fnm(f, p), ld) # sort them alphabetically ld.sort() if not with_stats: result = ld else: result = [] for file in ld: path = os.path.join(p, file) stat = safe_stat(path) if stat is not None: result.append((file, stat)) return result def readfile(self, path, mode, outstream, start=0, end=-1): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' p = self.translate(path) instream = open(p, mode) if start: instream.seek(start) pos = start while end < 0 or pos < end: toread = self.copy_bytes if end >= 0: toread = min(toread, end - pos) data = instream.read(toread) if not data: break pos += len(data) outstream.write(data) def stat(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' p = self.translate(path) return os.stat(p) ###################################### # from: Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem def mkdir(self, path, mode=6*2**6): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' p = self.translate(path) return os.mkdir(p, mode) def remove(self, path): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' p = self.translate (path) return os.remove(p) def rmdir(self, path): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' p = self.translate (path) return os.rmdir(p) def rename(self, old, new): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' old = self.translate(old) new = self.translate(new) return os.rename(old, new) def writefile(self, path, mode, instream, start=0): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' p = self.translate(path) outstream = open(p, mode) if start: outstream.seek(start) while 1: data = instream.read(self.copy_bytes) if not data: break outstream.write(data) def check_writable(self, path): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' p = self.translate(path) if os.path.exists(p): remove = 0 else: remove = 1 f = open(p, 'a') # append mode f.close() if remove: os.remove(p) # ############################################################ # utility methods def normalize (self, path): # watch for the ever-sneaky '/+' path element # XXX It is unclear why "/+" is dangerous. It is definitely # unexpected. path = re.sub('/+', '/', path) path = os.path.normpath(path) if path.startswith('..'): # Someone is trying to get lower than the permitted root. # We just ignore it. path = '/' return path def translate (self, path): """We need to join together three separate path components, and do it safely. / use the operating system's path separator. We need to be extremly careful to include the cases where a hacker could attempt to a directory below root! """ # Normalize the directory path = self.normalize(path) # Prepare for joining with root while path.startswith('/'): path = path[1:] # Join path with root return os.path.join(self.root, path) def __repr__ (self): return '' % self.root def safe_stat (path): try: return os.stat(path) except: return None === Added File Zope3/lib/python/Zope/Server/VFS/PublisherFileSystem.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: PublisherFileSystem.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ import os, re import stat import time from cStringIO import StringIO from IReadFileSystem import IReadFileSystem from IWriteFileSystem import IWriteFileSystem from Zope.Publisher.Publish import publish class NoOutput: """An output stream lookalike that warns you if you try to dump anything into it.""" def write(self, data): raise RuntimeError, "Not a writable stream" def flush(self): pass close = flush class PublisherFileSystem: """Generic Publisher FileSystem implementation. """ __implements__ = IReadFileSystem, IWriteFileSystem def __init__ (self, credentials, request_factory): self.credentials = credentials self.request_factory = request_factory def _execute(self, path, command, env=None): if env is None: env = {} env['command'] = command env['path'] = path env['credentials'] = self.credentials # NoOutput avoids creating a black hole. request = self.request_factory(StringIO(''), NoOutput(), env) # Note that publish() calls close() on request, which deletes the # response from the request, so that we need to keep track of it. response = request.getResponse() publish(request) return response.getResult() ############################################################ # Implementation methods for interface # Zope.Server.VFS.IReadFileSystem. def exists(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) if path == '/': return 1 path, file = os.path.split(path) env = {'name': file} return self._execute(path, 'exists', env) def isdir(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) return self._execute(path, 'isdir') def isfile(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) return self._execute(path, 'isfile') def listdir(self, path, with_stats=0, pattern='*'): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) env = {'with_stats' : with_stats, 'pattern' : pattern} return self._execute(path, 'listdir', env) def readfile(self, path, mode, outstream, start=0, end=-1): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) env = {'mode' : mode, 'outstream' : outstream, 'start' : start, 'end' : end} return self._execute(path, 'read', env) def stat(self, path): 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem' path = self.translate(path) return self._execute(path, 'stat') # ############################################################ ############################################################ # Implementation methods for interface # Zope.Server.VFS.IWriteFileSystem. def mkdir(self, path, mode=777): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' path = self.translate(path) path, dir = os.path.split(path) env = {'name': dir} return self._execute(path, 'mkdir', env) def remove(self, path): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' path = self.translate(path) path, name = os.path.split(path) env = {'name': name} return self._execute(path, 'remove', env) def rmdir(self, path): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' path = self.translate(path) path, dir = os.path.split(path) env = {'name': dir} return self._execute(path, 'rmdir', env) def rename(self, old, new): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' old = self.translate(old) new = self.translate(new) path0, old = os.path.split(old) path1, new = os.path.split(new) assert path0 == path1 env = {'old' : old, 'new' : new} return self._execute(path0, 'rename', env) def writefile(self, path, mode, instream, start=0): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' path = self.translate(path) path, name = os.path.split(path) env = {'name' : name, 'mode' : mode, 'instream' : instream, 'start' : start} return self._execute(path, 'writefile', env) def check_writable(self, path): 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem' path = self.translate(path) path, name = os.path.split(path) env = {'name' : name} return self._execute(path, 'check_writable', env) # ############################################################ # utility methods def translate (self, path): # Normalize path = os.path.normpath(path) if path.startswith('..'): # Someone is trying to get lower than the permitted root. # We just ignore it. path = '/' return path === Added File Zope3/lib/python/Zope/Server/VFS/TestFilesystemAccess.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Implementation of IFilesystemAccess intended only for testing. $Id: TestFilesystemAccess.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ from Zope.Server.VFS.IFilesystemAccess import IFilesystemAccess from Zope.Server.VFS.IUsernamePassword import IUsernamePassword from Zope.Exceptions import Unauthorized class TestFilesystemAccess: __implements__ = IFilesystemAccess passwords = {'foo': 'bar'} def __init__(self, fs): self.fs = fs def authenticate(self, credentials): if not IUsernamePassword.isImplementedBy(credentials): raise Unauthorized name = credentials.getUserName() if not self.passwords.has_key(name): raise Unauthorized if credentials.getPassword() != self.passwords[name]: raise Unauthorized def open(self, credentials): self.authenticate(credentials) return self.fs === Added File Zope3/lib/python/Zope/Server/VFS/UsernamePassword.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: UsernamePassword.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ from Zope.Server.VFS.IUsernamePassword import IUsernamePassword class UsernamePassword: __implements__ = IUsernamePassword def __init__(self, username, password): self.username = username self.password = password def getUserName(self): return self.username def getPassword(self): return self.password === Added File Zope3/lib/python/Zope/Server/VFS/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ From shane@cvs.zope.org Fri Apr 12 22:31:00 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:00 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/Logger - FileLogger.py:1.1.4.1 ILogger.py:1.1.4.1 MultiLogger.py:1.1.4.1 ResolvingLogger.py:1.1.4.1 RotatingFileLogger.py:1.1.4.1 SocketLogger.py:1.1.4.1 SyslogLogger.py:1.1.4.1 TailLogger.py:1.1.4.1 UnresolvingLogger.py:1.1.4.1 __init__.py:1.1.4.1 m_syslog.py:1.1.4.1 Message-ID: <200204122131.g3CLV0w21158@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/Logger In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/Logger Added Files: Tag: Zope-3x-branch FileLogger.py ILogger.py MultiLogger.py ResolvingLogger.py RotatingFileLogger.py SocketLogger.py SyslogLogger.py TailLogger.py UnresolvingLogger.py __init__.py m_syslog.py Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/Server/Logger/FileLogger.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: FileLogger.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ from types import StringType from ILogger import ILogger class FileLogger: """Simple File Logger """ __implements__ = ILogger def __init__ (self, file, flush=1, mode='a'): """pass this either a path or a file object.""" if type(file) is StringType: if (file == '-'): import sys self.file = sys.stdout else: self.file = open (file, mode) else: self.file = file self.do_flush = flush def __repr__ (self): return '' % self.file def write (self, data): self.file.write (data) self.maybe_flush() def writeline (self, line): self.file.writeline (line) self.maybe_flush() def writelines (self, lines): self.file.writelines (lines) self.maybe_flush() def maybe_flush (self): if self.do_flush: self.file.flush() def flush (self): self.file.flush() def softspace (self, *args): pass ############################################################ # Implementation methods for interface # Zope.Server.Logger.ILogger def log(self, message): 'See Zope.Server.Logger.ILogger.ILogger' if message[-1] not in ('\r', '\n'): self.write (message + '\n') else: self.write (message) # ############################################################ === Added File Zope3/lib/python/Zope/Server/Logger/ILogger.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: ILogger.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ from Interface import Interface class ILogger(Interface): """This interface describes the methods any Logging object has to implement. """ def log(message): """Logs the passed message at the appropriate place.""" === Added File Zope3/lib/python/Zope/Server/Logger/MultiLogger.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: MultiLogger.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ import asynchat import socket import time # these three are for the rotating logger import os # | import stat # v from types import StringType class MultiLogger: """Log to multiple places.""" def __init__ (self, loggers): self.loggers = loggers def __repr__ (self): return '' % (repr(self.loggers)) def log (self, message): for logger in self.loggers: logger.log (message) class ResolvingLogger: """Feed (ip, message) combinations into this logger to get a resolved hostname in front of the message. The message will not be logged until the PTR request finishes (or fails).""" def __init__ (self, resolver, logger): self.resolver = resolver self.logger = logger class logger_thunk: def __init__ (self, message, logger): self.message = message self.logger = logger def __call__ (self, host, ttl, answer): if not answer: answer = host self.logger.log ('%s%s' % (answer, self.message)) def log (self, ip, message): self.resolver.resolve_ptr ( ip, self.logger_thunk ( message, self.logger ) ) class UnresolvingLogger: """Just in case you don't want to resolve""" def __init__ (self, logger): self.logger = logger def log (self, ip, message): self.logger.log ('%s%s' % (ip, message)) def strip_eol (line): while line and line[-1] in '\r\n': line = line[:-1] return line class TailLogger: """Keep track of the last log messages""" def __init__ (self, logger, size=500): self.size = size self.logger = logger self.messages = [] def log (self, message): self.messages.append (strip_eol (message)) if len (self.messages) > self.size: del self.messages[0] self.logger.log (message) === Added File Zope3/lib/python/Zope/Server/Logger/ResolvingLogger.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: ResolvingLogger.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ from ILogger import ILogger class ResolvingLogger: """Feed (ip, message) combinations into this logger to get a resolved hostname in front of the message. The message will not be logged until the PTR request finishes (or fails).""" __implements__ = ILogger def __init__ (self, resolver, logger): self.resolver = resolver self.logger = logger class logger_thunk: def __init__ (self, message, logger): self.message = message self.logger = logger def __call__ (self, host, ttl, answer): if not answer: answer = host self.logger.log ('%s: %s' % (answer, self.message)) ############################################################ # Implementation methods for interface # Zope.Server.Logger.ILogger def log(self, ip, message): 'See Zope.Server.Logger.ILogger.ILogger' self.resolver.resolve_ptr ( ip, self.logger_thunk ( message, self.logger ) ) # ############################################################ === Added File Zope3/lib/python/Zope/Server/Logger/RotatingFileLogger.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: RotatingFileLogger.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ import time import os import stat from FileLogger import FileLogger class RotatingFileLogger(FileLogger): """ If freq is non-None we back up 'daily', 'weekly', or 'monthly'. Else if maxsize is non-None we back up whenever the log gets to big. If both are None we never back up. Like a FileLogger, but it must be attached to a filename. When the log gets too full, or a certain time has passed, it backs up the log and starts a new one. Note that backing up the log is done via 'mv' because anything else (cp, gzip) would take time, during which medusa would do nothing else. """ __implements__ = FileLogger.__implements__ def __init__ (self, file, freq=None, maxsize=None, flush=1, mode='a'): self.filename = file self.mode = mode self.file = open (file, mode) self.freq = freq self.maxsize = maxsize self.rotate_when = self.next_backup(self.freq) self.do_flush = flush def __repr__ (self): return '' % self.file # We back up at midnight every 1) day, 2) monday, or 3) 1st of month def next_backup (self, freq): (yr, mo, day, hr, min, sec, wd, jday, dst) = \ time.localtime(time.time()) if freq == 'daily': return time.mktime((yr,mo,day+1, 0,0,0, 0,0,-1)) elif freq == 'weekly': # wd(monday)==0 return time.mktime((yr,mo,day-wd+7, 0,0,0, 0,0,-1)) elif freq == 'monthly': return time.mktime((yr,mo+1,1, 0,0,0, 0,0,-1)) else: return None # not a date-based backup def maybe_flush (self): # rotate first if necessary self.maybe_rotate() if self.do_flush: # from file_logger() self.file.flush() def maybe_rotate (self): if self.freq and time.time() > self.rotate_when: self.rotate() self.rotate_when = self.next_backup(self.freq) elif self.maxsize: # rotate when we get too big try: if os.stat(self.filename)[stat.ST_SIZE] > self.maxsize: self.rotate() except os.error: # file not found, probably self.rotate() # will create a new file def rotate (self): (yr, mo, day, hr, min, sec, wd, jday, dst) = \ time.localtime(time.time()) try: self.file.close() newname = '%s.ends%04d%02d%02d' % (self.filename, yr, mo, day) try: open(newname, "r").close() # check if file exists newname = newname + "-%02d%02d%02d" % (hr, min, sec) except: # YEARMODY is unique pass os.rename(self.filename, newname) self.file = open(self.filename, self.mode) except: pass === Added File Zope3/lib/python/Zope/Server/Logger/SocketLogger.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: SocketLogger.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ import asynchat import socket from ILogger import ILogger class SocketLogger (asynchat.async_chat): """Log to a stream socket, asynchronously.""" __implements__ = ILogger def __init__ (self, address): if type(address) == type(''): self.create_socket (socket.AF_UNIX, socket.SOCK_STREAM) else: self.create_socket (socket.AF_INET, socket.SOCK_STREAM) self.connect (address) self.address = address def __repr__ (self): return '' % (self.address) ############################################################ # Implementation methods for interface # Zope.Server.Logger.ILogger def log(self, message): 'See Zope.Server.Logger.ILogger.ILogger' if message[-2:] != '\r\n': self.socket.push (message + '\r\n') else: self.socket.push (message) # ############################################################ === Added File Zope3/lib/python/Zope/Server/Logger/SyslogLogger.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: SyslogLogger.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ import os import m_syslog from ILogger import ILogger class SyslogLogger(m_syslog.syslog_client): """syslog is a line-oriented log protocol - this class would be appropriate for FTP or HTTP logs, but not for dumping stderr to. XXX: a simple safety wrapper that will ensure that the line sent to syslog is reasonable. XXX: async version of syslog_client: now, log entries use blocking send() """ __implements__ = ILogger svc_name = 'zope' pid_str = str(os.getpid()) def __init__ (self, address, facility='user'): m_syslog.syslog_client.__init__ (self, address) self.facility = m_syslog.facility_names[facility] self.address=address def __repr__ (self): return '' % (repr(self.address)) ############################################################ # Implementation methods for interface # Zope.Server.Logger.ILogger def log(self, message): 'See Zope.Server.Logger.ILogger.ILogger' m_syslog.syslog_client.log ( self, '%s[%s]: %s' % (self.svc_name, self.pid_str, message), facility=self.facility, priority=m_syslog.LOG_INFO ) # ############################################################ === Added File Zope3/lib/python/Zope/Server/Logger/TailLogger.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: TailLogger.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ from ILogger import ILogger class TailLogger: """Keep track of the last log messages""" __implements__ = ILogger def __init__ (self, logger, size=500): self.size = size self.logger = logger self.messages = [] ############################################################ # Implementation methods for interface # Zope.Server.Logger.ILogger def log(self, message): 'See Zope.Server.Logger.ILogger.ILogger' self.messages.append (strip_eol (message)) if len (self.messages) > self.size: del self.messages[0] self.logger.log (message) # ############################################################ def strip_eol (line): while line and line[-1] in '\r\n': line = line[:-1] return line === Added File Zope3/lib/python/Zope/Server/Logger/UnresolvingLogger.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: UnresolvingLogger.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ from ILogger import ILogger class UnresolvingLogger: """Just in case you don't want to resolve""" __implements__ = ILogger def __init__ (self, logger): self.logger = logger ############################################################ # Implementation methods for interface # Zope.Server.Logger.ILogger def log(self, ip, message): 'See Zope.Server.Logger.ILogger.ILogger' self.logger.log ('%s: %s' % (ip, message)) # ############################################################ === Added File Zope3/lib/python/Zope/Server/Logger/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $ """ === Added File Zope3/lib/python/Zope/Server/Logger/m_syslog.py === # -*- Mode: Python; tab-width: 4 -*- # ====================================================================== # Copyright 1997 by Sam Rushing # # All Rights Reserved # # Permission to use, copy, modify, and distribute this software and # its documentation for any purpose and without fee is hereby # granted, provided that the above copyright notice appear in all # copies and that both that copyright notice and this permission # notice appear in supporting documentation, and that the name of Sam # Rushing not be used in advertising or publicity pertaining to # distribution of the software without specific, written prior # permission. # # SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN # NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # ====================================================================== """socket interface to unix syslog. On Unix, there are usually two ways of getting to syslog: via a local unix-domain socket, or via the TCP service. Usually "/dev/log" is the unix domain socket. This may be different for other systems. >>> my_client = syslog_client ('/dev/log') Otherwise, just use the UDP version, port 514. >>> my_client = syslog_client (('my_log_host', 514)) On win32, you will have to use the UDP version. Note that you can use this to log to other hosts (and indeed, multiple hosts). This module is not a drop-in replacement for the python extension module - the interface is different. Usage: >>> c = syslog_client() >>> c = syslog_client ('/strange/non_standard_log_location') >>> c = syslog_client (('other_host.com', 514)) >>> c.log ('testing', facility='local0', priority='debug') """ # TODO: support named-pipe syslog. # [see ftp://sunsite.unc.edu/pub/Linux/system/Daemons/syslog-fifo.tar.z] # from : # =========================================================================== # priorities/facilities are encoded into a single 32-bit quantity, where the # bottom 3 bits are the priority (0-7) and the top 28 bits are the facility # (0-big number). Both the priorities and the facilities map roughly # one-to-one to strings in the syslogd(8) source code. This mapping is # included in this file. # # priorities (these are ordered) LOG_EMERG = 0 # system is unusable LOG_ALERT = 1 # action must be taken immediately LOG_CRIT = 2 # critical conditions LOG_ERR = 3 # error conditions LOG_WARNING = 4 # warning conditions LOG_NOTICE = 5 # normal but significant condition LOG_INFO = 6 # informational LOG_DEBUG = 7 # debug-level messages # facility codes LOG_KERN = 0 # kernel messages LOG_USER = 1 # random user-level messages LOG_MAIL = 2 # mail system LOG_DAEMON = 3 # system daemons LOG_AUTH = 4 # security/authorization messages LOG_SYSLOG = 5 # messages generated internally by syslogd LOG_LPR = 6 # line printer subsystem LOG_NEWS = 7 # network news subsystem LOG_UUCP = 8 # UUCP subsystem LOG_CRON = 9 # clock daemon LOG_AUTHPRIV = 10 # security/authorization messages (private) # other codes through 15 reserved for system use LOG_LOCAL0 = 16 # reserved for local use LOG_LOCAL1 = 17 # reserved for local use LOG_LOCAL2 = 18 # reserved for local use LOG_LOCAL3 = 19 # reserved for local use LOG_LOCAL4 = 20 # reserved for local use LOG_LOCAL5 = 21 # reserved for local use LOG_LOCAL6 = 22 # reserved for local use LOG_LOCAL7 = 23 # reserved for local use priority_names = { "alert": LOG_ALERT, "crit": LOG_CRIT, "debug": LOG_DEBUG, "emerg": LOG_EMERG, "err": LOG_ERR, "error": LOG_ERR, # DEPRECATED "info": LOG_INFO, "notice": LOG_NOTICE, "panic": LOG_EMERG, # DEPRECATED "warn": LOG_WARNING, # DEPRECATED "warning": LOG_WARNING, } facility_names = { "auth": LOG_AUTH, "authpriv": LOG_AUTHPRIV, "cron": LOG_CRON, "daemon": LOG_DAEMON, "kern": LOG_KERN, "lpr": LOG_LPR, "mail": LOG_MAIL, "news": LOG_NEWS, "security": LOG_AUTH, # DEPRECATED "syslog": LOG_SYSLOG, "user": LOG_USER, "uucp": LOG_UUCP, "local0": LOG_LOCAL0, "local1": LOG_LOCAL1, "local2": LOG_LOCAL2, "local3": LOG_LOCAL3, "local4": LOG_LOCAL4, "local5": LOG_LOCAL5, "local6": LOG_LOCAL6, "local7": LOG_LOCAL7, } import socket class syslog_client: def __init__ (self, address='/dev/log'): self.address = address if type (address) == type(''): try: # APUE 13.4.2 specifes /dev/log as datagram socket self.socket = socket.socket( socket.AF_UNIX , socket.SOCK_DGRAM) self.socket.connect (address) except: # older linux may create as stream socket self.socket = socket.socket( socket.AF_UNIX , socket.SOCK_STREAM) self.socket.connect (address) self.unix = 1 else: self.socket = socket.socket( socket.AF_INET , socket.SOCK_DGRAM) self.unix = 0 log_format_string = '<%d>%s\000' def log (self, message, facility=LOG_USER, priority=LOG_INFO): message = self.log_format_string % ( self.encode_priority (facility, priority), message ) if self.unix: self.socket.send (message) else: self.socket.sendto (message, self.address) def encode_priority (self, facility, priority): if type(facility) == type(''): facility = facility_names[facility] if type(priority) == type(''): priority = priority_names[priority] return (facility<<3) | priority def close (self): if self.unix: self.socket.close() From shane@cvs.zope.org Fri Apr 12 22:31:04 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:04 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/sendfile - README:NONE asynchat_sendfile.py:NONE sendfilemodule.c:NONE test_sendfile.py:NONE Message-ID: <200204122131.g3CLV4R21290@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/sendfile In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/medusa/sendfile Removed Files: Tag: Zope-3x-branch README asynchat_sendfile.py sendfilemodule.c test_sendfile.py Log Message: Merged Zope3-Server-Branch. === Removed File Zope3/lib/python/Zope/Server/medusa/sendfile/README === === Removed File Zope3/lib/python/Zope/Server/medusa/sendfile/asynchat_sendfile.py === === Removed File Zope3/lib/python/Zope/Server/medusa/sendfile/sendfilemodule.c === === Removed File Zope3/lib/python/Zope/Server/medusa/sendfile/test_sendfile.py === From shane@cvs.zope.org Fri Apr 12 22:31:02 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:02 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/dist - license.html:NONE Message-ID: <200204122131.g3CLV2n21222@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/dist In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/medusa/dist Removed Files: Tag: Zope-3x-branch license.html Log Message: Merged Zope3-Server-Branch. === Removed File Zope3/lib/python/Zope/Server/medusa/dist/license.html === From shane@cvs.zope.org Fri Apr 12 22:31:03 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:03 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/misc - async_mysql.py:NONE recorder.py:NONE syncsock.py:NONE Message-ID: <200204122131.g3CLV3G21250@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/misc In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/medusa/misc Removed Files: Tag: Zope-3x-branch async_mysql.py recorder.py syncsock.py Log Message: Merged Zope3-Server-Branch. === Removed File Zope3/lib/python/Zope/Server/medusa/misc/async_mysql.py === === Removed File Zope3/lib/python/Zope/Server/medusa/misc/recorder.py === === Removed File Zope3/lib/python/Zope/Server/medusa/misc/syncsock.py === From shane@cvs.zope.org Fri Apr 12 22:31:04 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:04 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/test - __init__.py:NONE asyn_http_bench.py:NONE max_sockets.py:NONE test_11.py:NONE test_lb.py:NONE test_medusa.py:NONE test_single_11.py:NONE tests.txt:NONE Message-ID: <200204122131.g3CLV4921297@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/test In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/medusa/test Removed Files: Tag: Zope-3x-branch __init__.py asyn_http_bench.py max_sockets.py test_11.py test_lb.py test_medusa.py test_single_11.py tests.txt Log Message: Merged Zope3-Server-Branch. === Removed File Zope3/lib/python/Zope/Server/medusa/test/__init__.py === === Removed File Zope3/lib/python/Zope/Server/medusa/test/asyn_http_bench.py === === Removed File Zope3/lib/python/Zope/Server/medusa/test/max_sockets.py === === Removed File Zope3/lib/python/Zope/Server/medusa/test/test_11.py === === Removed File Zope3/lib/python/Zope/Server/medusa/test/test_lb.py === === Removed File Zope3/lib/python/Zope/Server/medusa/test/test_medusa.py === === Removed File Zope3/lib/python/Zope/Server/medusa/test/test_single_11.py === === Removed File Zope3/lib/python/Zope/Server/medusa/test/tests.txt === From shane@cvs.zope.org Fri Apr 12 22:31:06 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:06 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/StartUp - RequestFactory.py:1.1.2.3 ServerType.py:1.1.2.3 SiteDefinition.py:1.1.2.2 startup-registry.zcml:1.1.2.2 Message-ID: <200204122131.g3CLV6E21339@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/StartUp In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/StartUp Modified Files: Tag: Zope-3x-branch RequestFactory.py ServerType.py SiteDefinition.py startup-registry.zcml Log Message: Merged Zope3-Server-Branch. === Zope3/lib/python/Zope/StartUp/RequestFactory.py 1.1.2.2 => 1.1.2.3 === # ############################################################################## -""" - -$Id$ -""" - -from Interface import Interface -import copy - - -class IRequestFactory(Interface): - """This is a pure read-only interface, since the values are set through - a ZCML directive and we shouldn't be able to change them. - """ - - def realize(db): - """Realize the factory by initalizing the publication. - - The method returns the realized object. - """ - - - def __call__(input_stream, output_steam, env): - """Call the Request Factory""" - - - - - -class RequestFactory: - """This class will generically create RequestFactories. This way I do - not have to create a method for each Server Type there is. - """ - - __implements__ = IRequestFactory - - def __init__(self, publication, request): - """Initialize Request Factory""" - self._pubFactory = publication - self._publication = None - self._request = request - - - ############################################################ - # Implementation methods for interface - # Zope.StartUp.RequestFactory.IRequestFactory - - def realize(self, db): - 'See Zope.StartUp.RequestFactory.IRequestFactory' - realized = copy.copy(self) - realized._publication = realized._pubFactory(db) - return realized - - - def __call__(self, input_stream, output_steam, env): - 'See Zope.StartUp.RequestFactory.IRequestFactory' - request = self._request(input_stream, output_steam, env) - request.setPublication(self._publication) - return request - - # - ############################################################ +"""ctory.py,v 1.1.2.2 2002/04/02 02:20:40 srichter Exp $ +""" + +from Interface import Interface +import copy + + +class IRequestFactory(Interface): + """This is a pure read-only interface, since the values are set through + a ZCML directive and we shouldn't be able to change them. + """ + + def realize(db): + """Realize the factory by initalizing the publication. + + The method returns the realized object. + """ + + + def __call__(input_stream, output_steam, env): + """Call the Request Factory""" + + + + + +class RequestFactory: + """This class will generically create RequestFactories. This way I do + not have to create a method for each Server Type there is. + """ + + __implements__ = IRequestFactory + + def __init__(self, publication, request): + """Initialize Request Factory""" + self._pubFactory = publication + self._publication = None + self._request = request + + + ############################################################ + # Implementation methods for interface + # Zope.StartUp.RequestFactory.IRequestFactory + + def realize(self, db): + 'See Zope.StartUp.RequestFactory.IRequestFactory' + realized = copy.copy(self) + realized._publication = realized._pubFactory(db) + return realized + + + def __call__(self, input_stream, output_steam, env): + 'See Zope.StartUp.RequestFactory.IRequestFactory' + request = self._request(input_stream, output_steam, env) + request.setPublication(self._publication) + return request + + # + ############################################################ === Zope3/lib/python/Zope/StartUp/ServerType.py 1.1.2.2 => 1.1.2.3 === # ############################################################################## -""" - -$Id$ -""" - -from Interface import Interface -from RequestFactoryRegistry import getRequestFactory - - -class IServerType(Interface): - """This is a pure read-only interface, since the values are set through - a ZCML directive and we shouldn't be able to change them. - """ - - def create(task_dispatcher, db, port=None, verbose=None): - """Create the server knowing the port, task dispatcher and the ZODB. - """ - - -class ServerType: - - __implements__ = IServerType - - - def __init__(self, name, factory, requestFactory, logFactory, - defaultPort, defaultVerbose): - """ """ - self._name = name - self._factory = factory - self._requestFactory = requestFactory - self._logFactory = logFactory - self._defaultPort = defaultPort - self._defaultVerbose = defaultVerbose - - - ############################################################ - # Implementation methods for interface - # Zope.StartUp.ServerType.IServerType - - def create(self, task_dispatcher, db, port=None, verbose=None): - 'See Zope.StartUp.ServerType.IServerType' - - - request_factory = getRequestFactory(self._requestFactory) - request_factory = request_factory.realize(db) - - if port is None: - port = self._defaultPort - - if verbose is None: - verbose = self._defaultVerbose - - apply(self._factory, - (request_factory, self._name, '', port), - {'task_dispatcher': task_dispatcher, - 'verbose': verbose, - 'hit_log': self._logFactory()}) - - # - ############################################################ - - +"""e.py,v 1.1.2.2 2002/04/02 02:20:40 srichter Exp $ +""" + +from Interface import Interface +from RequestFactoryRegistry import getRequestFactory + + +class IServerType(Interface): + """This is a pure read-only interface, since the values are set through + a ZCML directive and we shouldn't be able to change them. + """ + + def create(task_dispatcher, db, port=None, verbose=None): + """Create the server knowing the port, task dispatcher and the ZODB. + """ + + +class ServerType: + + __implements__ = IServerType + + + def __init__(self, name, factory, requestFactory, logFactory, + defaultPort, defaultVerbose): + """ """ + self._name = name + self._factory = factory + self._requestFactory = requestFactory + self._logFactory = logFactory + self._defaultPort = defaultPort + self._defaultVerbose = defaultVerbose + + + ############################################################ + # Implementation methods for interface + # Zope.StartUp.ServerType.IServerType + + def create(self, task_dispatcher, db, port=None, verbose=None): + 'See Zope.StartUp.ServerType.IServerType' + + request_factory = getRequestFactory(self._requestFactory) + request_factory = request_factory.realize(db) + + if port is None: + port = self._defaultPort + + if verbose is None: + verbose = self._defaultVerbose + + apply(self._factory, + (request_factory, self._name, '', port), + {'task_dispatcher': task_dispatcher, + 'verbose': verbose, + 'hit_log': self._logFactory()}) + + # + ############################################################ + + === Zope3/lib/python/Zope/StartUp/SiteDefinition.py 1.1.2.1 => 1.1.2.2 === # not create one. self._initDB() - + # Start the servers for type, server_info in self._servers.items(): server = getServerType(type) - server.create(td, self._zodb, server_info['port'], server_info['verbose']) - def _initDB(self): """Initialize the ZODB""" === Zope3/lib/python/Zope/StartUp/startup-registry.zcml 1.1.2.1 => 1.1.2.2 === + + + + + + From shane@cvs.zope.org Fri Apr 12 22:31:00 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:00 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS/tests - PosixFilesystemTests.py:1.1.4.1 ReadFilesystemTests.py:1.1.4.1 WriteFilesystemTests.py:1.1.4.1 __init__.py:1.1.4.1 testOSFileSystem.py:1.1.4.1 testPublisherFilesystem.py:1.1.4.1 Message-ID: <200204122131.g3CLV0Y21181@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS/tests In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/VFS/tests Added Files: Tag: Zope-3x-branch PosixFilesystemTests.py ReadFilesystemTests.py WriteFilesystemTests.py __init__.py testOSFileSystem.py testPublisherFilesystem.py Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/Server/VFS/tests/PosixFilesystemTests.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: PosixFilesystemTests.py,v 1.1.4.1 2002/04/12 21:30:59 shane Exp $ """ import stat from Interface.Verify import verifyClass from Zope.Server.VFS.IPosixFileSystem import IPosixFileSystem from WriteFilesystemTests import WriteFilesystemTests class PosixFilesystemTests (WriteFilesystemTests): """Tests of a writable and readable POSIX-compliant filesystem """ def testChmod(self): old_mode = self.filesystem.stat(self.file_name)[stat.ST_MODE] new_mode = old_mode ^ 0444 self.filesystem.chmod(self.file_name, new_mode) check_mode = self.filesystem.stat(self.file_name)[stat.ST_MODE] self.assertEqual(check_mode, new_mode) def testChown(self): self.filesystem.chown(self.file_name, 500, 500) s = self.filesystem.stat(self.file_name) self.assertEqual(s[stat.ST_UID], 500) self.assertEqual(s[stat.ST_GID], 500) def testMakeLink(self): self.filesystem.link(self.file_name, self.file_name + '.linked') self.failUnless(self.filesystem.exists(self.file_name + '.linked')) # Another test should test whether writing to one file # changes the other. def testMakeFifo(self): path = self.dir_name + '/fifo' self.filesystem.mkfifo(path) self.failUnless(self.filesystem.exists(path)) # Another test should test the behavior of the fifo. def testMakeSymlink(self): self.filesystem.symlink(self.file_name, self.file_name + '.symlink') self.failUnless(self.filesystem.exists(self.file_name + '.symlink')) # Another test should test whether writing to one file # changes the other. def testPosixInterface(self): class_ = self.filesystem.__class__ self.failUnless( IPosixFileSystem.isImplementedByInstancesOf(class_)) self.failUnless(verifyClass(IPosixFileSystem, class_)) def test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(OSFileSystemTest) if __name__=='__main__': unittest.TextTestRunner().run( test_suite() ) === Added File Zope3/lib/python/Zope/Server/VFS/tests/ReadFilesystemTests.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: ReadFilesystemTests.py,v 1.1.4.1 2002/04/12 21:30:59 shane Exp $ """ import stat from StringIO import StringIO from Interface.Verify import verifyClass from Zope.Server.VFS.IReadFileSystem import IReadFileSystem class ReadFilesystemTests: """Tests of a readable filesystem """ filesystem = None dir_name = '/dir' file_name = '/dir/file.txt' dir_contents = ['file.txt'] file_contents = 'Lengthen your stride' check_exceptions = 1 def testExists(self): self.failUnless(self.filesystem.exists(self.dir_name)) self.failUnless(self.filesystem.exists(self.file_name)) def testIsDir(self): self.failUnless(self.filesystem.isdir(self.dir_name)) self.failUnless(not self.filesystem.isdir(self.file_name)) def testIsFile(self): self.failUnless(self.filesystem.isfile(self.file_name)) self.failUnless(not self.filesystem.isfile(self.dir_name)) def testListDir(self): lst = self.filesystem.listdir(self.dir_name, 0) lst.sort() self.assertEqual(lst, self.dir_contents) def testReadFile(self): s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s) self.assertEqual(s.getvalue(), self.file_contents) def testReadPartOfFile(self): s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s, 2) self.assertEqual(s.getvalue(), self.file_contents[2:]) def testReadPartOfFile2(self): s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s, 1, 5) self.assertEqual(s.getvalue(), self.file_contents[1:5]) def testReadInterface(self): class_ = self.filesystem.__class__ self.failUnless( IReadFileSystem.isImplementedByInstancesOf(class_)) self.failUnless(verifyClass(IReadFileSystem, class_)) === Added File Zope3/lib/python/Zope/Server/VFS/tests/WriteFilesystemTests.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: WriteFilesystemTests.py,v 1.1.4.1 2002/04/12 21:30:59 shane Exp $ """ from StringIO import StringIO from Interface.Verify import verifyClass from Zope.Server.VFS.IWriteFileSystem import IWriteFileSystem from ReadFilesystemTests import ReadFilesystemTests class WriteFilesystemTests (ReadFilesystemTests): """Tests of a writable and readable filesystem """ def testRemove(self): self.failIf(not self.filesystem.exists(self.file_name)) self.filesystem.remove(self.file_name) self.failIf(self.filesystem.exists(self.file_name)) def testMkdir(self): path = self.dir_name + '/x' self.filesystem.mkdir(path) self.failUnless(self.filesystem.exists(path)) self.failUnless(self.filesystem.isdir(path)) def testRmdir(self): self.failIf(not self.filesystem.exists(self.dir_name)) self.filesystem.remove(self.file_name) self.filesystem.rmdir(self.dir_name) self.failIf(self.filesystem.exists(self.dir_name)) def testRename(self): self.filesystem.rename(self.file_name, self.file_name + '.bak') self.failIf(self.filesystem.exists(self.file_name)) self.failIf(not self.filesystem.exists(self.file_name + '.bak')) def testWriteFile(self): s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s) self.assertEqual(s.getvalue(), self.file_contents) data = 'Always ' + self.file_contents s = StringIO(data) self.filesystem.writefile(self.file_name, 'wb', s) s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s) self.assertEqual(s.getvalue(), data) def testAppendToFile(self): data = ' again' s = StringIO(data) self.filesystem.writefile(self.file_name, 'ab', s) s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s) self.assertEqual(s.getvalue(), self.file_contents + data) def testWritePartOfFile(self): data = '123' s = StringIO(data) self.filesystem.writefile(self.file_name, 'r+b', s, 3) expect = self.file_contents[:3] + data + self.file_contents[6:] s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s) self.assertEqual(s.getvalue(), expect) def testWriteBeyondEndOfFile(self): partlen = len(self.file_contents) - 6 data = 'daylight savings' s = StringIO(data) self.filesystem.writefile(self.file_name, 'r+b', s, partlen) expect = self.file_contents[:partlen] + data s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s) self.assertEqual(s.getvalue(), expect) def testWriteNewFile(self): s = StringIO(self.file_contents) self.filesystem.writefile(self.file_name + '.new', 'wb', s) s = StringIO() self.filesystem.readfile(self.file_name, 'rb', s) self.assertEqual(s.getvalue(), self.file_contents) def testCheckWritable(self): if self.check_exceptions: # Can't overwrite a directory. self.assertRaises( IOError, self.filesystem.check_writable, self.dir_name) # Can overwrite a file. try: self.filesystem.check_writable(self.file_name) except IOError, v: self.fail('%s should be writable. (%s)' % (self.file_name, v)) def testWriteInterface(self): class_ = self.filesystem.__class__ self.failUnless( IWriteFileSystem.isImplementedByInstancesOf(class_)) self.failUnless(verifyClass(IWriteFileSystem, class_)) def test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(OSFileSystemTest) if __name__=='__main__': unittest.TextTestRunner().run( test_suite() ) === Added File Zope3/lib/python/Zope/Server/VFS/tests/__init__.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: __init__.py,v 1.1.4.1 2002/04/12 21:30:59 shane Exp $ """ === Added File Zope3/lib/python/Zope/Server/VFS/tests/testOSFileSystem.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: testOSFileSystem.py,v 1.1.4.1 2002/04/12 21:30:59 shane Exp $ """ import unittest import os import shutil import tempfile from StringIO import StringIO from Zope.Server.VFS.OSFileSystem import OSFileSystem from WriteFilesystemTests import WriteFilesystemTests def joinToRoot(root, name): if name.startswith('/'): name = name[1:] return os.path.join(root, os.path.normpath(name)) class OSFileSystemTests(unittest.TestCase, WriteFilesystemTests): """This test is constructed in a way that it builds up a directory structure, whcih is removed at the end. """ filesystem_class = OSFileSystem root = None def setUp(self): if self.root is None: self.root = tempfile.mktemp() self.filesystem = self.filesystem_class(self.root) os.mkdir(self.root) os.mkdir(joinToRoot(self.root, self.dir_name)) f = open(joinToRoot(self.root, self.file_name), 'w') f.write(self.file_contents) f.close() def tearDown(self): shutil.rmtree(self.root) def testNormalize(self): self.assertEqual(self.filesystem.normalize('/foo/bar//'), '/foo/bar') self.assertEqual(self.filesystem.normalize('/foo//bar'), '/foo/bar') self.assertEqual(self.filesystem.normalize('///foo/bar'), '/foo/bar') self.assertEqual(self.filesystem.normalize('///foo//bar////'), '/foo/bar') self.assertEqual(self.filesystem.normalize('../foo/bar'), '/') self.assertEqual(self.filesystem.normalize('..'), '/') self.assertEqual(self.filesystem.normalize('/..'), '/') self.assertEqual(self.filesystem.normalize('/foo/..'), '/') self.assertEqual(self.filesystem.normalize('/foo/../bar'), '/bar') self.assertEqual(self.filesystem.normalize('../../'), '/') self.assertEqual(self.filesystem.normalize('///../foo/bar'), '/foo/bar') self.assertEqual(self.filesystem.normalize('/foo/..///'), '/') self.assertEqual(self.filesystem.normalize('///foo/..//bar'), '/bar') self.assertEqual(self.filesystem.normalize('..///../'), '/') def testTranslate(self): self.assertEqual(self.filesystem.root, self.root) self.assertEqual(self.filesystem.translate('/foo/'), os.path.join(self.root, 'foo')) self.assertEqual(self.filesystem.translate('/foo/bar'), os.path.join(self.root, 'foo', 'bar')) self.assertEqual(self.filesystem.translate('foo/bar'), os.path.join(self.root, 'foo', 'bar')) def testStat(self): stat = os.stat(joinToRoot(self.root, self.file_name)) self.assertEqual(self.filesystem.stat(self.file_name), stat) if 0 and os.name == 'posix': from PosixFilesystemTests import PosixFilesystemTests class OSPosixFilesystemTests(OSFileSystemTests, PosixFilesystemTests): def testChown(self): # Disable this test, since it won't work unless you're root. return OSFileSystemTests = OSPosixFilesystemTests def test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(OSFileSystemTests) if __name__=='__main__': unittest.TextTestRunner().run( test_suite() ) === Added File Zope3/lib/python/Zope/Server/VFS/tests/testPublisherFilesystem.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: testPublisherFilesystem.py,v 1.1.4.1 2002/04/12 21:30:59 shane Exp $ """ import unittest from StringIO import StringIO from Zope.Server.VFS.PublisherFileSystem import PublisherFileSystem from Zope.Publisher.VFS.VFSRequest import VFSRequest from Zope.Publisher.DefaultPublication import DefaultPublication from Zope.Publisher.VFS.IVFSFilePublisher import IVFSFilePublisher from Zope.Publisher.VFS.IVFSDirectoryPublisher import IVFSDirectoryPublisher from Zope.Publisher.mapply import mapply from WriteFilesystemTests import WriteFilesystemTests class VFSPublication (DefaultPublication): # This class will not be needed if we move callObject(). def callObject(self, request, ob): method = getattr(ob, request.method) return mapply(method, request.getPositionalArguments(), request) def traverseName(self, request, ob, name): return ob.publishTraverse(request, name) class TestFile: __implements__ = IVFSFilePublisher def __init__(self, data=''): self.data = data def publishTraverse(self, request, name): """See IVFSPublisher.""" raise OSError, 'Cannot traverse TestFiles' def isdir(self): """See IVFSObjectPublisher.""" return 0 def isfile(self): """See IVFSObjectPublisher.""" return 1 def stat(self): """See IVFSObjectPublisher.""" raise NotImplementedError def read(self, mode, outstream, start=0, end=-1): """See IVFSFilePublisher.""" if end >= 0: s = self.data[start:end] else: s = self.data[start:] outstream.write(s) def write(self, mode, instream, start=0): """See IVFSFilePublisher.""" s = instream.read() if 'a' in mode: self.data = self.data + s else: self.data = self.data[:start] + s + self.data[start + len(s):] class TestDirectory: __implements__ = IVFSDirectoryPublisher def __init__(self, items={}): self.items = items.copy() def publishTraverse(self, request, name): """See IVFSPublisher.""" return self.items[name] def isdir(self): """See IVFSObjectPublisher.""" return 1 def isfile(self): """See IVFSObjectPublisher.""" return 0 def stat(self): """See IVFSObjectPublisher.""" raise NotImplementedError def exists(self, name): """See IVFSDirectoryPublisher.""" return self.items.has_key(name) def listdir(self, with_stats=0, pattern='*'): """See IVFSDirectoryPublisher.""" if with_stats or pattern != '*': raise NotImplementedError return self.items.keys() def mkdir(self, name, mode=0777): """See IVFSDirectoryPublisher.""" self.items[name] = TestDirectory() def remove(self, name): """See IVFSDirectoryPublisher.""" del self.items[name] def rmdir(self, name): """See IVFSDirectoryPublisher.""" del self.items[name] def rename(self, old, new): """See IVFSDirectoryPublisher.""" if self.items.has_key(new): raise OSError, 'Name conflict' self.items[new] = self.items[old] del self.items[old] def writefile(self, name, mode, instream, start=0): """See IVFSDirectoryPublisher.""" if not self.items.has_key(name): self.items[name] = TestFile() self.items[name].write(mode, instream, start) def check_writable(self, name): """See IVFSDirectoryPublisher.""" if not self.items.has_key(name): return 1 return self.items[name].isfile() class PublisherFileSystemTests(unittest.TestCase, WriteFilesystemTests): """This test is constructed in a way that it builds up a directory structure, whcih is removed at the end. """ filesystem_class = PublisherFileSystem # XXX for now, the publisher always eats exceptions. check_exceptions = 0 def setUp(self): app = TestDirectory() pub = VFSPublication(app) def request_factory(input_stream, output_steam, env): request = VFSRequest(input_stream, output_steam, env) request.setPublication(pub) return request self.filesystem = PublisherFileSystem(None, request_factory) self.filesystem.mkdir(self.dir_name) s = StringIO(self.file_contents) self.filesystem.writefile(self.file_name, 'w', s) def tearDown(self): pass def test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(PublisherFileSystemTests) if __name__=='__main__': unittest.TextTestRunner().run( test_suite() ) From shane@cvs.zope.org Fri Apr 12 22:31:03 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:03 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/notes - async_blurbs.txt:NONE debugging.txt:NONE threads.txt:NONE tkinter.txt:NONE Message-ID: <200204122131.g3CLV3I21264@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/notes In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/medusa/notes Removed Files: Tag: Zope-3x-branch async_blurbs.txt debugging.txt threads.txt tkinter.txt Log Message: Merged Zope3-Server-Branch. === Removed File Zope3/lib/python/Zope/Server/medusa/notes/async_blurbs.txt === === Removed File Zope3/lib/python/Zope/Server/medusa/notes/debugging.txt === === Removed File Zope3/lib/python/Zope/Server/medusa/notes/threads.txt === === Removed File Zope3/lib/python/Zope/Server/medusa/notes/tkinter.txt === From shane@cvs.zope.org Fri Apr 12 22:31:04 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:04 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/script_handler_demo - form.mpy:NONE persistent.py:NONE start_demo.py:NONE today.mpy:NONE Message-ID: <200204122131.g3CLV4v21276@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/script_handler_demo In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/medusa/script_handler_demo Removed Files: Tag: Zope-3x-branch form.mpy persistent.py start_demo.py today.mpy Log Message: Merged Zope3-Server-Branch. === Removed File Zope3/lib/python/Zope/Server/medusa/script_handler_demo/form.mpy === === Removed File Zope3/lib/python/Zope/Server/medusa/script_handler_demo/persistent.py === === Removed File Zope3/lib/python/Zope/Server/medusa/script_handler_demo/start_demo.py === === Removed File Zope3/lib/python/Zope/Server/medusa/script_handler_demo/today.mpy === From shane@cvs.zope.org Fri Apr 12 22:31:05 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:05 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa/thread - __init__.py:NONE pi_module.py:NONE select_trigger.py:NONE test_module.py:NONE thread_channel.py:NONE thread_handler.py:NONE Message-ID: <200204122131.g3CLV5s21312@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa/thread In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/medusa/thread Removed Files: Tag: Zope-3x-branch __init__.py pi_module.py select_trigger.py test_module.py thread_channel.py thread_handler.py Log Message: Merged Zope3-Server-Branch. === Removed File Zope3/lib/python/Zope/Server/medusa/thread/__init__.py === === Removed File Zope3/lib/python/Zope/Server/medusa/thread/pi_module.py === === Removed File Zope3/lib/python/Zope/Server/medusa/thread/select_trigger.py === === Removed File Zope3/lib/python/Zope/Server/medusa/thread/test_module.py === === Removed File Zope3/lib/python/Zope/Server/medusa/thread/thread_channel.py === === Removed File Zope3/lib/python/Zope/Server/medusa/thread/thread_handler.py === From shane@cvs.zope.org Fri Apr 12 22:31:06 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:06 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/StartUp/tests - testRegisterServerType.py:1.1.2.3 Message-ID: <200204122131.g3CLV6Q21341@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/StartUp/tests In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/StartUp/tests Modified Files: Tag: Zope-3x-branch testRegisterServerType.py Log Message: Merged Zope3-Server-Branch. === Zope3/lib/python/Zope/StartUp/tests/testRegisterServerType.py 1.1.2.2 => 1.1.2.3 === # ############################################################################## -""" - -$Id$ -""" - -import unittest -from Zope.StartUp.ServerTypeRegistry import getServerType - -from Zope.Configuration.xmlconfig import xmlconfig -from cStringIO import StringIO - - -template = """ - %s - """ - - -class Test( unittest.TestCase ): - - - def testRegisterServerType(self): - - xmlconfig(StringIO(template % ( - ''' - - - ''' - ))) - - from Zope.Server.PublisherServers import PublisherHTTPServer - from Zope.Server.HTTPServer import CommonHitLogger - - self.assertEqual(getServerType('Browser')._factory, - PublisherHTTPServer) - self.assertEqual(getServerType('Browser')._logFactory, CommonHitLogger) - self.assertEqual(getServerType('Browser')._requestFactory, - "BrowserRequestFactory") - self.assertEqual(getServerType('Browser')._defaultPort, 8080) - self.assertEqual(getServerType('Browser')._defaultVerbose, 1) - - - -def test_suite(): - loader = unittest.TestLoader() - return loader.loadTestsFromTestCase( Test ) - - -if __name__=='__main__': - unittest.TextTestRunner().run( test_suite() ) - +"""terServerType.py,v 1.1.2.2 2002/04/02 02:20:40 srichter Exp $ +""" + +import unittest +from Zope.StartUp.ServerTypeRegistry import getServerType + +from Zope.Configuration.xmlconfig import xmlconfig +from cStringIO import StringIO + + +template = """ + %s + """ + + +class Test( unittest.TestCase ): + + + def testRegisterServerType(self): + + xmlconfig(StringIO(template % ( + ''' + + + ''' + ))) + + from Zope.Server.HTTP.PublisherHTTPServer import PublisherHTTPServer + from Zope.Server.HTTP.CommonHitLogger import CommonHitLogger + + self.assertEqual(getServerType('Browser')._factory, + PublisherHTTPServer) + self.assertEqual(getServerType('Browser')._logFactory, CommonHitLogger) + self.assertEqual(getServerType('Browser')._requestFactory, + "BrowserRequestFactory") + self.assertEqual(getServerType('Browser')._defaultPort, 8080) + self.assertEqual(getServerType('Browser')._defaultVerbose, 1) + + + +def test_suite(): + loader = unittest.TestLoader() + return loader.loadTestsFromTestCase( Test ) + + +if __name__=='__main__': + unittest.TextTestRunner().run( test_suite() ) + From shane@cvs.zope.org Fri Apr 12 22:31:18 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:18 -0400 Subject: [Zope-Checkins] CVS: Zope3 - startup.zcml:1.1.2.4 Message-ID: <200204122131.g3CLVIY22126@cvs.baymountain.com> Update of /cvs-repository/Zope3 In directory cvs.zope.org:/tmp/cvs-serv20835 Modified Files: Tag: Zope-3x-branch startup.zcml Log Message: Merged Zope3-Server-Branch. === Zope3/startup.zcml 1.1.2.3 => 1.1.2.4 === - xmlns="http://namespaces.zope.org/zope" - xmlns:startup="http://namespaces.zope.org/startup"> - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + From shane@cvs.zope.org Fri Apr 12 22:31:19 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:19 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Container - IContainer.py:1.1.2.3 container.zcml:1.1.2.4 Message-ID: <200204122131.g3CLVJJ22131@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Container In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/App/OFS/Container Modified Files: Tag: Zope-3x-branch IContainer.py container.zcml Log Message: Merged Zope3-Server-Branch. === Zope3/lib/python/Zope/App/OFS/Container/IContainer.py 1.1.2.2 => 1.1.2.3 === class IContainer(IReadContainer, IWriteContainer): """The interface for working with a readable and writable container.""" - - - - - === Zope3/lib/python/Zope/App/OFS/Container/container.zcml 1.1.2.3 => 1.1.2.4 === xmlns:browser='http://namespaces.zope.org/browser' xmlns:xmlrpc='http://namespaces.zope.org/xmlrpc' + xmlns:vfs='http://namespaces.zope.org/vfs' > + + + + + + + + + + From shane@cvs.zope.org Fri Apr 12 22:31:20 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:20 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/File - File.py:1.1.2.6 NaiveFile.py:1.1.2.4 Message-ID: <200204122131.g3CLVKf22135@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/App/OFS/Content/File Modified Files: Tag: Zope-3x-branch File.py NaiveFile.py Log Message: Merged Zope3-Server-Branch. === Zope3/lib/python/Zope/App/OFS/Content/File/File.py 1.1.2.5 => 1.1.2.6 === - def __init__(self, data=None, contentType=None): + def __init__(self, data='', contentType=None): """ """ self.setData(data) === Zope3/lib/python/Zope/App/OFS/Content/File/NaiveFile.py 1.1.2.3 => 1.1.2.4 === - def __init__(self, data=None, contentType=None): + def __init__(self, data='', contentType=None): """ """ self.setData(data) From shane@cvs.zope.org Fri Apr 12 22:31:20 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:20 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/File/Views - views.zcml:1.1.2.2 Message-ID: <200204122131.g3CLVKf22138@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File/Views In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/App/OFS/Content/File/Views Modified Files: Tag: Zope-3x-branch views.zcml Log Message: Merged Zope3-Server-Branch. === Zope3/lib/python/Zope/App/OFS/Content/File/Views/views.zcml 1.1.2.1 => 1.1.2.2 === - xmlns='http://namespaces.zope.org/zope' -> - - - - - \ No newline at end of file + + + + + + + From shane@cvs.zope.org Fri Apr 12 22:31:20 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:20 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Content/File/tests - testFile.py:1.1.2.3 testNaiveFile.py:1.1.2.3 Message-ID: <200204122131.g3CLVKM22142@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Content/File/tests In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/App/OFS/Content/File/tests Modified Files: Tag: Zope-3x-branch testFile.py testNaiveFile.py Log Message: Merged Zope3-Server-Branch. === Zope3/lib/python/Zope/App/OFS/Content/File/tests/testFile.py 1.1.2.2 => 1.1.2.3 === self.assertEqual(file.getContentType(), '') - self.assertEqual(file.getData(), None) + self.assertEqual(file.getData(), '') def testConstructor(self): === Zope3/lib/python/Zope/App/OFS/Content/File/tests/testNaiveFile.py 1.1.2.2 => 1.1.2.3 === self.assertEqual(file.getContentType(), '') - self.assertEqual(file.getData(), None) + self.assertEqual(file.getData(), '') def testConstructor(self): From shane@cvs.zope.org Fri Apr 12 22:31:21 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:21 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/Folder/Views - views.zcml:1.1.4.2 Message-ID: <200204122131.g3CLVLD22145@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Folder/Views In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/App/OFS/Folder/Views Modified Files: Tag: Zope-3x-branch views.zcml Log Message: Merged Zope3-Server-Branch. === Zope3/lib/python/Zope/App/OFS/Folder/Views/views.zcml 1.1.4.1 => 1.1.4.2 === + From shane@cvs.zope.org Fri Apr 12 22:31:22 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:22 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security - BasicVFSAuthAdapter.py:1.1.4.1 security.zcml:1.1.2.4 Message-ID: <200204122131.g3CLVMA22148@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/Security In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/App/Security Modified Files: Tag: Zope-3x-branch security.zcml Added Files: Tag: Zope-3x-branch BasicVFSAuthAdapter.py Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/App/Security/BasicVFSAuthAdapter.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## # HTTP Basic Authentication adapter from Zope.Publisher.VFS.IVFSCredentials import IVFSCredentials from LoginPassword import LoginPassword class BasicVFSAuthAdapter(LoginPassword): __used_for__ = IVFSCredentials __request = None def __init__(self, request): self.__request = request # XXX base64 decoding should be done here, not in request lpw = request._authUserPW() if lpw is None: login, password = None, None else: login, password = lpw LoginPassword.__init__(self, login, password) def needLogin(self, realm): self.__request.unauthorized("Did not work") === Zope3/lib/python/Zope/App/Security/security.zcml 1.1.2.3 => 1.1.2.4 === for="Zope.Publisher.HTTP.IHTTPCredentials." /> + From shane@cvs.zope.org Fri Apr 12 22:31:01 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:01 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/medusa - .testinfo:NONE ANNOUNCE.txt:NONE ANNOUNCE_970922.txt:NONE INSTALL.txt:NONE Makefile:NONE __init__.py:NONE asynchat.py:NONE auth_handler.py:NONE chat_server.py:NONE continuation.py:NONE counter.py:NONE default_handler.py:NONE event_loop.py:NONE fifo.py:NONE filesys.py:NONE ftp_server.py:NONE http_bobo.py:NONE http_date.py:NONE http_server.py:NONE logger.py:NONE m_syslog.py:NONE medusa.html:NONE medusa_gif.py:NONE mime_type_table.py:NONE monitor.py:NONE monitor_client.py:NONE monitor_client_win32.py:NONE out:NONE producers.py:NONE put_handler.py:NONE redirecting_handler.py:NONE resolver.py:NONE rpc_client.py:NONE rpc_server.py:NONE script_handler.py:NONE start_medusa.py:NONE status_handler.py:NONE unix_user_handler.py:NONE virtual_handler.py:NONE xmlrpc_handler.py:NONE Message-ID: <200204122131.g3CLV1L21188@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server/medusa In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/medusa Removed Files: Tag: Zope-3x-branch .testinfo ANNOUNCE.txt ANNOUNCE_970922.txt INSTALL.txt Makefile __init__.py asynchat.py auth_handler.py chat_server.py continuation.py counter.py default_handler.py event_loop.py fifo.py filesys.py ftp_server.py http_bobo.py http_date.py http_server.py logger.py m_syslog.py medusa.html medusa_gif.py mime_type_table.py monitor.py monitor_client.py monitor_client_win32.py out producers.py put_handler.py redirecting_handler.py resolver.py rpc_client.py rpc_server.py script_handler.py start_medusa.py status_handler.py unix_user_handler.py virtual_handler.py xmlrpc_handler.py Log Message: Merged Zope3-Server-Branch. === Removed File Zope3/lib/python/Zope/Server/medusa/.testinfo === === Removed File Zope3/lib/python/Zope/Server/medusa/ANNOUNCE.txt === === Removed File Zope3/lib/python/Zope/Server/medusa/ANNOUNCE_970922.txt === === Removed File Zope3/lib/python/Zope/Server/medusa/INSTALL.txt === === Removed File Zope3/lib/python/Zope/Server/medusa/Makefile === === Removed File Zope3/lib/python/Zope/Server/medusa/__init__.py === === Removed File Zope3/lib/python/Zope/Server/medusa/asynchat.py === === Removed File Zope3/lib/python/Zope/Server/medusa/auth_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/chat_server.py === === Removed File Zope3/lib/python/Zope/Server/medusa/continuation.py === === Removed File Zope3/lib/python/Zope/Server/medusa/counter.py === === Removed File Zope3/lib/python/Zope/Server/medusa/default_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/event_loop.py === === Removed File Zope3/lib/python/Zope/Server/medusa/fifo.py === === Removed File Zope3/lib/python/Zope/Server/medusa/filesys.py === === Removed File Zope3/lib/python/Zope/Server/medusa/ftp_server.py === === Removed File Zope3/lib/python/Zope/Server/medusa/http_bobo.py === === Removed File Zope3/lib/python/Zope/Server/medusa/http_date.py === === Removed File Zope3/lib/python/Zope/Server/medusa/http_server.py === === Removed File Zope3/lib/python/Zope/Server/medusa/logger.py === === Removed File Zope3/lib/python/Zope/Server/medusa/m_syslog.py === === Removed File Zope3/lib/python/Zope/Server/medusa/medusa.html === === Removed File Zope3/lib/python/Zope/Server/medusa/medusa_gif.py === === Removed File Zope3/lib/python/Zope/Server/medusa/mime_type_table.py === === Removed File Zope3/lib/python/Zope/Server/medusa/monitor.py === === Removed File Zope3/lib/python/Zope/Server/medusa/monitor_client.py === === Removed File Zope3/lib/python/Zope/Server/medusa/monitor_client_win32.py === === Removed File Zope3/lib/python/Zope/Server/medusa/out === === Removed File Zope3/lib/python/Zope/Server/medusa/producers.py === === Removed File Zope3/lib/python/Zope/Server/medusa/put_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/redirecting_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/resolver.py === === Removed File Zope3/lib/python/Zope/Server/medusa/rpc_client.py === === Removed File Zope3/lib/python/Zope/Server/medusa/rpc_server.py === === Removed File Zope3/lib/python/Zope/Server/medusa/script_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/start_medusa.py === === Removed File Zope3/lib/python/Zope/Server/medusa/status_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/unix_user_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/virtual_handler.py === === Removed File Zope3/lib/python/Zope/Server/medusa/xmlrpc_handler.py === From shane@cvs.zope.org Fri Apr 12 22:31:23 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:23 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication/XMLRPC - Publication.py:1.1.2.4 Message-ID: <200204122131.g3CLVN222154@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication/XMLRPC In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/App/ZopePublication/XMLRPC Modified Files: Tag: Zope-3x-branch Publication.py Log Message: Merged Zope3-Server-Branch. === Zope3/lib/python/Zope/App/ZopePublication/XMLRPC/Publication.py 1.1.2.3 => 1.1.2.4 === # ############################################################################## -""" - +""" + $Id$ -""" +""" + +from Zope.App.ZopePublication.HTTP.Publication import ZopeHTTPPublication +from Zope.ComponentArchitecture import getRequestView +from Zope.ContextWrapper import Wrapper +from Zope.App.Security.SecurityManagement import getSecurityManager + + +class XMLRPCPublication(ZopeHTTPPublication): + """XML-RPC publication handling. + + There is nothing special here right now. + """ + + +# For now, have a factory that returns a singleton +class XMLRPCPublicationFactory: + + def __init__(self, db): + self.__pub = XMLRPCPublication(db) -from Zope.App.ZopePublication.HTTP.Publication import ZopeHTTPPublication -from Zope.ComponentArchitecture import getRequestView -from Zope.ContextWrapper import Wrapper -from Zope.App.Security.SecurityManagement import getSecurityManager - - -class XMLRPCPublication(ZopeHTTPPublication): - """XML-RPC publication handling. - - There is nothing special here right now. - """ - - -# For now, have a factory that returns a singleton -class XMLRPCPublicationFactory: - - def __init__(self, db): - self.__pub = XMLRPCPublication(db) - - def __call__(self): - return self.__pub + def __call__(self): + return self.__pub From shane@cvs.zope.org Fri Apr 12 22:31:23 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:23 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher - BaseRequest.py:1.1.2.28 BaseResponse.py:1.1.2.12 IPublisherResponse.py:1.1.2.6 Publish.py:1.1.2.17 publisher-meta.zcml:1.1.4.2 Message-ID: <200204122131.g3CLVNh22163@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Publisher Modified Files: Tag: Zope-3x-branch BaseRequest.py BaseResponse.py IPublisherResponse.py Publish.py publisher-meta.zcml Log Message: Merged Zope3-Server-Branch. === Zope3/lib/python/Zope/Publisher/BaseRequest.py 1.1.2.27 => 1.1.2.28 === environment = RequestDataProperty(RequestEnvironment) - def __init__(self, body_instream, outstream, environ, positional=()): + def __init__(self, body_instream, outstream, environ, response=None, + positional=()): self._traversal_stack = [] self._traversed_names = [] self._environ = environ self._args = positional - self._response = self._createResponse(outstream) + if response is None: + self._response = self._createResponse(outstream) + else: + self._response = response self._body_instream = body_instream self._held = () === Zope3/lib/python/Zope/Publisher/BaseResponse.py 1.1.2.11 => 1.1.2.12 === exc_info[0], exc_info[1], exc_info[2], 100, self) + def internalError(self): + 'See Zope.Publisher.IPublisherResponse.IPublisherResponse' + pass + def retry(self): 'See Zope.Publisher.IPublisherResponse.IPublisherResponse' return self.__class__(self.outstream) === Zope3/lib/python/Zope/Publisher/IPublisherResponse.py 1.1.2.5 => 1.1.2.6 === def setBody(result): - """Set's the response result value. + """Sets the response result value. """ def handleException(exc_info): - """Handle an otherwise unhandled exception. + """Handles an otherwise unhandled exception. - The handling of the exception is expected to effect the reponse body. + The publication object gets the first chance to handle an exception, + and if it doesn't have a good way to do it, it defers to the + response. Implementations should set the reponse body. + """ + + def internalError(): + """Called when the exception handler bombs. + + Should report back to the client that an internal error occurred. """ - # XXX ZopePublication seems to call this, so maybe this should be - # in an IPublicationResponse interface, but maybe this will change, - # so we'll apply YAGNI for now. def outputBody(): - """Output the response to the client + """Outputs the response to the client """ def retry(): - """Return a retry response + """Returns a retry response - Return a response suitable for repeating the publication attempt. + Returns a response suitable for repeating the publication attempt. """ === Zope3/lib/python/Zope/Publisher/Publish.py 1.1.2.16 => 1.1.2.17 === # ############################################################################## -__doc__="""Python Object Publisher -- Publish Python objects on web servers +""" +Python Object Publisher -- Publish Python objects on web servers + +$Id$ +""" -$Id$""" -__version__='$Revision$'[11:-2] import sys, os from Exceptions import Retry @@ -71,6 +73,7 @@ except: # Bad exception handler or retry method. # Re-raise after outputting the response. + request.getResponse().internalError() to_raise = sys.exc_info() break === Zope3/lib/python/Zope/Publisher/publisher-meta.zcml 1.1.4.1 => 1.1.4.2 === > - - - + + + + From shane@cvs.zope.org Fri Apr 12 22:31:25 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:25 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/XMLRPC - XMLRPCRequest.py:1.1.2.3 Message-ID: <200204122131.g3CLVPg22176@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/XMLRPC In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Publisher/XMLRPC Modified Files: Tag: Zope-3x-branch XMLRPCRequest.py Log Message: Merged Zope3-Server-Branch. === Zope3/lib/python/Zope/Publisher/XMLRPC/XMLRPCRequest.py 1.1.2.2 => 1.1.2.3 === class TestRequest(XMLRPCRequest): - def __init__(self, body_instream=None, outstream=None, environ=None, **kw): + def __init__(self, body_instream=None, outstream=None, environ=None, + response=None, **kw): _testEnv = { 'SERVER_URL': 'http://127.0.0.1', @@ -78,5 +79,6 @@ if outstream is None: outstream = StringIO() - super(TestRequest, self).__init__(body_instream, outstream, _testEnv) - + super(TestRequest, self).__init__( + body_instream, outstream, _testEnv, response) + From shane@cvs.zope.org Fri Apr 12 22:31:23 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:23 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Publisher/Browser - AttributePublisher.py:1.1.2.15 BrowserRequest.py:1.1.4.10 BrowserResponse.py:1.1.4.6 Message-ID: <200204122131.g3CLVNA22166@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Publisher/Browser In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Publisher/Browser Modified Files: Tag: Zope-3x-branch AttributePublisher.py BrowserRequest.py BrowserResponse.py Log Message: Merged Zope3-Server-Branch. === Zope3/lib/python/Zope/Publisher/Browser/AttributePublisher.py 1.1.2.14 => 1.1.2.15 === # ############################################################################## +""" + +$Id$ +""" from IBrowserPublisher import IBrowserPublisher class AttributePublisher(object): === Zope3/lib/python/Zope/Publisher/Browser/BrowserRequest.py 1.1.4.9 => 1.1.4.10 === - def __init__(self, body_instream, outstream, environ): + def __init__(self, body_instream, outstream, environ, response=None): self._form = {} - super(BrowserRequest, self).__init__(body_instream, outstream, environ) + super(BrowserRequest, self).__init__( + body_instream, outstream, environ, response) def _createResponse(self, outstream): === Zope3/lib/python/Zope/Publisher/Browser/BrowserResponse.py 1.1.4.5 => 1.1.4.6 === Sets the return body equal to the (string) argument "body". Also - updates the "content-length" return header. - - If the body is a 2-element tuple, then it will be treated - as (title,body) - - If is_error is true then the HTML will be formatted as a Zope error - message instead of a generic HTML page. + updates the "content-length" return header and sets the status to + 200 if it has not already been set. """ body = str(body) @@ -65,6 +60,8 @@ body = self.__insertBase(body) self._body = body self._updateContentLength() + if not self._status_set: + self.setStatus(200) def __isHTML(self, str): s = str.strip().lower() @@ -85,7 +82,7 @@ def __insertBase(self, body): # Only insert a base tag if content appears to be html. content_type = self.getHeader('content-type', '') - if content_type and content_type != 'text/html': + if content_type and not is_text_html(content_type): return body if getattr(self, '_base', ''): From shane@cvs.zope.org Fri Apr 12 22:31:26 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:26 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Server - FixedStreamReceiver.py:1.1.4.1 IDispatcher.py:1.1.4.1 IDispatcherEventHandler.py:1.1.4.1 IDispatcherLogging.py:1.1.4.1 IServer.py:1.1.4.1 IServerChannel.py:1.1.4.1 ISocket.py:1.1.4.1 MaxSockets.py:1.1.4.1 ServerChannelBase.py:1.1.4.1 Adjustments.py:1.1.2.5 Buffers.py:1.1.2.4 DualModeChannel.py:1.1.2.5 IHeaderOutput.py:1.1.2.4 IRequestFactory.py:1.1.4.3 IStreamConsumer.py:1.1.2.4 ITask.py:1.1.2.4 ITaskDispatcher.py:1.1.2.3 ServerBase.py:1.1.2.5 TaskThreads.py:1.1.2.9 Utilities.py:1.1.2.4 ZLogIntegration.py:1.1.2.4 __init__.py:1.1.2.6 Chunking.py:NONE HTTPServer.py:NONE PublisherServers.py:NONE Message-ID: <200204122131.g3CLVQK22191@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Server In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server Modified Files: Tag: Zope-3x-branch Adjustments.py Buffers.py DualModeChannel.py IHeaderOutput.py IRequestFactory.py IStreamConsumer.py ITask.py ITaskDispatcher.py ServerBase.py TaskThreads.py Utilities.py ZLogIntegration.py __init__.py Added Files: Tag: Zope-3x-branch FixedStreamReceiver.py IDispatcher.py IDispatcherEventHandler.py IDispatcherLogging.py IServer.py IServerChannel.py ISocket.py MaxSockets.py ServerChannelBase.py Removed Files: Tag: Zope-3x-branch Chunking.py HTTPServer.py PublisherServers.py Log Message: Merged Zope3-Server-Branch. === Added File Zope3/lib/python/Zope/Server/FixedStreamReceiver.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: FixedStreamReceiver.py,v 1.1.4.1 2002/04/12 21:30:54 shane Exp $ """ from IStreamConsumer import IStreamConsumer class FixedStreamReceiver: __implements__ = IStreamConsumer # See Zope.Server.IStreamConsumer.IStreamConsumer completed = 0 def __init__(self, cl, buf): self.remain = cl self.buf = buf ############################################################ # Implementation methods for interface # Zope.Server.IStreamConsumer def received(self, data): 'See Zope.Server.IStreamConsumer.IStreamConsumer' rm = self.remain if rm < 1: self.completed = 1 # Avoid any chance of spinning return 0 datalen = len(data) if rm <= datalen: self.buf.append(data[:rm]) self.remain = 0 self.completed = 1 return rm else: self.buf.append(data) self.remain -= datalen return datalen # ############################################################ def getfile(self): return self.buf.getfile() === Added File Zope3/lib/python/Zope/Server/IDispatcher.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IDispatcher.py,v 1.1.4.1 2002/04/12 21:30:54 shane Exp $ """ from ISocket import ISocket from IDispatcherEventHandler import IDispatcherEventHandler from IDispatcherLogging import IDispatcherLogging class IDispatcher(ISocket, IDispatcherEventHandler, IDispatcherLogging): """The dispatcher is the most low-level component of a server. 1. It manages the socket connections and distributes the request to the appropriate channel. 2. It handles the events passed to it, such as reading input, writing output and handling errors. More about this functionality can be found in IDispatcherEventHandler. 3. It handles logging of the requests passed to the server as well as other informational messages and erros. Please see IDispatcherLogging for more details. Note: Most of this documentation is taken from the Python Library Reference. """ def add_channel(map=None): """After the low-level socket connection negotiation is completed, a channel is created that handles all requests and responses until the end of the connection. """ def del_channel(map=None): """Delete a channel. This should include also closing the socket to the client. """ def create_socket(family, type): """This is identical to the creation of a normal socket, and will use the same options for creation. Refer to the socket documentation for information on creating sockets. """ def readable(): """Each time through the select() loop, the set of sockets is scanned, and this method is called to see if there is any interest in reading. The default method simply returns 1, indicating that by default, all channels will be interested. """ def writable(): """Each time through the select() loop, the set of sockets is scanned, and this method is called to see if there is any interest in writing. The default method simply returns 1, indicating that by default, all channels will be interested. """ === Added File Zope3/lib/python/Zope/Server/IDispatcherEventHandler.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IDispatcherEventHandler.py,v 1.1.4.1 2002/04/12 21:30:54 shane Exp $ """ from Interface import Interface class IDispatcherEventHandler(Interface): """The Dispatcher can receive several different types of events. This interface describes the necessary methods that handle these common event types. """ def handle_read_event(): """Given a read event, a server has to handle the event and read the input from the client. """ def handle_write_event(): """Given a write event, a server has to handle the event and write the output to the client. """ def handle_expt_event(): """An exception event was handed to the server. """ def handle_error(): """An error occured, but we are still trying to fix it. """ def handle_expt(): """Handle unhandled exceptions. This is usually a time to log. """ def handle_read(): """Read output from client. """ def handle_write(): """Write output via the socket to the client. """ def handle_connect(): """A client requests a connection, now we need to do soemthing. """ def handle_accept(): """A connection is accepted. """ def handle_close(): """A connection is being closed. """ === Added File Zope3/lib/python/Zope/Server/IDispatcherLogging.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IDispatcherLogging.py,v 1.1.4.1 2002/04/12 21:30:54 shane Exp $ """ from Interface import Interface class IDispatcherLogging(Interface): """This interface provides methods through which the Dispatcher will write its logs. A distinction is made between hit and message logging, since they often go to different output types and can have very different structure. """ def log (message): """Logs general requests made to the server. """ def log_info(message, type='info'): """Logs informational messages, warnings and errors. """ === Added File Zope3/lib/python/Zope/Server/IServer.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IServer.py,v 1.1.4.1 2002/04/12 21:30:54 shane Exp $ """ from Interface import Interface from Interface.Attribute import Attribute class IServer(Interface): """This interface describes the basic base server. The most unusual part about the Zope servers (since they all implement this interface or inherit its base class) is that it uses a mix of asynchronous and thread-based mechanism to serve. While the low-level socket listener uses async, the actual request is executed in a thread. This has the huge advantage that if a request takes really long to process, the server does not hang at that point to wait for the request to finish. """ channel_class = Attribute(""" The channel class defines the type of channel to be used by the server. See IServerChannel for more information. """) SERVER_IDENT = Attribute(""" This string identifies the server. By default this is 'Zope.Server.' and should be overridden. """) === Added File Zope3/lib/python/Zope/Server/IServerChannel.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: IServerChannel.py,v 1.1.4.1 2002/04/12 21:30:54 shane Exp $ """ from Interface import Interface from Interface.Attribute import Attribute class IServerChannel(Interface): """ """ parser_class = Attribute("Subclasses must provide a parser class") task_class = Attribute("Subclasses must provide a task class.") active_channels = Attribute("Class-specific channel tracker") next_channel_cleanup = Attribute("Class-specific cleanup time") proto_request = Attribute("A request parser instance") ready_requests = Attribute("A list of requests to be processed.") last_activity = Attribute("Time of last activity") running_tasks = Attribute("boolean") def queue_request(self, req): """Queues a request to be processed in sequence by a task. """ def end_task(self, close): """Called at the end of a task, may launch another task. """ def create_task(self, req): """Creates a new task and queues it for execution. The task may get executed in another thread. """ === Added File Zope3/lib/python/Zope/Server/ISocket.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: ISocket.py,v 1.1.4.1 2002/04/12 21:30:54 shane Exp $ """ from Interface import Interface class ISocket(Interface): """Represents a socket. Note: Most of this documentation is taken from the Python Library Reference. """ def listen(num): """Listen for connections made to the socket. The backlog argument specifies the maximum number of queued connections and should be at least 1; the maximum value is system-dependent (usually 5). """ def bind(addr): """Bind the socket to address. The socket must not already be bound. """ def connect(address): """Connect to a remote socket at address. """ def accept(): """Accept a connection. The socket must be bound to an address and listening for connections. The return value is a pair (conn, address) where conn is a new socket object usable to send and receive data on the connection, and address is the address bound to the socket on the other end of the connection. """ def recv(buffer_size): """Receive data from the socket. The return value is a string representing the data received. The maximum amount of data to be received at once is specified by bufsize. See the Unix manual page recv(2) for the meaning of the optional argument flags; it defaults to zero. """ def send(data): """Send data to the socket. The socket must be connected to a remote socket. The optional flags argument has the same meaning as for recv() above. Returns the number of bytes sent. Applications are responsible for checking that all data has been sent; if only some of the data was transmitted, the application needs to attempt delivery of the remaining data. """ def close(): """Close the socket. All future operations on the socket object will fail. The remote end will receive no more data (after queued data is flushed). Sockets are automatically closed when they are garbage-collected. """ === Added File Zope3/lib/python/Zope/Server/MaxSockets.py === # Medusa max_sockets module. import socket import select # several factors here we might want to test: # 1) max we can create # 2) max we can bind # 3) max we can listen on # 4) max we can connect def max_server_sockets(): sl = [] while 1: try: s = socket.socket (socket.AF_INET, socket.SOCK_STREAM) s.bind (('',0)) s.listen(5) sl.append (s) except: break num = len(sl) for s in sl: s.close() del sl return num def max_client_sockets(): # make a server socket server = socket.socket (socket.AF_INET, socket.SOCK_STREAM) server.bind (('', 9999)) server.listen (5) sl = [] while 1: try: s = socket.socket (socket.AF_INET, socket.SOCK_STREAM) s.connect (('', 9999)) conn, addr = server.accept() sl.append ((s,conn)) except: break num = len(sl) for s,c in sl: s.close() c.close() del sl return num def max_select_sockets(): sl = [] while 1: try: num = len(sl) for i in range(1 + len(sl) * 0.05): # Increase exponentially. s = socket.socket (socket.AF_INET, socket.SOCK_STREAM) s.bind (('',0)) s.listen(5) sl.append (s) select.select(sl,[],[],0) except: break for s in sl: s.close() del sl return num === Added File Zope3/lib/python/Zope/Server/ServerChannelBase.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: ServerChannelBase.py,v 1.1.4.1 2002/04/12 21:30:54 shane Exp $ """ import os import time import sys import asyncore from thread import allocate_lock # Enable ZOPE_SERVER_SIMULT_MODE to enable experimental # simultaneous channel mode, which may improve or degrade # throughput depending on load characteristics. if os.environ.get('ZOPE_SERVER_SIMULT_MODE'): from DualModeChannel import SimultaneousModeChannel as \ ChannelBaseClass else: from DualModeChannel import DualModeChannel as ChannelBaseClass from IServerChannel import IServerChannel # Synchronize access to the "running_tasks" attributes. running_lock = allocate_lock() class ServerChannelBase(ChannelBaseClass, object): """Base class for a high-performance, mixed-mode server-side channel. """ __implements__ = ChannelBaseClass.__implements__, IServerChannel parser_class = None # Subclasses must provide a parser class task_class = None # ... and a task class. active_channels = {} # Class-specific channel tracker next_channel_cleanup = [0] # Class-specific cleanup time proto_request = None # A request parser instance ready_requests = None # A list # ready_requests must always be empty when not running tasks. last_activity = 0 # Time of last activity running_tasks = 0 # boolean: true when any task is being executed # # ASYNCHRONOUS METHODS (incl. __init__) # def __init__(self, server, conn, addr, adj=None): ChannelBaseClass.__init__(self, conn, addr, adj) self.server = server self.last_activity = t = self.creation_time self.check_maintenance(t) def add_channel(self, map=None): """This hook keeps track of opened HTTP channels. """ ChannelBaseClass.add_channel(self, map) self.__class__.active_channels[self._fileno] = self def del_channel(self, map=None): """This hook keeps track of closed HTTP channels. """ ChannelBaseClass.del_channel(self, map) ac = self.__class__.active_channels fd = self._fileno if ac.has_key(fd): del ac[fd] def check_maintenance(self, now): """Performs maintenance if necessary. """ ncc = self.__class__.next_channel_cleanup if now < ncc[0]: return ncc[0] = now + self.adj.cleanup_interval self.maintenance() def maintenance(self): """Kills off dead connections. """ self.kill_zombies() def kill_zombies(self): """Closes connections that have not had any activity in a while. The timeout is configured through adj.channel_timeout (seconds). """ now = time.time() cutoff = now - self.adj.channel_timeout for channel in self.active_channels.values(): if (channel is not self and not channel.running_tasks and channel.last_activity < cutoff): channel.close() def received(self, data): """Receive input asynchronously and send requests to receivedCompleteRequest(). """ preq = self.proto_request while data: if preq is None: preq = self.parser_class(self.adj) n = preq.received(data) if preq.completed: # The request is ready to use. if not preq.empty: self.receivedCompleteRequest(preq) preq = None self.proto_request = None else: self.proto_request = preq if n >= len(data): break data = data[n:] def receivedCompleteRequest(self, req): """If there are tasks running or requests on hold, queue the request, otherwise execute it. """ do_now = 0 running_lock.acquire() try: if self.running_tasks: # A task thread is working. It will read from the queue # when it is finished. rr = self.ready_requests if rr is None: rr = [] self.ready_requests = rr rr.append(req) else: # Do it now. do_now = 1 finally: running_lock.release() if do_now: task = self.process_request(req) if task is not None: self.start_task(task) def start_task(self, task): """Starts the given task. *** For thread safety, this should only be called from the main (async) thread. ***""" if self.running_tasks: # Can't start while another task is running! # Otherwise two threads would work on the queue at the same time. raise RuntimeError, 'Already executing tasks' self.running_tasks = 1 self.set_sync() self.server.addTask(task) def handle_error(self): """Handles program errors (not communication errors) """ t, v = sys.exc_info()[:2] if t is SystemExit or t is KeyboardInterrupt: raise t, v asyncore.dispatcher.handle_error(self) def handle_comm_error(self): """Handles communication errors (not program errors) """ if self.adj.log_socket_errors: self.handle_error() else: # Ignore socket errors. self.close() # # SYNCHRONOUS METHODS # def end_task(self, close): """Called at the end of a task and may launch another task. """ if close: # Note that self.running_tasks is left on, which has the # side effect of preventing further requests from being # serviced even if more appear. A good thing. self.close_when_done() return # Process requests held in the queue, if any. while 1: req = None running_lock.acquire() try: rr = self.ready_requests if rr: req = rr.pop(0) else: # No requests to process. self.running_tasks = 0 finally: running_lock.release() if req is not None: task = self.process_request(req) if task is not None: # Add the new task. It will service the queue. self.server.addTask(task) break # else check the queue again. else: # Idle -- Wait for another request on this connection. self.set_async() break # # BOTH MODES # def process_request(self, req): """Returns a task to execute or None if the request is quick and can be processed in the main thread. Override to handle some requests in the main thread. """ return self.task_class(self, req) === Zope3/lib/python/Zope/Server/Adjustments.py 1.1.2.4 => 1.1.2.5 === +# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved. # -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# -############################################################################## -from medusa.test import max_sockets + +import MaxSockets class Adjustments: + """This class contains tunable communication parameters. + + You can either change default_adj to adjust parameters for + all sockets, or you can create a new instance of this class, + change its attributes, and pass it to the channel constructors. + """ # backlog is the argument to pass to socket.listen(). backlog = 1024 @@ -25,6 +27,9 @@ # send_bytes is the number of bytes to send to socket.send(). send_bytes = 8192 + # copy_bytes is the number of bytes to copy from one file to another. + copy_bytes = 65536 + # Create a tempfile if the pending output data gets larger # than outbuf_overflow. With RAM so cheap, this probably # ought to be set to the 16-32 MB range (circa 2001) for @@ -37,7 +42,7 @@ inbuf_overflow = 525000 # Stop accepting new connections if too many are already active. - connection_limit = max_sockets.max_select_sockets() - 3 # Safe + connection_limit = MaxSockets.max_select_sockets() - 3 # Safe # Minimum seconds between cleaning up inactive channels. cleanup_interval = 300 @@ -45,7 +50,7 @@ # Maximum seconds to leave an inactive connection open. channel_timeout = 900 - # Boolean: turn off to ignore premature client disconnects. + # Boolean: turn off to not log premature client disconnects. log_socket_errors = 1 === Zope3/lib/python/Zope/Server/Buffers.py 1.1.2.3 => 1.1.2.4 === +# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved. # -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# -############################################################################## + + try: from cStringIO import StringIO except ImportError: === Zope3/lib/python/Zope/Server/DualModeChannel.py 1.1.2.4 => 1.1.2.5 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## +""" + +$Id$ +""" + import asyncore import socket from time import time from UserDict import UserDict -from medusa.thread import select_trigger +from Thread import SelectTrigger from Adjustments import default_adj from Buffers import OverflowableBuffer # Create the main trigger if it doesn't exist yet. -if select_trigger.the_trigger is None: - select_trigger.the_trigger = select_trigger.trigger() - - -class AlternateSocketMapMixin: - """Mixin for asyncore.dispatcher to more easily support - alternate socket maps""" - - socket_map = None +if SelectTrigger.the_trigger is None: + SelectTrigger.the_trigger = SelectTrigger.Trigger() - def add_channel(self, map=None): - if map is None: - map = self.socket_map - asyncore.dispatcher.add_channel(self, map) - - def del_channel(self, map=None): - if map is None: - map = self.socket_map - asyncore.dispatcher.del_channel(self, map) - - def pull_trigger(self): - pull_trigger = getattr(self.socket_map, 'pull_trigger', None) - if pull_trigger is not None: - # Use the trigger from the socket map. - pull_trigger() - else: - select_trigger.the_trigger.pull_trigger() -class ASMTrigger (AlternateSocketMapMixin, select_trigger.trigger): - """Trigger for an alternate socket map""" - - def __init__(self, socket_map): - self.socket_map = socket_map - select_trigger.trigger.__init__(self) - - pull_trigger = select_trigger.trigger.pull_trigger - - -class SocketMapWithTrigger (UserDict): - - def __init__(self): - UserDict.__init__(self) - self.pull_trigger = ASMTrigger(self).pull_trigger +class DualModeChannel(asyncore.dispatcher): + """Channel that switches between asynchronous and synchronous mode. + Call set_sync() before using a channel in a thread other than + the thread handling the main loop. -class DualModeChannel (AlternateSocketMapMixin, asyncore.dispatcher): - """Channel that switches between asynchronous and synchronous mode. + Call set_async() to give the channel back to the thread handling + the main loop. """ + __implements__ = asyncore.dispatcher.__implements__ + # will_close is set to 1 to close the socket. will_close = 0 # boolean: async or sync mode async_mode = 1 - def __init__(self, server, conn, addr, adj=None, socket_map=None): - self.server = server + def __init__(self, conn, addr, adj=None): self.addr = addr if adj is None: adj = default_adj self.adj = adj - self.socket_map = socket_map self.outbuf = OverflowableBuffer(adj.outbuf_overflow) self.creation_time = time() asyncore.dispatcher.__init__(self, conn) @@ -163,20 +133,26 @@ self.outbuf.append(data) while len(self.outbuf) >= self.adj.send_bytes: # Send what we can without blocking. - # We propogate errors to the application on purpose - # (to prevent unnecessary work). + # We propagate errors to the application on purpose + # (to stop the application if the connection closes). if not self._flush_some(): break - def flush(self): - """ - Pauses the application while outbuf is flushed. - Normally not a good thing to do. + def flush(self, block=1): + """Sends pending data. + + If block is set, this pauses the application. If it is turned + off, only the amount of data that can be sent without blocking + is sent. """ + if not block: + while self._flush_some(): + pass + return blocked = 0 try: while self.outbuf: - # We propogate errors to the application on purpose. + # We propagate errors to the application on purpose. if not blocked: self.socket.setblocking(1) blocked = 1 @@ -197,9 +173,17 @@ # METHODS USED IN BOTH MODES # + def pull_trigger(self): + """Wakes up the main loop. + """ + SelectTrigger.the_trigger.pull_trigger() + def _flush_some(self): + """Flushes data. + + Returns 1 if some data was sent.""" outbuf = self.outbuf - if outbuf: + if outbuf and self.connected: chunk = outbuf.get(self.adj.send_bytes) num_sent = self.send(chunk) if num_sent: @@ -208,19 +192,16 @@ return 0 def close_when_done(self): - if self.async_mode: - self.will_close = 1 - self.pull_trigger() + # We might be able close immediately. + while self._flush_some(): + pass + if not self.outbuf: + # Quick exit. + self.close() else: - # We might be able close immediately. - while self._flush_some(): - pass - if not self.outbuf: - # Quick exit. - self.close() - else: - # Wait until outbuf is flushed. - self.will_close = 1 + # Wait until outbuf is flushed. + self.will_close = 1 + if not self.async_mode: self.async_mode = 1 self.pull_trigger() @@ -237,16 +218,21 @@ and fill the input buffer. """ - def __init__(self, server, conn, addr, adj=None, socket_map=None): + __implements__ = asyncore.dispatcher.__implements__ + + + def __init__(self, conn, addr, adj=None): global allocate_lock if allocate_lock is None: from thread import allocate_lock + # writelock protects all accesses to outbuf, since reads and + # writes of buffers in this class need to be serialized. writelock = allocate_lock() self._writelock_acquire = writelock.acquire self._writelock_release = writelock.release self._writelock_locked = writelock.locked - DualModeChannel.__init__(self, server, conn, addr, adj, socket_map) + DualModeChannel.__init__(self, conn, addr, adj) # # ASYNCHRONOUS METHODS @@ -285,10 +271,10 @@ finally: self._writelock_release() - def flush(self): + def flush(self, block=1): self._writelock_acquire() try: - DualModeChannel.flush(self) + DualModeChannel.flush(self, block) finally: self._writelock_release() === Zope3/lib/python/Zope/Server/IHeaderOutput.py 1.1.2.3 => 1.1.2.4 === +# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved. # -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# -############################################################################## + + from Interface import Interface === Zope3/lib/python/Zope/Server/IRequestFactory.py 1.1.4.2 => 1.1.4.3 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# +# FOR A PARTICULAR PURPOSE +# ############################################################################## """ @@ -30,4 +30,4 @@ """ - + === Zope3/lib/python/Zope/Server/IStreamConsumer.py 1.1.2.3 => 1.1.2.4 === +# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved. # -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# -############################################################################## + + from Interface import Interface from Interface.Attribute import Attribute @@ -18,7 +15,7 @@ """Consumes a data stream until reaching a completion point. The actual amount to be consumed might not be known ahead of time. - """ + """ def received(data): """Accepts data, returning the number of bytes consumed.""" === Zope3/lib/python/Zope/Server/ITask.py 1.1.2.3 => 1.1.2.4 === +# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved. # -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# -############################################################################## + + from Interface import Interface === Zope3/lib/python/Zope/Server/ITaskDispatcher.py 1.1.2.2 => 1.1.2.3 === +# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved. # -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# -############################################################################## + + from Interface import Interface class ITaskDispatcher (Interface): === Zope3/lib/python/Zope/Server/ServerBase.py 1.1.2.4 => 1.1.2.5 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## -import os +""" + +$Id$ +""" + import asyncore import socket -import time -import sys -from thread import allocate_lock -from DualModeChannel import AlternateSocketMapMixin -from IStreamConsumer import IStreamConsumer from Adjustments import default_adj +from IServer import IServer -# Enable ZOPE_SERVER_SIMULT_MODE to enable experimental -# simultaneous channel mode, which may improve or degrade -# throughput depending on load characteristics. -if os.environ.get('ZOPE_SERVER_SIMULT_MODE'): - from DualModeChannel import SimultaneousModeChannel as \ - channel_base_class -else: - from DualModeChannel import DualModeChannel as channel_base_class - - - -class FixedStreamReceiver: - - __implements__ = IStreamConsumer - - completed = 0 - - def __init__(self, cl, buf): - self.remain = cl - self.buf = buf - - def received(self, data): - rm = self.remain - if rm < 1: - self.completed = 1 # Avoid any chance of spinning - return 0 - datalen = len(data) - if rm <= datalen: - self.buf.append(data[:rm]) - self.remain = 0 - self.completed = 1 - return rm - else: - self.buf.append(data) - self.remain -= datalen - return datalen - - def getfile(self): - return self.buf.getfile() - - - -# Synchronize access to the "running_tasks" attributes. -running_lock = allocate_lock() - - - -class ServerChannelBase (channel_base_class): - """Base class for a high-performance, mixed-mode server-side channel. - """ - - parser_class = None # Subclasses must provide a parser class - task_class = None # ... and a task class. - - active_channels = {} # Class-specific channel tracker - next_channel_cleanup = [0] # Class-specific cleanup time - proto_request = None # A request parser instance - ready_requests = None # A list - last_activity = 0 # Time of last activity - running_tasks = 0 # boolean: true when any task is being executed - - # - # ASYNCHRONOUS METHODS (incl. __init__) - # - - def __init__(self, server, conn, addr, adj=None, socket_map=None): - channel_base_class.__init__(self, server, conn, addr, adj, socket_map) - self.last_activity = t = self.creation_time - self.check_maintenance(t) - - def add_channel(self, map=None): - """This hook keeps track of opened HTTP channels. - """ - channel_base_class.add_channel(self, map) - self.active_channels[self._fileno] = self - - def del_channel(self, map=None): - """This hook keeps track of closed HTTP channels. - """ - channel_base_class.del_channel(self, map) - ac = self.active_channels - fd = self._fileno - if ac.has_key(fd): - del ac[fd] - - def check_maintenance(self, now): - """Performs maintenance if necessary. - """ - if now < self.next_channel_cleanup[0]: - return - self.next_channel_cleanup[0] = now + self.adj.cleanup_interval - self.maintenance() - - def maintenance(self): - """Kills off dead connections. - """ - self.kill_zombies() - - def kill_zombies(self): - """Closes connections that have not had any activity in a while. - - The timeout is configured through adj.channel_timeout (seconds). - """ - now = time.time() - cutoff = now - self.adj.channel_timeout - for channel in self.active_channels.values(): - if (channel is not self and not channel.running_tasks and - channel.last_activity < cutoff): - channel.close() - - def received(self, data): - """Receives input asynchronously and launches or queues requests. - """ - preq = self.proto_request - while data: - if preq is None: - preq = self.parser_class(self.adj) - n = preq.received(data) - if preq.completed: - # The request is ready to use. - if not preq.empty: - self.queue_request(preq) - preq = None - self.proto_request = None - else: - self.proto_request = preq - if n >= len(data): - break - data = data[n:] - - def queue_request(self, req): - """Queues a request to be processed in sequence. - """ - do_now = 0 - running_lock.acquire() - try: - if self.running_tasks: - # Wait for the current tasks to finish. - rr = self.ready_requests - if rr is None: - rr = [] - self.ready_requests = rr - rr.append(req) - else: - # Do it now. - self.running_tasks = 1 - do_now = 1 - finally: - running_lock.release() - if do_now: - self.process_request(req) - - def handle_error(self): - """Handles program errors (not communication errors) - """ - t, v = sys.exc_info()[:2] - if t is SystemExit or t is KeyboardInterrupt: - raise t, v - asyncore.dispatcher.handle_error(self) - - def handle_comm_error(self): - """Handles communication errors (not program errors) - """ - if self.adj.log_socket_errors: - self.handle_error() - else: - # Ignore socket errors. - self.close() - - # - # SYNCHRONOUS METHODS - # - - def end_task(self, close): - """Called at the end of a task and may launch another task. - """ - if close: - self.close_when_done() - return - new_req = None - running_lock.acquire() - try: - rr = self.ready_requests - if rr: - new_req = rr.pop(0) - else: - # No requests to service. - self.running_tasks = 0 - finally: - running_lock.release() - if new_req: - # Respond to the next request. - self.process_request(new_req) - else: - # Wait for another request on this connection. - self.set_async() - - # - # BOTH MODES - # - - def process_request(self, req): - """Creates a new task and queues it for execution. - - The task may get executed in another thread. - """ - self.set_sync() - task = self.task_class(self, req) - self.server.addTask(task) - - - - - -class ServerBase (AlternateSocketMapMixin, asyncore.dispatcher): +class ServerBase(asyncore.dispatcher, object): """Async. server base for launching derivatives of ServerChannelBase. """ + __implements__ = asyncore.dispatcher.__implements__, IServer + channel_class = None # Override with a channel class. SERVER_IDENT = 'Zope.Server.ServerBase' # Override. def __init__(self, ip, port, task_dispatcher=None, adj=None, start=1, - hit_log=None, verbose=0, socket_map=None): + hit_log=None, verbose=0): if adj is None: adj = default_adj self.adj = adj - self.socket_map = socket_map asyncore.dispatcher.__init__(self) self.port = port self.task_dispatcher = task_dispatcher @@ -296,23 +83,40 @@ self.port )) + + def addTask(self, task): + td = self.task_dispatcher + if td is not None: + td.addTask(task) + else: + task.service() + + ############################################################ + # Implementation methods for interface + # Zope.Server.IDispatcher.IDispatcher + def readable(self): + 'See Zope.Server.IDispatcher.IDispatcher' return (self.accepting and len(asyncore.socket_map) < self.adj.connection_limit) - def writable (self): + def writable(self): + 'See Zope.Server.IDispatcher.IDispatcher' return 0 - - def handle_read (self): + + ###################################### + # from: Zope.Server.IDispatcherEventHandler.IDispatcherEventHandler + + def handle_read(self): + 'See Zope.Server.IDispatcherEventHandler.IDispatcherEventHandler' pass - - def readable (self): - return self.accepting - - def handle_connect (self): + + def handle_connect(self): + 'See Zope.Server.IDispatcherEventHandler.IDispatcherEventHandler' pass - def handle_accept (self): + def handle_accept(self): + 'See Zope.Server.IDispatcherEventHandler.IDispatcherEventHandler' try: v = self.accept() if v is None: @@ -327,12 +131,8 @@ self.log_info ('warning: server accept() threw an exception', 'warning') return - self.channel_class(self, conn, addr, self.adj, self.socket_map) + self.channel_class(self, conn, addr, self.adj) - def addTask(self, task): - td = self.task_dispatcher - if td is not None: - td.addTask(task) - else: - task.service() + # + ############################################################ === Zope3/lib/python/Zope/Server/TaskThreads.py 1.1.2.8 => 1.1.2.9 === +# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved. # -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# -############################################################################## + + import sys from Queue import Queue, Empty from thread import allocate_lock, start_new_thread === Zope3/lib/python/Zope/Server/Utilities.py 1.1.2.3 => 1.1.2.4 === +# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved. # -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# -############################################################################## + + def find_double_newline(s): """Returns the position just after a double newline in the given string.""" pos1 = s.find('\n\r\n') # One kind of double newline === Zope3/lib/python/Zope/Server/ZLogIntegration.py 1.1.2.3 => 1.1.2.4 === +# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved. # -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# -############################################################################## """Makes asyncore log to zLOG. """ === Zope3/lib/python/Zope/Server/__init__.py 1.1.2.5 => 1.1.2.6 === # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. -# +# ############################################################################## """ Zope.Server package. -""" - - - +$Id$ +""" -### A routine to try to arrange for request sockets to be closed -### on exec. This makes it easier for folks who spawn long running -### processes from Zope code. Thanks to Dieter Maurer for this. -##try: -## import fcntl, FCNTL -## FCNTL.F_SETFD; FCNTL.FD_CLOEXEC -## def requestCloseOnExec(sock): -## try: fcntl.fcntl(sock.fileno(), FCNTL.F_SETFD, FCNTL.FD_CLOEXEC) -## except: pass - -##except (ImportError, AttributeError): - -## def requestCloseOnExec(sock): -## pass +from IDispatcher import IDispatcher +from Interface.Implements import implements -##import asyncore -##from medusa import resolver, logger -##from HTTPServer import zhttp_server, zhttp_handler -##from PubCore import setNumberOfThreads -##from medusa.monitor import secure_monitor_server +import asyncore -### override the service name in logger.syslog_logger -##logger.syslog_logger.svc_name='ZServer' +implements(asyncore.dispatcher, IDispatcher, 0) === Removed File Zope3/lib/python/Zope/Server/Chunking.py === === Removed File Zope3/lib/python/Zope/Server/HTTPServer.py === === Removed File Zope3/lib/python/Zope/Server/PublisherServers.py === From shane@cvs.zope.org Fri Apr 12 22:31:22 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Fri, 12 Apr 2002 17:31:22 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication - ZopePublication.py:1.1.2.35 Message-ID: <200204122131.g3CLVMw22151@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/App/ZopePublication Modified Files: Tag: Zope-3x-branch ZopePublication.py Log Message: Merged Zope3-Server-Branch. === Zope3/lib/python/Zope/App/ZopePublication/ZopePublication.py 1.1.2.34 => 1.1.2.35 === from PublicationTraverse import PublicationTraverse -from Zope.Publisher.Browser.IBrowserPublisher import IBrowserPublisher - class RequestContainer: # TODO: add security assertion declaring access to REQUEST From fdrake@acm.org Fri Apr 12 22:40:31 2002 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Fri, 12 Apr 2002 17:40:31 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/PageTemplates - ZopePageTemplate.py:1.36 Message-ID: <200204122140.g3CLeVQ24617@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/PageTemplates In directory cvs.zope.org:/tmp/cvs-serv24610 Modified Files: ZopePageTemplate.py Log Message: Change it back -- Casey tells me it should be tolerant of objects derived from ExtensionClass, and reminded me that the 2.1 version of isinstance() does not deal with the more general constructs that newer versions of Python can handle. === Zope/lib/python/Products/PageTemplates/ZopePageTemplate.py 1.35 => 1.36 === raise ResourceLockedError, "File is locked via WebDAV" - if not isinstance(file, StringType): + if type(file) is not StringType: if not file: raise ValueError, 'File not specified' file = file.read() From andreas@digicool.com Fri Apr 12 23:08:11 2002 From: andreas@digicool.com (Andreas Jung) Date: Fri, 12 Apr 2002 18:08:11 -0400 Subject: [Zope-Checkins] CVS: Zope - zpasswd.py:1.15 Message-ID: <200204122208.g3CM8BR04771@cvs.baymountain.com> Update of /cvs-repository/Zope In directory cvs.zope.org:/tmp/cvs-serv4463 Modified Files: zpasswd.py Log Message: replaced whrandom by random module because whrandom will be deprecated soon === Zope/zpasswd.py 1.14 => 1.15 === __version__='$Revision$ '[11:-2] -import sys, sha, binascii, whrandom, getopt, getpass, os +import sys, sha, binascii, random, getopt, getpass, os try: from crypt import crypt @@ -27,7 +27,7 @@ salt_choices = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789./") - return whrandom.choice(salt_choices)+whrandom.choice(salt_choices) + return random.choice(salt_choices)+random.choice(salt_choices) def generate_passwd(password, encoding): encoding=encoding.upper() @@ -41,14 +41,13 @@ return pw def write_generated_password(home, ac_path, username): - import whrandom pw_choices = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789!") acfile=open(ac_path, 'w') pw = '' for i in range(8): - pw = pw + whrandom.choice(pw_choices) + pw = pw + random.choice(pw_choices) acfile.write('%s:%s' % (username, generate_passwd(pw, 'SHA'))) acfile.close() os.system('chmod 644 %s' % ac_path) From jeremy@zope.com Fri Apr 12 23:16:20 2002 From: jeremy@zope.com (Jeremy Hylton) Date: Fri, 12 Apr 2002 18:16:20 -0400 Subject: [Zope-Checkins] CVS: StandaloneZODB/ZODB - cPickleCache.c:1.56 Message-ID: <200204122216.g3CMGKw09403@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZODB In directory cvs.zope.org:/tmp/cvs-serv9394 Modified Files: cPickleCache.c Log Message: Sundry changes. Implement behavior for minimize() and full_sweep() as discussed on zodb-dev. minimize() ghostifies all unmodified objects. full_sweep() with age==0 is the same as minimize(), otherwise it's the same as incrgc(). Reformat and/or reindent lots of code. Use PyObject_Compare() instead of PyObject_Cmp() because it has a simpler return value. Fix a few more PyDict_SetItem() and PyDict_DelItem() calls to make correct check for error return. === StandaloneZODB/ZODB/cPickleCache.c 1.55 => 1.56 === #ifdef MUCH_RING_CHECKING - int safety_counter = self->cache_size*10; - if (safety_counter<10000) + int safety_counter = self->cache_size * 10; + if (safety_counter < 10000) safety_counter = 10000; #endif @@ -368,29 +368,25 @@ return lockgc(self, target_size); } -/* XXX Does it make sense for full_sweep() and reallyfull_sweep() to - empty the cache completely? I agree that it would if dt is 0, but - don't think it should for other times. Perhaps it should just call - incrgc() if dt > 2; the new cache may be efficient enough that - incrgc() would suffice. -*/ - static PyObject * cc_full_sweep(ccobject *self, PyObject *args) { int dt = 0; if (!PyArg_ParseTuple(args, "|i:full_sweep", &dt)) return NULL; - return lockgc(self, 0); + if (dt == 0) + return lockgc(self, 0); + else + return cc_incrgc(self, args); } static PyObject * -cc_reallyfull_sweep(ccobject *self, PyObject *args) +cc_minimize(ccobject *self, PyObject *args) { - int dt = 0; - if (!PyArg_ParseTuple(args, "|i:reallyfull_sweep", &dt)) - return NULL; - return lockgc(self, 0); + int ignored; + if (!PyArg_ParseTuple(args, "|i:minimize", &ignored)) + return NULL; + return lockgc(self, 0); } static void @@ -425,67 +421,75 @@ { PyObject *inv, *key, *v; int i; - + + /* XXX The code supports invalidation of all objects, but I don't + think it's possible for a Connection object to pass None. If + this is correct, the code could be simplied. + */ + if (PyArg_ParseTuple(args, "O!", &PyDict_Type, &inv)) { - for (i=0; PyDict_Next(inv, &i, &key, &v); ) - if (key==Py_None) - { /* Eek some nitwit invalidated everything! */ - for (i=0; PyDict_Next(self->data, &i, &key, &v); ) - _invalidate(self, key); - break; - } - else - _invalidate(self, key); - PyDict_Clear(inv); + for (i=0; PyDict_Next(inv, &i, &key, &v); ) + if (key == Py_None) { + /* Eek some nitwit invalidated everything! */ + for (i=0; PyDict_Next(self->data, &i, &key, &v); ) + _invalidate(self, key); + break; + } + else + _invalidate(self, key); + PyDict_Clear(inv); } else { - PyErr_Clear(); - UNLESS (PyArg_ParseTuple(args, "O", &inv)) return NULL; - if (PyString_Check(inv)) - _invalidate(self, inv); - else if (inv==Py_None) /* All */ - for (i=0; PyDict_Next(self->data, &i, &key, &v); ) - _invalidate(self, key); - else { - int l; - PyErr_Clear(); - if ((l=PyObject_Length(inv)) < 0) return NULL; - for(i=l; --i >= 0; ) - { - UNLESS (key=PySequence_GetItem(inv, i)) return NULL; - _invalidate(self, key); - Py_DECREF(key); - } - PySequence_DelSlice(inv, 0, l); - } + if (!PyArg_ParseTuple(args, "O:invalidate", &inv)) + return NULL; + if (PyString_Check(inv)) + _invalidate(self, inv); + else if (inv == Py_None) /* All */ + for (i=0; PyDict_Next(self->data, &i, &key, &v); ) + _invalidate(self, key); + else { + int l; + + PyErr_Clear(); + l = PyObject_Length(inv); + if (l < 0) + return NULL; + for (i=l; --i >= 0; ) { + key = PySequence_GetItem(inv, i); + if (!key) + return NULL; + _invalidate(self, key); + Py_DECREF(key); + } + PySequence_DelSlice(inv, 0, l); + } } - + Py_INCREF(Py_None); return Py_None; } - static PyObject * cc_get(ccobject *self, PyObject *args) { - PyObject *r, *key, *d=0; + PyObject *r, *key, *d = NULL; - if (!PyArg_ParseTuple(args, "O|O:get", &key, &d)) - return NULL; + if (!PyArg_ParseTuple(args, "O|O:get", &key, &d)) + return NULL; - r = (PyObject *)object_from_oid(self, key); - if (!r) { - if (d) { - r = d; - Py_INCREF(r); - } else { - PyErr_SetObject(PyExc_KeyError, key); - return NULL; - } - } + r = (PyObject *)object_from_oid(self, key); + if (!r) { + if (d) { + r = d; + Py_INCREF(r); + } else { + PyErr_SetObject(PyExc_KeyError, key); + return NULL; + } + } - return r; + return r; } static PyObject * @@ -638,17 +642,13 @@ }, {"full_sweep", (PyCFunction)cc_full_sweep, METH_VARARGS, "full_sweep([age]) -- Perform a full sweep of the cache\n\n" - "Make a single pass through the cache, removing any objects that are no\n" - "longer referenced, and deactivating enough objects to bring\n" - "the cache under its size limit\n" - "The optional 'age' parameter is ignored.\n" + "Supported for backwards compatibility. If the age argument is 0,\n" + "behaves like minimize(). Otherwise, behaves like incrgc()." }, - {"minimize", (PyCFunction)cc_reallyfull_sweep, METH_VARARGS, - "minimize([age]) -- Remove as many objects as possible\n\n" - "Make multiple passes through the cache, removing any objects that are no\n" - "longer referenced, and deactivating enough objects to bring the" - " cache under its size limit\n" - "The option 'age' parameter is ignored.\n" + {"minimize", (PyCFunction)cc_minimize, METH_VARARGS, + "minimize([ignored]) -- Remove as many objects as possible\n\n" + "Ghostify all objects that are not modified. Takes an optional\n" + "argument, but ignores it." }, {"incrgc", (PyCFunction)cc_incrgc, METH_VARARGS, "incrgc([n]) -- Perform incremental garbage collection\n\n" @@ -742,24 +742,24 @@ static int cc_length(ccobject *self) { - return PyObject_Length(self->data); + return PyObject_Length(self->data); } static PyObject * cc_subscript(ccobject *self, PyObject *key) { - PyObject *r; + PyObject *r; - if (ring_corrupt(self, "__getitem__")) - return NULL; + if (ring_corrupt(self, "__getitem__")) + return NULL; - r = (PyObject *)object_from_oid(self, key); - if (r == NULL) { - PyErr_SetObject(PyExc_KeyError, key); - return NULL; - } + r = (PyObject *)object_from_oid(self, key); + if (r == NULL) { + PyErr_SetObject(PyExc_KeyError, key); + return NULL; + } - return r; + return r; } static int @@ -795,16 +795,17 @@ return -1; /* XXX key and oid should both be PyString objects. May be helpful to check this. */ - if (PyObject_Cmp(key, oid, &result) < 0) { + result = PyObject_Compare(key, oid); + if (PyErr_Occurred()) { Py_DECREF(oid); return -1; - } + } Py_DECREF(oid); if (result) { - PyErr_SetString(PyExc_ValueError, - "key must be the same as the object's oid attribute"); + PyErr_SetString(PyExc_ValueError, "cache key does not match oid"); return -1; } + object_again = object_from_oid(self, key); if (object_again) { if (object_again != v) { @@ -818,8 +819,9 @@ return 0; } } + if (PyExtensionClass_Check(v)) { - if (PyDict_SetItem(self->data, key, v)) + if (PyDict_SetItem(self->data, key, v) < 0) return -1; self->klass_count++; return 0; @@ -842,7 +844,7 @@ if (ring_corrupt(self, "pre-setitem")) return -1; - if (PyDict_SetItem(self->data, key, v)) + if (PyDict_SetItem(self->data, key, v) < 0) return -1; p = (cPersistentObject *)v; @@ -1015,28 +1017,24 @@ }; static PyTypeObject Cctype = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "cPickleCache", /*tp_name*/ - sizeof(ccobject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - (destructor)cc_dealloc, /*tp_dealloc*/ - (printfunc)0, /*tp_print*/ - (getattrfunc)cc_getattr, /*tp_getattr*/ - (setattrfunc)cc_setattr, /*tp_setattr*/ - (cmpfunc)0, /*tp_compare*/ - (reprfunc)0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - &cc_as_mapping, /*tp_as_mapping*/ - (hashfunc)0, /*tp_hash*/ - (ternaryfunc)0, /*tp_call*/ - (reprfunc)0, /*tp_str*/ - - /* Space for future expansion */ - 0L,0L,0L,0L, - "" + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "cPickleCache", /*tp_name*/ + sizeof(ccobject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)cc_dealloc, /*tp_dealloc*/ + (printfunc)0, /*tp_print*/ + (getattrfunc)cc_getattr, /*tp_getattr*/ + (setattrfunc)cc_setattr, /*tp_setattr*/ + (cmpfunc)0, /*tp_compare*/ + (reprfunc)0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + &cc_as_mapping, /*tp_as_mapping*/ + (hashfunc)0, /*tp_hash*/ + (ternaryfunc)0, /*tp_call*/ + (reprfunc)0, /*tp_str*/ }; static ccobject * From chrism@zope.com Sat Apr 13 15:22:40 2002 From: chrism@zope.com (Chris McDonough) Date: Sat, 13 Apr 2002 10:22:40 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/StructuredText - ClassicStructuredText.py:1.6 Message-ID: <200204131422.g3DEMef30898@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/StructuredText In directory cvs.zope.org:/tmp/cvs-serv29983 Modified Files: ClassicStructuredText.py Log Message: Committing patch from Albert Ting on Zope maillist 4/12. Regex change which fixes a table parsing problem. === Zope/lib/python/StructuredText/ClassicStructuredText.py 1.5 => 1.6 === ROW='
\n%s
' - def create(self,aPar, - td_reg=re.compile(r'[ \t\n]*\|\|([^\0x00|]*)') + td_reg=re.compile(r'[ \t\n]*\|\|([^\0|]*)') ): '''parses a table and returns nested list representing the table''' From chrism@zope.com Sat Apr 13 15:23:42 2002 From: chrism@zope.com (Chris McDonough) Date: Sat, 13 Apr 2002 10:23:42 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/StructuredText - ClassicStructuredText.py:1.4.10.1 Message-ID: <200204131423.g3DENgY30991@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/StructuredText In directory cvs.zope.org:/tmp/cvs-serv30979 Modified Files: Tag: Zope-2_5-branch ClassicStructuredText.py Log Message: Committing patch from Albert Ting on Zope maillist. Fixes problem with table parsing regex. === Zope/lib/python/StructuredText/ClassicStructuredText.py 1.4 => 1.4.10.1 === def create(self,aPar, - td_reg=re.compile(r'[ \t\n]*\|\|([^\0x00|]*)') + td_reg=re.compile(r'[ \t\n]*\|\|([^\0|]*)') ): '''parses a table and returns nested list representing the table''' From chrism@zope.com Sat Apr 13 15:24:54 2002 From: chrism@zope.com (Chris McDonough) Date: Sat, 13 Apr 2002 10:24:54 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.406.2.50 Message-ID: <200204131424.g3DEOs331118@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv31111 Modified Files: Tag: Zope-2_5-branch CHANGES.txt Log Message: === Zope/doc/CHANGES.txt 1.406.2.49 => 1.406.2.50 === Bugs Fixed + - Fixed table regex parsing bug in ClassicStructuredText + thanks to Albert Ting via Zope maillist. + - Register CatalogPathAware as a ZClass base class in response to Collector #33. From jeremy@zope.com Sat Apr 13 21:17:22 2002 From: jeremy@zope.com (Jeremy Hylton) Date: Sat, 13 Apr 2002 16:17:22 -0400 Subject: [Zope-Checkins] CVS: StandaloneZODB/ZODB - Connection.py:1.65 Message-ID: <200204132017.g3DKHMk23125@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZODB In directory cvs.zope.org:/tmp/cvs-serv23118 Modified Files: Connection.py Log Message: Use cache.get() instead of has_key() & __getitem__() combo. === StandaloneZODB/ZODB/Connection.py 1.64 => 1.65 === except: pass - def __getitem__(self, oid, - tt=type(())): - cache=self._cache - if cache.has_key(oid): return cache[oid] + def __getitem__(self, oid, tt=type(())): + obj = self._cache.get(oid, None) + if obj is not None: + return obj __traceback_info__ = (oid) p, serial = self._storage.load(oid, self._version) @@ -144,8 +144,9 @@ object._p_changed=None object._p_serial=serial - cache[oid]=object - if oid=='\0\0\0\0\0\0\0\0': self._root_=object # keep a ref + self._cache[oid] = object + if oid=='\0\0\0\0\0\0\0\0': + self._root_=object # keep a ref return object def _persistent_load(self,oid, @@ -153,13 +154,13 @@ __traceback_info__=oid - cache=self._cache - if type(oid) is tt: # Quick instance reference. We know all we need to know # to create the instance wo hitting the db, so go for it! oid, klass = oid - if cache.has_key(oid): return cache[oid] + obj = self._cache.get(oid, None) + if obj is not None: + return obj if type(klass) is tt: module, name = klass @@ -175,11 +176,13 @@ object._p_jar=self object._p_changed=None - cache[oid]=object + self._cache[oid] = object return object - if cache.has_key(oid): return cache[oid] + obj = self._cache.get(oid, None) + if obj is not None: + return obj return self[oid] def _setDB(self, odb): @@ -219,8 +222,11 @@ else: self._cache.invalidate(object._p_oid) - def cacheFullSweep(self, dt=0): self._cache.full_sweep(dt) - def cacheMinimize(self, dt=0): self._cache.minimize(dt) + def cacheFullSweep(self, dt=0): + self._cache.full_sweep(dt) + + def cacheMinimize(self, dt=0): + self._cache.minimize(dt) __onCloseCallbacks = None @@ -426,7 +432,6 @@ self._tmp=None self._storage=tmp - self._cache.invalidate(src._index.keys()) self._invalidate_creating(src._creating) From garyposter@earthlink.net Sun Apr 14 22:21:03 2002 From: garyposter@earthlink.net (Gary Poster) Date: Sun, 14 Apr 2002 17:21:03 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Configuration - HookRegistry.py:1.1.2.1 configuration-meta.zcml:1.1.2.1 metaConfigure.py:1.1.2.1 name.py:1.1.2.12 xmlconfig.py:1.1.2.14 Message-ID: <200204142121.g3ELL3105222@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Configuration In directory cvs.zope.org:/tmp/cvs-serv2286 Modified Files: Tag: Zope-3x-branch name.py xmlconfig.py Added Files: Tag: Zope-3x-branch HookRegistry.py configuration-meta.zcml metaConfigure.py Log Message: added support for and tags; won't be actually usable until the next commit, in which I point zope.zcml at configuration-meta.zcml. Also added a name normalization routine in names.py. hookable tag sets up a possible object that can be overwritten: module is optional so you can also write These are assuming you are setting up a hookable that you loaded in the package's __init__.py. Here's one more example, this time completely hypothetical (the other two will not be hypothetical after the next commit). You use a hook with the "hook" tag: or if you are in the right place in the file system, shorten the implementation value to ".hooks._getServiceManager". Again, it won't be in use until later this evening, after I get back from doing other things. But you can glance at it now, if so desired. === Added File Zope3/lib/python/Zope/Configuration/HookRegistry.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: HookRegistry.py,v 1.1.2.1 2002/04/14 21:21:02 poster Exp $ """ from types import ModuleType from Zope.Exceptions import DuplicationError, NotFoundError, ZopeError import name class MissingHookableError(NotFoundError): """the stated hook has not been registered""" class DuplicateHookError(DuplicationError): """an implementation for the given hook has already been registered""" class BadHookableError(ZopeError): """hookable cannot be found or is not usable""" class BadHookError(ZopeError): """hook cannot be set""" class HookRegistry: def __init__(self): self._reg = {} def addHookable(self, hname): if self._reg.has_key(hname): raise DuplicationError(hname) try: name.resolve(hname) except ImportError: raise BadHookableError( "default hookable implementation cannot be found", hname) parent, last=self._getParentAndLast(hname) self._reg[hname]=0 def addHook(self, hookablename, hookname): if not self._reg.has_key(hookablename): raise MissingHookableError(hookablename) if self._reg[hookablename]: raise DuplicateHookError(hookablename, hookname) try: implementation=name.resolve(hookname) except ImportError: raise BadHookError('cannot find implementation', hookname) try: hookableDefault=name.resolve(hookablename) except: raise BadHookableError( 'hookable cannot be found, but was found earlier: some code has probably masked the hookable', hookablename) # This won't work as is: I'd have to create a NumberTypes and do # various annoying checks #if type(implementation) is not type (hookableDefault): # raise BadHookError( # 'hook and hookable must be same type') # if they are functions, could check to see if signature is same # (somewhat tricky because functions and methods could be # interchangable but would have a different signature because # of 'self') # for now I'll leave both of the above to the sanity of the site # configuration manager... # find and import immediate parent parent, last=self._getParentAndLast(hookablename) # set parent.last to implementation setattr(parent, last, implementation) self._reg[hookablename]=hookname def _getParentAndLast(self, hookablename): if hookablename.endswith('.') or hookablename.endswith('+'): hookablename = hookablename[:-1] repeat = 1 else: repeat = 0 names=hookablename.split(".") last=names.pop() importname=".".join(names) if not importname: if not repeat: raise BadHookableError( 'hookable cannot be on top level of Python namespace', hookablename) importname=last parent=__import__(importname,{},{},('__doc__',)) child=getattr(parent, last, self) if child is self: raise BadHookableError( 'hookable cannot be on top level of Python namespace', hookablename) while repeat: grand=getattr(child, last, self) if grand is self: break parent=child child=grand if type(parent) is not ModuleType: raise BadHookableError("parent of hookable must be a module") return parent, last def getHooked(self): return [(key, self._reg[key]) for key in self._reg if self._reg[key]] def getUnhooked(self): return [(key, self._reg[key]) for key in self._reg if not self._reg[key]] def getHookables(self): return [(key, self._reg[key]) for key in self._reg] === Added File Zope3/lib/python/Zope/Configuration/configuration-meta.zcml === === Added File Zope3/lib/python/Zope/Configuration/metaConfigure.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: metaConfigure.py,v 1.1.2.1 2002/04/14 21:21:02 poster Exp $ """ from Action import Action from HookRegistry import HookRegistry hookRegistry=HookRegistry() # one could make this a service and # theoretically use it TTW, but that doesn't immediately seem like a # great idea addHookable=hookRegistry.addHookable addHook=hookRegistry.addHook def provideHookable(_context, name, module=None): if module: name="%s.%s" % (module, name) name=_context.getNormalizedName(name) return [ Action( discriminator = ('addHookable', name), callable = addHookable, args = (name,) ) ] def provideHook(_context, name, implementation, module=None): if module: name="%s.%s" % (module, name) name=_context.getNormalizedName(name) implementation=_context.getNormalizedName(implementation) return [ Action( discriminator = ('addHook', name), callable = addHook, args = (name, implementation) ) ] === Zope3/lib/python/Zope/Configuration/name.py 1.1.2.11 => 1.1.2.12 === """Provide configuration object name resolution +$Id$ """ import sys @@ -47,3 +48,23 @@ if not repeat or (not isinstance(a, ModuleType)): return a mod += '.' + last + + +def getNormalizedName(name, package): + name=name.strip() + if name.startswith('.'): + name=package+name + + if name.endswith('.') or name.endswith('+'): + name = name[:-1] + repeat = 1 + else: + repeat = 0 + name=name.split(".") + while len(name)>1 and name[-1]==name[-2]: + name.pop() + repeat=1 + name=".".join(name) + if repeat: + name+="+" + return name \ No newline at end of file === Zope3/lib/python/Zope/Configuration/xmlconfig.py 1.1.2.13 => 1.1.2.14 === def resolve(self, dottedname): return name.resolve(dottedname, self.__package) + + def getNormalizedName(self, dottedname): + return name.getNormalizedName(dottedname, self.__package) def xmlconfig(file, actions=None, context=None, directives=None): From garyposter@earthlink.net Sun Apr 14 22:21:03 2002 From: garyposter@earthlink.net (Gary Poster) Date: Sun, 14 Apr 2002 17:21:03 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Configuration/tests - hookTestDummyModule.py:1.1.2.1 testHookRegistry.py:1.1.2.1 testNames.py:1.1.2.9 Message-ID: <200204142121.g3ELL3p05221@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Configuration/tests In directory cvs.zope.org:/tmp/cvs-serv2286/tests Modified Files: Tag: Zope-3x-branch testNames.py Added Files: Tag: Zope-3x-branch hookTestDummyModule.py testHookRegistry.py Log Message: added support for and tags; won't be actually usable until the next commit, in which I point zope.zcml at configuration-meta.zcml. Also added a name normalization routine in names.py. hookable tag sets up a possible object that can be overwritten: module is optional so you can also write These are assuming you are setting up a hookable that you loaded in the package's __init__.py. Here's one more example, this time completely hypothetical (the other two will not be hypothetical after the next commit). You use a hook with the "hook" tag: or if you are in the right place in the file system, shorten the implementation value to ".hooks._getServiceManager". Again, it won't be in use until later this evening, after I get back from doing other things. But you can glance at it now, if so desired. === Added File Zope3/lib/python/Zope/Configuration/tests/hookTestDummyModule.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Hook test dummy module $Id: hookTestDummyModule.py,v 1.1.2.1 2002/04/14 21:21:02 poster Exp $ """ def dummyHookable(): return "original implementation" === Added File Zope3/lib/python/Zope/Configuration/tests/testHookRegistry.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: testHookRegistry.py,v 1.1.2.1 2002/04/14 21:21:02 poster Exp $ """ import unittest, sys def dummyHook(): return "hooked implementation" class HookRegistryTest(unittest.TestCase): # def setUp(self): # # from Zope.Configuration.tests import Products_ # self.old=sys.modules.get('ZopeProducts', None) # sys.modules['ZopeProducts']=Products_ # # def tearDown(self): # old=self.old # if old is None: del sys.modules['ZopeProducts'] # else: sys.modules['ZopeProducts']=self.old def testAddHookable(self): from Zope.Configuration.HookRegistry import HookRegistry hookableAddr='Zope.Configuration.tests.hookTestDummyModule.dummyHookable' hookRegistry=HookRegistry() hookRegistry.addHookable(hookableAddr) hookables=hookRegistry.getHookables() self.assertEquals(len(hookables), 1) self.assertEquals(hookables[0][0], hookableAddr) self.assertEquals(hookables[0][1],0) def testAddDuplicateHookable(self): from Zope.Configuration.HookRegistry import HookRegistry from Zope.Exceptions import DuplicationError hookableAddr='Zope.Configuration.tests.hookTestDummyModule.dummyHookable' hookRegistry=HookRegistry() hookRegistry.addHookable(hookableAddr) self.assertRaises(DuplicationError, hookRegistry.addHookable, hookableAddr) def testAddInvalidHookable(self): from Zope.Configuration.HookRegistry import HookRegistry, \ BadHookableError hookRegistry=HookRegistry() self.assertRaises(BadHookableError, hookRegistry.addHookable, 'foo.bar.this.should.not.resolve.anywhere') self.assertRaises(BadHookableError, hookRegistry.addHookable, 'Zope') self.assertRaises(BadHookableError, hookRegistry.addHookable, 'Zope.Configuration.HookRegistry.HookRegistry.addHookable') def testAddHook(self): from Zope.Configuration.HookRegistry import \ HookRegistry, BadHookError, DuplicateHookError, \ MissingHookableError hookableParent='Zope.Configuration.tests.hookTestDummyModule' hookableLast='dummyHookable' hookableAddr='%s.%s' % (hookableParent, hookableLast) hookRegistry=HookRegistry() hookRegistry.addHookable(hookableAddr) old=__import__(hookableParent,{},{}, ('__dict__',)) # for cleanup old=getattr(old, hookableLast) self.assertEquals(old(),"original implementation") self.assertRaises(BadHookError, hookRegistry.addHook, hookableAddr, 'foo.bar.this.should.not.resolve.anywhere') hookRegistry.addHook(hookableAddr, 'Zope.Configuration.tests.testHookRegistry.dummyHook') new=__import__(hookableParent,{},{}, ('__dict__',)) new=getattr(new, hookableLast) self.assertEquals(new(), "hooked implementation") self.assertRaises(DuplicateHookError, hookRegistry.addHook, hookableAddr, 'Zope.Configuration.tests.testHookRegistry.test_suite') self.assertRaises(MissingHookableError, hookRegistry.addHook, 'Zope.Configuration.tests.testHookRegistry.test_suite', 'Zope.Configuration.tests.testHookRegistry.dummyHook') setattr(__import__(hookableParent,{},{}, ('__dict__',)), hookableLast, old) # cleanup def test_suite(): loader=unittest.TestLoader() return loader.loadTestsFromTestCase(HookRegistryTest) if __name__=='__main__': unittest.TextTestRunner().run(test_suite()) === Zope3/lib/python/Zope/Configuration/tests/testNames.py 1.1.2.8 => 1.1.2.9 === # ############################################################################## +""" + +$Id$ +""" + import unittest, sys class NameTest(unittest.TestCase): @@ -59,6 +64,28 @@ import Zope.App.ZMI self.assertEquals(id(c), id(Zope.App.ZMI)) + + nameSet={ + ('Zope.Configuration.tests','Noplace'):'Zope.Configuration.tests', + ('Zope.Configuration.tests.tests','Noplace'):'Zope.Configuration.tests+', + ('Zope.Configuration.tests.tests.tests','Noplace'):'Zope.Configuration.tests+', + ('Zope.Configuration.tests.tests.tests.','Noplace'):'Zope.Configuration.tests+', + ('Zope.Configuration.tests+','Noplace'):'Zope.Configuration.tests+', + ('Zope.Configuration.tests.tests.tests+','Noplace'):'Zope.Configuration.tests+', + ('Zope.Configuration.tests.','Noplace'):'Zope.Configuration.tests+', + ('.tests','Zope.Configuration'):'Zope.Configuration.tests', + ('.tests.tests','Zope.Configuration'):'Zope.Configuration.tests+', + ('.tests.tests.tests','Zope.Configuration'):'Zope.Configuration.tests+', + ('.tests.tests.tests.','Zope.Configuration'):'Zope.Configuration.tests+', + ('.tests+','Zope.Configuration'):'Zope.Configuration.tests+', + ('.tests.tests.tests+','Zope.Configuration'):'Zope.Configuration.tests+', + ('.tests.','Zope.Configuration'):'Zope.Configuration.tests+' + } + + def testNormalizedName(self): + from Zope.Configuration.name import getNormalizedName + for args in self.nameSet: + self.assertEquals(self.nameSet[args], getNormalizedName(*args)) def test_suite(): loader=unittest.TestLoader() From garyposter@earthlink.net Mon Apr 15 04:32:00 2002 From: garyposter@earthlink.net (Gary Poster) Date: Sun, 14 Apr 2002 23:32:00 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ServiceManager/tests - testServiceManager.py:1.1.2.4 Message-ID: <200204150332.g3F3W0820516@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ServiceManager/tests In directory cvs.zope.org:/tmp/cvs-serv19265/App/OFS/ServiceManager/tests Modified Files: Tag: Zope-3x-branch testServiceManager.py Log Message: This commit sets up the hook tag so that it actually works, and uses the new functionality to better divide up the labor of the ComponentArchitecture. The placeless ComponentArchitecture code for getService is still there, but the placeful code has been moved to the ServiceManager section. A few other hooks are also set up in ComponentArchitecture, and a few changes made in preparation for a later update of some placeful services. The ServiceManager test was altered to use the newly moved placeful getService code. Other hooks can now be set up and used using this hopefully helpful mechanism. === Zope3/lib/python/Zope/App/OFS/ServiceManager/tests/testServiceManager.py 1.1.2.3 => 1.1.2.4 === from Zope.App.OFS.ServiceManager.ServiceManager import ServiceManager from Zope.Testing.CleanUp import CleanUp # Base class w registry cleanup -from Zope.ComponentArchitecture import getService, provideService +from Zope.App.OFS.ServiceManager.hooks import _getService as getService +from Zope.ComponentArchitecture import provideService # getService should be local type above from Zope.ComponentArchitecture import defineService from Zope.Exceptions import ZopeError From garyposter@earthlink.net Mon Apr 15 04:32:00 2002 From: garyposter@earthlink.net (Gary Poster) Date: Sun, 14 Apr 2002 23:32:00 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/ComponentArchitecture - Service.py:1.1.6.10 __init__.py:1.1.6.17 component.zcml:1.1.2.2 Message-ID: <200204150332.g3F3W0i20520@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/ComponentArchitecture In directory cvs.zope.org:/tmp/cvs-serv19265/ComponentArchitecture Modified Files: Tag: Zope-3x-branch Service.py __init__.py component.zcml Log Message: This commit sets up the hook tag so that it actually works, and uses the new functionality to better divide up the labor of the ComponentArchitecture. The placeless ComponentArchitecture code for getService is still there, but the placeful code has been moved to the ServiceManager section. A few other hooks are also set up in ComponentArchitecture, and a few changes made in preparation for a later update of some placeful services. The ServiceManager test was altered to use the newly moved placeful getService code. Other hooks can now be set up and used using this hopefully helpful mechanism. === Zope3/lib/python/Zope/ComponentArchitecture/Service.py 1.1.6.9 => 1.1.6.10 === del addCleanUp -def getService(object, name): - """ - context based lookup, with fallback to component architecture - service manager if no service manager found within context - """ - while object is not None: - if IServiceManagerContainer.isImplementedBy(object): - sm = object.getServiceManager(None) - if sm is not None: - return sm.getService(object, name) - object = getinnercontext(object) +# below are imported in ComponentArchitecture __init__ without underline +# (i.e., don't use these, use the hookable imported versions in the package itself) + +def _getServiceManager(context): + return serviceManager + +_getGlobalServiceManager=_getServiceManager + +def _getService(object, name): return serviceManager.getService(object, name) -def getServiceDefinitions(): +def _getServiceDefinitions(): # this needs context if we want it to be placeful """ get service defintions from component architecture service manager. === Zope3/lib/python/Zope/ComponentArchitecture/__init__.py 1.1.6.16 => 1.1.6.17 === from hooks import provideFactory, createObject from Service import defineService, provideService -from Service import getService, getServiceDefinitions +from Service import _getServiceManager as getServiceManager # hookable +from Service import _getService as getService # hookable +from Service import _getServiceDefinitions as getServiceDefinitions # hookable +from Service import _getGlobalServiceManager as getGlobalServiceManager from SkinService import getSkin, defineSkin from ViewService import getView, provideView, getRequestView from ViewService import getDefaultViewName, getRequestDefaultViewName, \ === Zope3/lib/python/Zope/ComponentArchitecture/component.zcml 1.1.2.1 => 1.1.2.2 === component='Zope.ComponentArchitecture.ViewService.viewService' /> + + + + From garyposter@earthlink.net Mon Apr 15 04:32:29 2002 From: garyposter@earthlink.net (Gary Poster) Date: Sun, 14 Apr 2002 23:32:29 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope - zope.zcml:1.1.2.9 Message-ID: <200204150332.g3F3WT620609@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope In directory cvs.zope.org:/tmp/cvs-serv19265 Modified Files: Tag: Zope-3x-branch zope.zcml Log Message: This commit sets up the hook tag so that it actually works, and uses the new functionality to better divide up the labor of the ComponentArchitecture. The placeless ComponentArchitecture code for getService is still there, but the placeful code has been moved to the ServiceManager section. A few other hooks are also set up in ComponentArchitecture, and a few changes made in preparation for a later update of some placeful services. The ServiceManager test was altered to use the newly moved placeful getService code. Other hooks can now be set up and used using this hopefully helpful mechanism. === Zope3/lib/python/Zope/zope.zcml 1.1.2.8 => 1.1.2.9 === + @@ -26,9 +27,9 @@ title="Manage Application" /> + - From garyposter@earthlink.net Mon Apr 15 04:32:29 2002 From: garyposter@earthlink.net (Gary Poster) Date: Sun, 14 Apr 2002 23:32:29 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/OFS/ServiceManager - hooks.py:1.1.2.1 service-manager.zcml:1.1.2.2 Message-ID: <200204150332.g3F3WTt20612@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/ServiceManager In directory cvs.zope.org:/tmp/cvs-serv19265/App/OFS/ServiceManager Modified Files: Tag: Zope-3x-branch service-manager.zcml Added Files: Tag: Zope-3x-branch hooks.py Log Message: This commit sets up the hook tag so that it actually works, and uses the new functionality to better divide up the labor of the ComponentArchitecture. The placeless ComponentArchitecture code for getService is still there, but the placeful code has been moved to the ServiceManager section. A few other hooks are also set up in ComponentArchitecture, and a few changes made in preparation for a later update of some placeful services. The ServiceManager test was altered to use the newly moved placeful getService code. Other hooks can now be set up and used using this hopefully helpful mechanism. === Added File Zope3/lib/python/Zope/App/OFS/ServiceManager/hooks.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: hooks.py,v 1.1.2.1 2002/04/15 03:31:59 poster Exp $ """ from Zope.ComponentArchitecture.IServiceService import IServiceService from Zope.ComponentArchitecture.IServiceManagerContainer import IServiceManagerContainer from Zope.ContextWrapper import getinnercontext from Zope.ComponentArchitecture import getGlobalServiceManager def _getService(context, name): """ context based lookup """ return _getServiceManager(context).getService(context, name) def _getServiceManager(context): """ context based lookup, with fallback to component architecture service manager if no service manager found within context """ while context is not None: # if the context is actually a service or service manager... if IServiceService.isImplementedBy(context): return context if IServiceManagerContainer.isImplementedBy(context): sm = context.getServiceManager() if sm is not None: return sm context = getinnercontext(context) return getGlobalServiceManager() def _getServiceDefinitions(context): # needed? not hooked in now """ context based lookup to get service defintions """ return _getServiceManager(context).getServiceDefinitions() === Zope3/lib/python/Zope/App/OFS/ServiceManager/service-manager.zcml 1.1.2.1 => 1.1.2.2 === + + + + + + From garyposter@earthlink.net Mon Apr 15 05:00:57 2002 From: garyposter@earthlink.net (Gary Poster) Date: Mon, 15 Apr 2002 00:00:57 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/App/ZopePublication - PublicationTraverse.py:1.1.2.14 Message-ID: <200204150400.g3F40v927069@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/App/ZopePublication In directory cvs.zope.org:/tmp/cvs-serv27012 Modified Files: Tag: Zope-3x-branch PublicationTraverse.py Log Message: fixes acquire namespace--or at least makes it accomplish what I understand it to mean! === Zope3/lib/python/Zope/App/ZopePublication/PublicationTraverse.py 1.1.2.13 => 1.1.2.14 === from Zope.Publisher.Exceptions import NotFound from types import StringTypes -from Zope.ContextWrapper import Wrapper +from Zope.ContextWrapper import Wrapper, getcontext from Zope.App.ZMI.Addable import ContentAddables from Zope.App.OFS.Container.IContainer import IWriteContainer @@ -150,16 +150,35 @@ return ApplicationController def _traverseacquire(self, request, ob, name): + """acquires content objects from higher in tree""" i = 0 + origOb=ob while i < 200: i = i + 1 - r = getattr(ob, name, self) - if r is not self: - return r - r = getcontext(ob) - if r is None: - raise NotFound(ob, name, request) - raise ExcessiveWrapping(ob, name, request) + #r = getattr(ob, name, self) # no... + # what we actually want to do is traverse ob, then parents, yes? + # this is a cut and paste of the pertinent traverseName code; + # clean to your pleasure, if desired. + try: + if request.getViewType().isImplementedBy(ob): + ob2 = ob.publishTraverse(request, name) + else: + adapter = getRequestView(ob, '_traverse', request, self # marker + ) + + if adapter is not self: + ob2 = adapter.publishTraverse(request, name) + else: + raise NotFound(ob, name, request) + # the only difference--is this the best way to + # accomplish the wrap we want? + return self._wrap(ob2, origOb, name, name) + + except NotFound: + ob = getcontext(ob) + if ob is None: + raise NotFound(origOb, name, request) + raise ExcessiveWrapping(origOb, name, request) def _traversecreate(self, request, ob, name): for addable in ContentAddables.getAddables(ob): From tdickenson@geminidataloggers.com Mon Apr 15 11:13:56 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Mon, 15 Apr 2002 06:13:56 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.468 Message-ID: <200204151013.g3FADuj26263@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv26256/doc Modified Files: CHANGES.txt Log Message: merged toby-cacheable-zmi-branch and toby-metatype-branch === Zope/doc/CHANGES.txt 1.467 => 1.468 === - New implementation of ZODB object cache. + - Implementation of RestrictedCreation fishbowl proposal; + Product registration can now include a function used to + determine whether that product constructor want to allow + objects to be created in the specified container object. + + - Collector 196: manage_page_style.css is now cacheable. + Added freshness information to ImageFile, to improve + cacheability of management interface + Bugs: - Fixed bug #96: Narrower/Wider buttons now work on both CSS and non-CSS From tdickenson@geminidataloggers.com Mon Apr 15 11:15:27 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Mon, 15 Apr 2002 06:15:27 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - ObjectManager.py:1.150 Message-ID: <200204151015.g3FAFRk27319@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv27298/lib/python/OFS Modified Files: ObjectManager.py Log Message: merged toby-metatype-branch === Zope/lib/python/OFS/ObjectManager.py 1.149 => 1.150 === def all_meta_types(self, interfaces=None): + # A list of products registered elsewhere + external_candidates = [] + + # Look at _product_meta_types, if there is one _pmt=() if hasattr(self, '_product_meta_types'): _pmt=self._product_meta_types elif hasattr(self, 'aq_acquire'): try: _pmt=self.aq_acquire('_product_meta_types') except: pass + external_candidates.extend(list(_pmt)) - if interfaces is None: pmt = list(_pmt) - else: - pmt = [] + # Look at all globally visible meta types. + for entry in Products.meta_types: + if ( (interfaces is not None) or (entry.get("visibility", None)=="Global") ): + external_candidates.append(entry) - for entry in pmt: + # Filter the list of external candidates based on the + # specified interface constraint + if interfaces is None: + interface_constrained_meta_types = external_candidates + else: + interface_constrained_meta_types = [] + for entry in external_candidates: try: eil = entry.get('interfaces',None) - if eil is not None: for ei in eil: for i in interfaces: if ei is i or ei.extends(i): - pmt.append(entry) + interface_constrained_meta_types.append(entry) raise BreakoutException # only append 1ce except BreakoutException: pass - - gmt = [] - - for entry in Products.meta_types: - if interfaces is None: - if entry.get("visibility", None) == "Global": - gmt.append(entry) + # Meta types specified by this instance are not checked against the + # interface constraint. This is as it always has been, but Im not + # sure it is correct. + interface_constrained_meta_types.extend(list(self.meta_types)) + + # Filter the list based on each meta-types's container_filter + meta_types = [] + for entry in interface_constrained_meta_types: + container_filter = entry.get('container_filter',None) + if container_filter is None: + meta_types.append(entry) else: - try: - eil = entry.get("interfaces", None) - if eil is not None: - for ei in eil: - for i in interfaces: - if ei is i or ei.extends(i): - gmt.append(entry) - raise BreakoutException # only append 1ce - except BreakoutException: - pass + if container_filter(self): + meta_types.append(entry) - return list(self.meta_types)+gmt+pmt + return meta_types def _subobject_permissions(self): return (Products.__ac_permissions__+ From tdickenson@geminidataloggers.com Mon Apr 15 11:15:51 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Mon, 15 Apr 2002 06:15:51 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - ProductContext.py:1.39 Message-ID: <200204151015.g3FAFpL27420@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv27413/lib/python/App Modified Files: ProductContext.py Log Message: merged toby-metatype-branch === Zope/lib/python/App/ProductContext.py 1.38 => 1.39 === permission=None, constructors=(), icon=None, permissions=None, legacy=(), - visibility="Global",interfaces=_marker + visibility="Global",interfaces=_marker, + container_filter=None ): """Register a constructor @@ -88,6 +89,13 @@ interfaces -- a list of the interfaces the object supports + container_filter -- function that is called with an ObjectManager + object as the only parameter, which should return a true object + if the object is happy to be created in that container. The + filter is called before showing ObjectManager's Add list, + and before pasting (after object copy or cut), but not + before calling an object's constructor. + """ app=self.__app pack=self.__pack @@ -171,6 +179,7 @@ 'visibility': visibility, 'interfaces': interfaces, 'instance': instance_class, + 'container_filter': container_filter },) m[name]=initial @@ -325,3 +334,4 @@ ht=APIHelpTopic.APIHelpTopic(file, '', os.path.join(path, file)) self.registerHelpTopic(file, ht) + From tdickenson@geminidataloggers.com Mon Apr 15 11:18:30 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Mon, 15 Apr 2002 06:18:30 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - ImageFile.py:1.16 Message-ID: <200204151018.g3FAIUC28443@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv28432/lib/python/App Modified Files: ImageFile.py Log Message: merged toby-cacheable-zmi-branch === Zope/lib/python/App/ImageFile.py 1.15 => 1.16 === from os import stat import Acquisition +import Globals import os - class ImageFile(Acquisition.Explicit): """Image objects stored in external files.""" @@ -33,6 +33,13 @@ _prefix=package_home(_prefix) path = os.path.join(_prefix, path) self.path=path + if Globals.DevelopmentMode: + # In development mode, shorter is handy + max_age = 60 + else: + # In production mode, longer reduces latency + max_age = 600 + self.cch = 'public,max-age=%d' % max_age file=open(path, 'rb') data=file.read() @@ -52,6 +59,9 @@ # HTTP If-Modified-Since header handling. This is duplicated # from OFS.Image.Image - it really should be consolidated # somewhere... + RESPONSE.setHeader('Content-Type', self.content_type) + RESPONSE.setHeader('Last-Modified', self.lmh) + RESPONSE.setHeader('Cache-Control', self.cch) header=REQUEST.get_header('If-Modified-Since', None) if header is not None: header=header.split(';')[0] @@ -72,8 +82,6 @@ RESPONSE.setStatus(304) return '' - RESPONSE.setHeader('Content-Type', self.content_type) - RESPONSE.setHeader('Last-Modified', self.lmh) f=open(self.path,'rb') data=f.read() f.close() From tdickenson@geminidataloggers.com Mon Apr 15 11:18:30 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Mon, 15 Apr 2002 06:18:30 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App/dtml - manage_page_style.css.dtml:1.8 Message-ID: <200204151018.g3FAIU128445@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App/dtml In directory cvs.zope.org:/tmp/cvs-serv28432/lib/python/App/dtml Modified Files: manage_page_style.css.dtml Log Message: merged toby-cacheable-zmi-branch === Zope/lib/python/App/dtml/manage_page_style.css.dtml 1.7 => 1.8 === + h1 { font-family: Verdana, Helvetica, sans-serif; From tdickenson@geminidataloggers.com Mon Apr 15 11:52:30 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Mon, 15 Apr 2002 06:52:30 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/SiteErrorLog - SiteErrorLog.py:1.5 Message-ID: <200204151052.g3FAqUu05067@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/SiteErrorLog In directory cvs.zope.org:/tmp/cvs-serv5060 Modified Files: SiteErrorLog.py Log Message: added _ignored_exceptions; 'Unauthorized' no longer appears in the error log === Zope/lib/python/Products/SiteErrorLog/SiteErrorLog.py 1.4 => 1.5 === return log + # Exceptions that happen all the time, so we dont need + # to log them. Eventually this should be configured + # through-the-web. + _ignored_exceptions = ( 'Unauthorized', ) + security.declarePrivate('raising') def raising(self, info): """Log an exception. @@ -109,6 +114,10 @@ tb_text = None tb_html = None + strtype = str(getattr(info[0], '__name__', info[0])) + if strtype in self._ignored_exceptions: + return + if not isinstance(info[2], StringType) and not isinstance( info[2], UnicodeType): tb_text = ''.join( @@ -137,7 +146,7 @@ log = self._getLog() log.append({ - 'type': str(getattr(info[0], '__name__', info[0])), + 'type': strtype, 'value': strv, 'time': now, 'id': str(now) + str(random()), # Low chance of collision From tdickenson@geminidataloggers.com Mon Apr 15 15:30:22 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Mon, 15 Apr 2002 10:30:22 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App - ImageFile.py:1.17 Message-ID: <200204151430.g3FEUMv02321@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App In directory cvs.zope.org:/tmp/cvs-serv2312/lib/python/App Modified Files: ImageFile.py Log Message: change max-age time to one hour, for consistency with the css === Zope/lib/python/App/ImageFile.py 1.16 => 1.17 === self.path=path if Globals.DevelopmentMode: - # In development mode, shorter is handy - max_age = 60 + # In development mode, a shorter time is handy + max_age = 60 # One minute else: - # In production mode, longer reduces latency - max_age = 600 + # A longer time reduces latency in production mode + max_age = 3600 # One hour self.cch = 'public,max-age=%d' % max_age file=open(path, 'rb') From chrisw@nipltd.com Mon Apr 15 16:17:33 2002 From: chrisw@nipltd.com (Chris Withers) Date: Mon, 15 Apr 2002 11:17:33 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/ZODB - cPickleCache.c:1.57 Message-ID: <200204151517.g3FFHXD14616@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/ZODB In directory cvs.zope.org:/tmp/cvs-serv14609 Modified Files: cPickleCache.c Log Message: Change void* to char* to make VC++ happy. === Zope/lib/python/ZODB/cPickleCache.c 1.56 => 1.57 === * the pointer to the Python object that slot is embedded in. */ - object = (PyObject *)(((void *)here) - offsetof(cPersistentObject, ring)); + object = (PyObject *)(((char *)here) - offsetof(cPersistentObject, ring)); #ifdef MUCH_RING_CHECKING if (!PyExtensionInstance_Check(object)) { From shane@cvs.zope.org Mon Apr 15 16:36:13 2002 From: shane@cvs.zope.org (Shane Hathaway) Date: Mon, 15 Apr 2002 11:36:13 -0400 Subject: [Zope-Checkins] CVS: Zope3/lib/python/Zope/Testing - __init__.py:1.3.38.7 Message-ID: <200204151536.g3FFaDU19153@cvs.baymountain.com> Update of /cvs-repository/Zope3/lib/python/Zope/Testing In directory cvs.zope.org:/tmp/cvs-serv18529 Modified Files: Tag: Zope-3x-branch __init__.py Log Message: Changed default policy for tracebacks--we need the filenames. === Zope3/lib/python/Zope/Testing/__init__.py 1.3.38.6 => 1.3.38.7 === traceback.format_exception = format_exception -# Use the new exception formatter by default, its useful! -if os.environ.get('NEW_EXCEPTION_FORMATTER', 1): +# Don't use the new exception formatter by default, since it +# doesn't show filenames. +if os.environ.get('NEW_ZOPE_EXCEPTION_FORMATTER', 0): patchTracebackModule() From jeremy@zope.com Mon Apr 15 19:43:02 2002 From: jeremy@zope.com (Jeremy Hylton) Date: Mon, 15 Apr 2002 14:43:02 -0400 Subject: [Zope-Checkins] CVS: StandaloneZODB/ZODB - Connection.py:1.66 DB.py:1.41 cPersistence.c:1.59 cPickleCache.c:1.58 Message-ID: <200204151843.g3FIh2E00985@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZODB In directory cvs.zope.org:/tmp/cvs-serv951 Modified Files: Connection.py DB.py cPersistence.c cPickleCache.c Log Message: Remove the cache_deactivate_after argument from the cPickleCache constructor, since it is ignored and there is no current plan to support two caches with almost-but-not-quite-the-same arguments. This change has effects in many files. The Connection and DB don't pass this argument and don't bother setting it explicitly when it is reset via DB APIs like setCacheDeactivateAfter(). XXX These APIs remain, since existing code may depend on them, but they have no effect. New policy in cPersistence.c: A Persistent object can't have its _p_jar set or deleted once it is in a cache. Persistent already implemented this policy for _p_oid; it seems safer to do the same for the jar. Add ringlen() method to cache objects (implemented as cc_ringlen). This returns the length of the doubly linked list of non-ghost objects. Same as len(cache.lru_items()), but more efficient. Only used for testing at the moment. In ring_corrupt(), don't raise a new exception if one has already been set. The old behavior masked useful information about the original error / traceback. === StandaloneZODB/ZODB/Connection.py 1.65 => 1.66 === """Create a new Connection""" self._version=version - self._cache=cache=PickleCache(self, cache_size, cache_deactivate_after) + self._cache = cache = PickleCache(self, cache_size) if version: # Caches for versions end up empty if the version # is not used for a while. Non-version caches # keep their content indefinitely. + + # XXX Why do we want version caches to behave this way? + self._cache.cache_drain_resistance = 100 self._incrgc=self.cacheGC=cache.incrgc self._invalidated=d={} @@ -209,8 +212,7 @@ self._code_timestamp = global_code_timestamp self._invalidated.clear() orig_cache = self._cache - self._cache = PickleCache(self, orig_cache.cache_size, - orig_cache.cache_age) + self._cache = PickleCache(self, orig_cache.cache_size) def abort(self, object, transaction): """Abort the object in the transaction. @@ -226,7 +228,8 @@ self._cache.full_sweep(dt) def cacheMinimize(self, dt=0): - self._cache.minimize(dt) + # dt is ignored + self._cache.minimize() __onCloseCallbacks = None === StandaloneZODB/ZODB/DB.py 1.40 => 1.41 === self._pool_size=pool_size self._cache_size=cache_size - self._cache_deactivate_after=cache_deactivate_after + self._cache_deactivate_after = cache_deactivate_after self._version_pool_size=version_pool_size self._version_cache_size=version_cache_size - self._version_cache_deactivate_after=version_cache_deactivate_after + self._version_cache_deactivate_after = version_cache_deactivate_after self._miv_cache={} @@ -157,17 +157,19 @@ Organized by class.""" - detail={} - def f(con,detail=detail,have_detail=detail.has_key): + detail = {} + def f(con, detail=detail, have_detail=detail.has_key): for oid, ob in con._cache.items(): module = getattr(ob.__class__, '__module__', '') module = module and '%s.' % module or '' - c="%s%s" % (module, ob.__class__.__name__) - if have_detail(c): detail[c]=detail[c]+1 - else: detail[c]=1 + c = "%s%s" % (module, ob.__class__.__name__) + if have_detail(c): + detail[c] = detail[c] + 1 + else: + detail[c] = 1 self._connectionMap(f) - detail=detail.items() + detail = detail.items() detail.sort() return detail @@ -224,7 +226,7 @@ def cacheSize(self): m=[0] def f(con, m=m): - m[0]=m[0]+con._cache.cache_non_ghost_count + m[0] = m[0] + con._cache.cache_non_ghost_count self._connectionMap(f) return m[0] @@ -247,8 +249,11 @@ def exportFile(self, oid, file=None): raise 'Not yet implemented' - def getCacheDeactivateAfter(self): return self._cache_deactivate_after - def getCacheSize(self): return self._cache_size + def getCacheDeactivateAfter(self): + return self._cache_deactivate_after + + def getCacheSize(self): + return self._cache_size def getName(self): return self._storage.getName() @@ -258,9 +263,12 @@ def getVersionCacheDeactivateAfter(self): return self._version_cache_deactivate_after - def getVersionCacheSize(self): return self._version_cache_size + + def getVersionCacheSize(self): + return self._version_cache_size - def getVersionPoolSize(self): return self._version_pool_size + def getVersionPoolSize(self): + return self._version_pool_size def importFile(self, file): raise 'Not yet implemented' @@ -322,7 +330,8 @@ cache[h]=oid, v return v - def objectCount(self): return len(self._storage) + def objectCount(self): + return len(self._storage) def open(self, version='', transaction=None, temporary=0, force=None, waitflag=1): @@ -361,9 +370,7 @@ # a one-use connection. c=self.klass( version=version, - cache_size=self._version_cache_size, - cache_deactivate_after= - self._version_cache_deactivate_after) + cache_size=self._version_cache_size) c._setDB(self) self._temps.append(c) if transaction is not None: transaction[id(c)]=c @@ -412,17 +419,13 @@ if self._version_pool_size > len(allocated) or force: c=self.klass( version=version, - cache_size=self._version_cache_size, - cache_deactivate_after= - self._version_cache_deactivate_after) + cache_size=self._version_cache_size) allocated.append(c) pool.append(c) elif self._pool_size > len(allocated) or force: c=self.klass( version=version, - cache_size=self._cache_size, - cache_deactivate_after= - self._cache_deactivate_after) + cache_size=self._cache_size) allocated.append(c) pool.append(c) @@ -492,19 +495,26 @@ raise def setCacheDeactivateAfter(self, v): - self._cache_deactivate_after=v - for c in self._pools[0][''][1]: - c._cache.cache_age=v + self._cache_deactivate_after = v + d = self._pools[0] + pool_info = d.get('') + if pool_info is not None: + for c in pool_info[1]: + c._cache.cache_age = v def setCacheSize(self, v): - self._cache_size=v - for c in self._pools[0][''][1]: - c._cache.cache_size=v + self._cache_size = v + d = self._pools[0] + pool_info = d.get('') + if pool_info is not None: + for c in pool_info[1]: + c._cache.cache_size = v def setClassFactory(self, factory): - self._classFactory=factory + self._classFactory = factory - def setPoolSize(self, v): self._pool_size=v + def setPoolSize(self, v): + self._pool_size=v def setVersionCacheDeactivateAfter(self, v): self._version_cache_deactivate_after=v === StandaloneZODB/ZODB/cPersistence.c 1.58 => 1.59 === if (*name == '_' && name[1] == 'p' && name[2] == '_') { - if (name[3] == 'o' && name[4] == 'i' && name[5] == 'd' && ! name[6]) { + if (strcmp(name + 3, "oid") == 0) { if (self->cache) { int result; if (v == NULL) { PyErr_SetString(PyExc_ValueError, - "can not delete the oid of a cached object"); + "can not delete oid of cached object"); return -1; } if (PyObject_Cmp(self->oid, v, &result) < 0) return -1; if (result) { PyErr_SetString(PyExc_ValueError, - "can not change the oid of a cached object"); + "can not change oid of cached object"); return -1; } } @@ -592,32 +592,41 @@ ASSIGN(self->oid, v); return 0; } - if (name[3]=='j' && name[4]=='a' && name[5]=='r' && ! name[6]) - { + else if (strcmp(name + 3, "jar") == 0) { + if (self->cache && self->jar) { + int result; + if (v == NULL) { + PyErr_SetString(PyExc_ValueError, + "can not delete jar of cached object"); + return -1; + } + if (PyObject_Cmp(self->jar, v, &result) < 0) + return -1; + if (result) { + PyErr_SetString(PyExc_ValueError, + "can not change jar of cached object"); + return -1; + } + } Py_XINCREF(v); ASSIGN(self->jar, v); return 0; - } - if (name[3]=='s' && strcmp(name+4,"erial")==0) - { - if (v) - { - if (PyString_Check(v) && PyString_Size(v)==8) - memcpy(self->serial, PyString_AS_STRING(v), 8); - else - { + } + else if (strcmp(name + 3, "serial") == 0) { + if (v) { + if (PyString_Check(v) && PyString_GET_SIZE(v) == 8) + memcpy(self->serial, PyString_AS_STRING(v), 8); + else { PyErr_SetString(PyExc_ValueError, "_p_serial must be an 8-character string"); return -1; - } - } - else - memset(self->serial, 0, 8); + } + } else + memset(self->serial, 0, 8); return 0; - } - if (name[3]=='c' && strcmp(name+4,"hanged")==0) - { - if (! v) + } + else if (strcmp(name+3, "changed") == 0) { + if (!v) { /* delatter is used to invalidate the object *even* if it has changed. === StandaloneZODB/ZODB/cPickleCache.c 1.57 => 1.58 === } ccobject; +#ifdef MUCH_RING_CHECKING static int present_in_ring(ccobject *self, CPersistentRing *target); +#endif static int ring_corrupt(ccobject *self, const char *context); static int cc_ass_sub(ccobject *self, PyObject *key, PyObject *v); @@ -214,7 +216,9 @@ static int scan_gc_items(ccobject *self,int target) { - /* This function must only be called with the ring lock held */ + /* This function must only be called with the ring lock held, + because it places a non-object placeholder in the ring. + */ cPersistentObject *object; int error; @@ -632,6 +636,19 @@ return 0; } +static PyObject * +cc_ringlen(ccobject *self, PyObject *args) +{ + CPersistentRing *here; + int c = 0; + + if (!PyArg_ParseTuple(args, ":ringlen")) + return NULL; + for (here = self->ring_home.next; here != &self->ring_home; + here = here->next) + c++; + return PyInt_FromLong(c); +} static struct PyMethodDef cc_methods[] = { {"lru_items", (PyCFunction)cc_lru_items, METH_VARARGS, @@ -658,6 +675,8 @@ "invalidate(oids) -- invalidate one, many, or all ids"}, {"get", (PyCFunction)cc_get, METH_VARARGS, "get(key [, default]) -- get an item, or a default"}, + {"ringlen", (PyCFunction)cc_ringlen, METH_VARARGS, + "ringlen() -- Returns number of non-ghost items in cache."}, {NULL, NULL} /* sentinel */ }; @@ -771,14 +790,14 @@ cPersistentObject *p; if (!PyExtensionInstance_Check(v)) { - PyErr_SetString(PyExc_ValueError, + PyErr_SetString(PyExc_TypeError, "Cache values must be persistent objects."); return -1; } class = (PyExtensionClass *)(v->ob_type); if (!((class->class_flags & PERSISTENT_TYPE_FLAG) && v->ob_type->tp_basicsize >= sizeof(cPersistentObject))) { - PyErr_SetString(PyExc_ValueError, + PyErr_SetString(PyExc_TypeError, "Cache values must be persistent objects."); /* Must be either persistent classes (ie ZClasses), or instances of persistent classes (ie Python classeses that derive from @@ -790,7 +809,6 @@ * persistent class. */ oid = PyObject_GetAttr(v, py__p_oid); - if (oid == NULL) return -1; /* XXX key and oid should both be PyString objects. @@ -806,6 +824,8 @@ return -1; } + /* XXX check that object has valid _p_jar? */ + object_again = object_from_oid(self, key); if (object_again) { if (object_again != v) { @@ -911,7 +931,7 @@ if (PyDict_DelItem(self->data, key) < 0) { PyErr_SetString(PyExc_RuntimeError, - "unexpectedly couldnt remove key in cc_ass_sub"); + "unexpectedly couldn't remove key in cc_ass_sub"); return -1; } @@ -958,7 +978,9 @@ if (here->next->prev != here) return 10; if (!self->ring_lock) { - /* if the ring must be locked then it only contains object other than persistent instances */ + /* If the ring must be locked, then it only contains + object other than persistent instances. + */ if (here != &self->ring_home) { cPersistentObject *object = object_from_ring(self, here, context); @@ -986,17 +1008,19 @@ ring_corrupt(ccobject *self, const char *context) { #ifdef MUCH_RING_CHECKING - int code = _ring_corrupt(self,context); + int code = _ring_corrupt(self, context); if (code) { - PyErr_Format(PyExc_RuntimeError, - "broken ring (code %d) in %s, size %d", - code, context, PyDict_Size(self->data)); + if (!PyErr_Occurred()) + PyErr_Format(PyExc_RuntimeError, + "broken ring (code %d) in %s, size %d", + code, context, PyDict_Size(self->data)); return code; } #endif return 0; } +#ifdef MUCH_RING_CHECKING static int present_in_ring(ccobject *self,CPersistentRing *target) { @@ -1009,6 +1033,7 @@ here = here->next; } } +#endif static PyMappingMethods cc_as_mapping = { (inquiry)cc_length, /*mp_length*/ @@ -1038,7 +1063,7 @@ }; static ccobject * -newccobject(PyObject *jar, int cache_size, int cache_age) +newccobject(PyObject *jar, int cache_size) { ccobject *self; @@ -1071,16 +1096,16 @@ static PyObject * cCM_new(PyObject *self, PyObject *args) { - int cache_size=100, cache_age=1000; + int cache_size=100; PyObject *jar; - if (!PyArg_ParseTuple(args, "O|ii", &jar, &cache_size, &cache_age)) + if (!PyArg_ParseTuple(args, "O|i", &jar, &cache_size)) return NULL; - return (PyObject*)newccobject(jar, cache_size, cache_age); + return (PyObject*)newccobject(jar, cache_size); } static struct PyMethodDef cCM_methods[] = { - {"PickleCache",(PyCFunction)cCM_new, METH_VARARGS, ""}, + {"PickleCache", (PyCFunction)cCM_new, METH_VARARGS, ""}, {NULL, NULL} /* sentinel */ }; From jeremy@zope.com Mon Apr 15 19:55:12 2002 From: jeremy@zope.com (Jeremy Hylton) Date: Mon, 15 Apr 2002 14:55:12 -0400 Subject: [Zope-Checkins] CVS: StandaloneZODB/ZODB/tests - testDB.py:1.1 testCache.py:1.2 testTransaction.py:1.7 Message-ID: <200204151855.g3FItC803787@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZODB/tests In directory cvs.zope.org:/tmp/cvs-serv3778 Modified Files: testCache.py testTransaction.py Added Files: testDB.py Log Message: Add a bunch more tests of the LRU cache mechanism and of DB methods. Also, reformat a test in testTransaction. === Added File StandaloneZODB/ZODB/tests/testDB.py === import time import unittest import ZODB import ZODB.MappingStorage from ZODB.tests.MinPO import MinPO class DBTests(unittest.TestCase): def setUp(self): store = ZODB.MappingStorage.MappingStorage() self.db = ZODB.DB(store) def tearDown(self): self.db.close() def dowork(self, version=''): c = self.db.open(version) r = c.root() o = r[time.time()] = MinPO(0) get_transaction().commit() for i in range(25): o.value = MinPO(i) get_transaction().commit() o = o.value print r.items() c.close() # make sure the basic methods are callable def testSets(self): # test set methods that have non-trivial implementations self.db.setCacheDeactivateAfter(12) # deprecated self.db.setCacheSize(15) self.db.setVersionCacheDeactivateAfter(12) # deprecated self.db.setVersionCacheSize(15) def test_suite(): return unittest.makeSuite(DBTests) === StandaloneZODB/ZODB/tests/testCache.py 1.1 => 1.2 === objects in memory under the assumption that they may be used again. """ +from __future__ import nested_scopes import random import time @@ -12,17 +13,20 @@ import ZODB import ZODB.MappingStorage +from ZODB.cPickleCache import PickleCache +from ZODB.POSException import ConflictError from ZODB.PersistentMapping import PersistentMapping from ZODB.tests.MinPO import MinPO from ZODB.utils import p64 +from Persistence import Persistent + class CacheTestBase(unittest.TestCase): def setUp(self): store = ZODB.MappingStorage.MappingStorage() self.db = ZODB.DB(store, - cache_size = self.CACHE_SIZE, - cache_deactivate_after = self.CACHE_DEACTIVATE_AFTER) + cache_size = self.CACHE_SIZE) self.conns = [] def tearDown(self): @@ -33,12 +37,12 @@ NUM_COLLECTIONS = 10 MAX_OBJECTS = 100 CACHE_SIZE = 20 - CACHE_DEACTIVATE_AFTER = 5 def noodle_new_connection(self): """Do some reads and writes on a new connection.""" c = self.db.open() + self.conns.append(c) self.noodle_connection(c) def noodle_connection(self, c): @@ -106,5 +110,180 @@ # XXX same for the get and invalidate methods + def checkLRUitems(self): + # get a cache + c = self.conns[0]._cache + c.lru_items() + + def checkClassItems(self): + c = self.conns[0]._cache + c.klass_items() + +class LRUCacheTests(CacheTestBase): + + def checkLRU(self): + # verify the LRU behavior of the cache + CACHE_SIZE = 5 + self.db.setCacheSize(CACHE_SIZE) + c = self.db.open() + r = c.root() + l = [None] * 10 + for i in range(10): + l[i] = r[i] = MinPO(i) + # the root is the only thing in the cache, because all the + # other objects are new + self.assertEqual(len(c._cache), 1) + get_transaction().commit() + # commit() will register the objects, placing them in the cache. + # at the end of commit, the cache will be reduced down to CACHE_SIZE + # items + self.assertEqual(c._cache.ringlen(), CACHE_SIZE) + x = c._cache.get(p64(0), None) + self.assertEqual(x._p_changed, None) # the root is ghosted + for i in range(len(l)): + if i < CACHE_SIZE: + self.assertEqual(l[i]._p_changed, None) + else: + self.assertEqual(l[i]._p_changed, 0) + + def checkSize(self): + self.assertEqual(self.db.cacheSize(), 0) + self.assertEqual(self.db.cacheDetailSize(), []) + + CACHE_SIZE = 10 + self.db.setCacheSize(CACHE_SIZE) + + CONNS = 3 + for i in range(CONNS): + self.noodle_new_connection() + + self.assertEquals(self.db.cacheSize(), CACHE_SIZE * CONNS) + details = self.db.cacheDetailSize() + self.assertEquals(len(details), CONNS) + for d in details: + self.assertEquals(d['ngsize'], CACHE_SIZE) + # the root is also in the cache as ghost, because + # the connection holds a reference to it + self.assertEquals(d['size'], CACHE_SIZE + 1) + + def checkDetail(self): + CACHE_SIZE = 10 + self.db.setCacheSize(CACHE_SIZE) + + CONNS = 3 + for i in range(CONNS): + self.noodle_new_connection() + + for klass, count in self.db.cacheDetail(): + if klass.endswith('PersistentMapping'): + # one root per connection + self.assertEqual(count, CONNS) + if klass.endswith('MinPO'): + self.assertEqual(count, CONNS * CACHE_SIZE) + + for details in self.db.cacheExtremeDetail(): + # one dict per object. keys: + if details['klass'].endswith('PersistentMapping'): + self.assertEqual(details['state'], None) + else: + self.assert_(details['klass'].endswith('MinPO')) + self.assertEqual(details['state'], 0) + +class StubDataManager: + def setklassstate(self, object): + pass + +class StubObject(Persistent): + pass + +class CacheErrors(unittest.TestCase): + + def setUp(self): + self.jar = StubDataManager() + self.cache = PickleCache(self.jar) + + def checkGetBogusKey(self): + self.assertRaises(KeyError, self.cache.get, p64(0)) + try: + self.cache[12] + except KeyError: + pass + else: + self.fail("expected KeyError") + try: + self.cache[12] = 12 + except TypeError: + pass + else: + self.fail("expected TyepError") + try: + del self.cache[12] + except TypeError: + pass + else: + self.fail("expected TypeError") + + def checkBogusObject(self): + def add(key, obj): + self.cache[key] = obj + + key = p64(2) + # value isn't persistent + self.assertRaises(TypeError, add, key, 12) + + o = StubObject() + # o._p_oid == None + self.assertRaises(ValueError, add, key, o) + + o._p_oid = key + # o._p_jar == None + self.assertRaises(Exception, add, key, o) + + o._p_jar = self.jar + self.cache[key] = o + # make sure it can be added multiple times + self.cache[key] = o + + # same object, different keys + self.assertRaises(ValueError, add, p64(0), o) + + def checkTwoCaches(self): + jar2 = StubDataManager() + cache2 = PickleCache(jar2) + + o = StubObject() + key = o._p_oid = p64(1) + o._p_jar = jar2 + + cache2[key] = o + + try: + self.cache[key] = o + except ValueError: + pass + else: + self.fail("expected ValueError because object already in cache") + + def checkReadOnlyAttrsWhenCached(self): + o = StubObject() + key = o._p_oid = p64(1) + o._p_jar = self.jar + self.cache[key] = o + try: + o._p_oid = p64(2) + except ValueError: + pass + else: + self.fail("expect that you can't change oid of cached object") + try: + del o._p_jar + except ValueError: + pass + else: + self.fail("expect that you can't delete jar of cached object") + def test_suite(): - return unittest.makeSuite(DBMethods, 'check') + s = unittest.makeSuite(DBMethods, 'check') + s.addTest(unittest.makeSuite(LRUCacheTests, 'check')) + s.addTest(unittest.makeSuite(CacheErrors, 'check')) + return s === StandaloneZODB/ZODB/tests/testTransaction.py 1.6 => 1.7 === def modify(self, nojar=0, tracing=0): - if not nojar: - if self.nost: self._p_jar = NoSubTransactionJar(tracing=tracing) - else: self._p_jar = SubTransactionJar(tracing=tracing) - - else: pass - get_transaction().register(self) - - -class TestTxnException(Exception): pass +class TestTxnException(Exception): + pass class BasicJar: From andreas@digicool.com Mon Apr 15 20:00:45 2002 From: andreas@digicool.com (Andreas Jung) Date: Mon, 15 Apr 2002 15:00:45 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/PluginIndexes/TopicIndex - TopicIndex.py:1.4 Message-ID: <200204151900.g3FJ0jb06104@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/PluginIndexes/TopicIndex In directory cvs.zope.org:/tmp/cvs-serv6097/TopicIndex Modified Files: TopicIndex.py Log Message: split overlong lines === Zope/lib/python/Products/PluginIndexes/TopicIndex/TopicIndex.py 1.3 => 1.4 === if RESPONSE: - RESPONSE.redirect(URL1+'/manage_workspace?manage_tabs_message=FilteredSet%20added') + RESPONSE.redirect(URL1+'/manage_workspace?' + 'manage_tabs_message=FilteredSet%20added') def manage_delFilteredSet(self, filterIds=[], URL1=None, \ @@ -191,7 +192,8 @@ self.delFilteredSet(filterId) if RESPONSE: - RESPONSE.redirect(URL1+'/manage_workspace?manage_tabs_message=FilteredSet(s)%20deleted') + RESPONSE.redirect(URL1+'/manage_workspace?' + 'manage_tabs_message=FilteredSet(s)%20deleted') def manage_saveFilteredSet(self,filterId, expr, URL1=None,\ @@ -201,7 +203,8 @@ self.filteredSets[filterId].setExpression(expr) if RESPONSE: - RESPONSE.redirect(URL1+'/manage_workspace?manage_tabs_message=FilteredSet(s)%20updated') + RESPONSE.redirect(URL1+'/manage_workspace?' + 'manage_tabs_message=FilteredSet(s)%20updated') def manage_clearFilteredSet(self, filterIds=[], URL1=None, \ @@ -212,7 +215,8 @@ self.clearFilteredSet(filterId) if RESPONSE: - RESPONSE.redirect(URL1+'/manage_workspace?manage_tabs_message=FilteredSet(s)%20cleared') + RESPONSE.redirect(URL1+'/manage_workspace?' + 'manage_tabs_message=FilteredSet(s)%20cleared') editFilteredSet = DTMLFile('dtml/editFilteredSet',globals()) From jeremy@zope.com Mon Apr 15 20:12:15 2002 From: jeremy@zope.com (Jeremy Hylton) Date: Mon, 15 Apr 2002 15:12:15 -0400 Subject: [Zope-Checkins] CVS: StandaloneZODB/ZODB - cPickleCache.c:1.59 Message-ID: <200204151912.g3FJCF009624@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZODB In directory cvs.zope.org:/tmp/cvs-serv9617 Modified Files: cPickleCache.c Log Message: Turn off MUCH_RING_CHECKING. I think it's safe to run this code without extra checking. === StandaloneZODB/ZODB/cPickleCache.c 1.58 => 1.59 === that it uses to report problems. */ -#define MUCH_RING_CHECKING 1 +#define MUCH_RING_CHECKING 0 /* Do we want 'engine noise'.... abstract debugging output useful for visualizing cache behavior */ From brian@zope.com Mon Apr 15 21:55:11 2002 From: brian@zope.com (Brian Lloyd) Date: Mon, 15 Apr 2002 16:55:11 -0400 Subject: [Zope-Checkins] CVS: Zope/ZServer - FCGIServer.py:1.13.16.2 HTTPResponse.py:1.36.16.1 PCGIServer.py:1.21.16.2 Message-ID: <200204152055.g3FKtBX06156@cvs.baymountain.com> Update of /cvs-repository/Zope/ZServer In directory cvs.zope.org:/tmp/cvs-serv6091 Modified Files: Tag: Zope-2_5-branch FCGIServer.py HTTPResponse.py PCGIServer.py Log Message: Fixes for Hotfix issue. === Zope/ZServer/FCGIServer.py 1.13.16.1 => 1.13.16.2 === self.stderr.close() - # The following was adapted from PCGIPipe.finish and PCGIPipe.close - # I don't really understand it enough to know if I got it right... - shutdown = 0 - if self.headers.get('bobo-exception-type','') == \ - 'exceptions.SystemExit': - r = self.headers.get('bobo-exception-value','0') - try: r=string.atoi(r) - except: r = r and 1 or 0 - shutdown = r, - if not self.channel.closed: self.channel.push_with_producer(LoggingProducer(self.channel, self.stdout.length, 'log_request'), 0) - if shutdown: - sys.ZServerExitCode = shutdown[0] + if self._shutdownRequested(): self.channel.push(ShutdownProducer(), 0) Wakeup(lambda: asyncore.close_all()) else: === Zope/ZServer/HTTPResponse.py 1.36 => 1.36.16.1 === lambda t=('E', id(self._request)): apply(DebugLogger.log, t)), 0) if self._shutdown: - try: r=self._shutdown[0] - except: r=0 - sys.ZServerExitCode=r self._channel.push(ShutdownProducer(), 0) Wakeup() else: @@ -270,9 +267,6 @@ DebugLogger.log('E', id(self._request)) if self._shutdown: - try: r=self._shutdown[0] - except: r=0 - sys.ZServerExitCode=r Wakeup(lambda: asyncore.close_all()) else: Wakeup() @@ -283,13 +277,8 @@ def flush(self): pass # yeah, whatever def finish(self, response): - if response.headers.get('bobo-exception-type', '') == \ - 'exceptions.SystemExit': - - r=response.headers.get('bobo-exception-value','0') - try: r=int(r) - except: r = r and 1 or 0 - self._shutdown=r, + if response._shutdownRequested(): + self._shutdown = 1 if response.headers.get('connection','') == 'close' or \ response.headers.get('Connection','') == 'close': self._close=1 === Zope/ZServer/PCGIServer.py 1.21.16.1 => 1.21.16.2 === def finish(self, response): - if response.headers.get('bobo-exception-type','') == \ - 'exceptions.SystemExit': - r=response.headers.get('bobo-exception-value','0') - try: r=string.atoi(r) - except: r = r and 1 or 0 - self._shutdown=r, + if response._shutdownRequested(): + self._shutdown = 1 self._channel.reply_code=response.status From brian@zope.com Mon Apr 15 21:55:28 2002 From: brian@zope.com (Brian Lloyd) Date: Mon, 15 Apr 2002 16:55:28 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/ZPublisher - HTTPResponse.py:1.53.8.2 Publish.py:1.155.8.1 Message-ID: <200204152055.g3FKtS506171@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/ZPublisher In directory cvs.zope.org:/tmp/cvs-serv6163 Modified Files: Tag: Zope-2_5-branch HTTPResponse.py Publish.py Log Message: Fixes for hotfix issue. === Zope/lib/python/ZPublisher/HTTPResponse.py 1.53.8.1 => 1.53.8.2 === return self.__class__(stdout=self.stdout, stderr=self.stderr) + + _shutdown_flag = None + def _requestShutdown(self, exitCode=0): + """Request that the server shut down with exitCode after fulfilling + the current request.""" + sys.ZServerExitCode = exitCode + self._shutdown_flag = 1 + + def _shutdownRequested(self): + """Returns true if this request requested a server shutdown.""" + return self._shutdown_flag is not None def setStatus(self, status, reason=None): '''\ === Zope/lib/python/ZPublisher/Publish.py 1.155 => 1.155.8.1 === if must_die: + # Try to turn exception value into an exit code. + try: + if hasattr(must_die[1], 'code'): + code = must_die[1].code + else: code = int(must_die[1]) + except: + code = must_die[1] and 1 or 0 + if hasattr(request.response, '_requestShutdown'): + request.response._requestShutdown(code) + try: raise must_die[0], must_die[1], must_die[2] finally: must_die=None From brian@zope.com Mon Apr 15 21:58:28 2002 From: brian@zope.com (Brian Lloyd) Date: Mon, 15 Apr 2002 16:58:28 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/ZPublisher - HTTPResponse.py:1.60 Publish.py:1.156 Message-ID: <200204152058.g3FKwS507296@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/ZPublisher In directory cvs.zope.org:/tmp/cvs-serv7288 Modified Files: HTTPResponse.py Publish.py Log Message: Fixed hotfix issues === Zope/lib/python/ZPublisher/HTTPResponse.py 1.59 => 1.60 === return self.__class__(stdout=self.stdout, stderr=self.stderr) - + + _shutdown_flag = None + def _requestShutdown(self, exitCode=0): + """Request that the server shut down with exitCode after fulfilling + the current request.""" + sys.ZServerExitCode = exitCode + self._shutdown_flag = 1 + + def _shutdownRequested(self): + """Returns true if this request requested a server shutdown.""" + return self._shutdown_flag is not None + def setStatus(self, status, reason=None): '''\ Sets the HTTP status code of the response; the argument may === Zope/lib/python/ZPublisher/Publish.py 1.155 => 1.156 === if must_die: + # Try to turn exception value into an exit code. + try: + if hasattr(must_die[1], 'code'): + code = must_die[1].code + else: code = int(must_die[1]) + except: + code = must_die[1] and 1 or 0 + if hasattr(request.response, '_requestShutdown'): + request.response._requestShutdown(code) + try: raise must_die[0], must_die[1], must_die[2] finally: must_die=None From brian@zope.com Mon Apr 15 21:58:48 2002 From: brian@zope.com (Brian Lloyd) Date: Mon, 15 Apr 2002 16:58:48 -0400 Subject: [Zope-Checkins] CVS: Zope/ZServer - FCGIServer.py:1.17 HTTPResponse.py:1.40 PCGIServer.py:1.23 Message-ID: <200204152058.g3FKwmW07318@cvs.baymountain.com> Update of /cvs-repository/Zope/ZServer In directory cvs.zope.org:/tmp/cvs-serv7309 Modified Files: FCGIServer.py HTTPResponse.py PCGIServer.py Log Message: Fixes for hotfix issues === Zope/ZServer/FCGIServer.py 1.16 => 1.17 === self.stderr.close() - # The following was adapted from PCGIPipe.finish and PCGIPipe.close - # I don't really understand it enough to know if I got it right... - shutdown = 0 - if self.headers.get('bobo-exception-type','') == \ - 'exceptions.SystemExit': - r = self.headers.get('bobo-exception-value','0') - try: r=string.atoi(r) - except: r = r and 1 or 0 - shutdown = r, - if not self.channel.closed: self.channel.push_with_producer(LoggingProducer(self.channel, self.stdout.length, 'log_request'), 0) - if shutdown: - sys.ZServerExitCode = shutdown[0] + if self._shutdownRequested(): self.channel.push(ShutdownProducer(), 0) Wakeup(lambda: asyncore.close_all()) else: === Zope/ZServer/HTTPResponse.py 1.39 => 1.40 === lambda t=('E', id(self._request)): apply(DebugLogger.log, t)), 0) if self._shutdown: - try: r=self._shutdown[0] - except: r=0 - sys.ZServerExitCode=r self._channel.push(ShutdownProducer(), 0) Wakeup() else: @@ -272,9 +269,6 @@ DebugLogger.log('E', id(self._request)) if self._shutdown: - try: r=self._shutdown[0] - except: r=0 - sys.ZServerExitCode=r Wakeup(lambda: asyncore.close_all()) else: Wakeup() @@ -285,13 +279,8 @@ def flush(self): pass # yeah, whatever def finish(self, response): - if response.headers.get('bobo-exception-type', '') == \ - 'exceptions.SystemExit': - - r=response.headers.get('bobo-exception-value','0') - try: r=int(r) - except: r = r and 1 or 0 - self._shutdown=r, + if response._shutdownRequested(): + self._shutdown = 1 if response.headers.get('connection','') == 'close' or \ response.headers.get('Connection','') == 'close': self._close=1 === Zope/ZServer/PCGIServer.py 1.22 => 1.23 === def finish(self, response): - if response.headers.get('bobo-exception-type','') == \ - 'exceptions.SystemExit': - r=response.headers.get('bobo-exception-value','0') - try: r=string.atoi(r) - except: r = r and 1 or 0 - self._shutdown=r, + if response._shutdownRequested(): + self._shutdown = 1 self._channel.reply_code=response.status From brian@zope.com Mon Apr 15 22:00:36 2002 From: brian@zope.com (Brian Lloyd) Date: Mon, 15 Apr 2002 17:00:36 -0400 Subject: [Zope-Checkins] CVS: Zope/doc - CHANGES.txt:1.406.2.51 Message-ID: <200204152100.g3FL0at07532@cvs.baymountain.com> Update of /cvs-repository/Zope/doc In directory cvs.zope.org:/tmp/cvs-serv7525 Modified Files: Tag: Zope-2_5-branch CHANGES.txt Log Message: updated === Zope/doc/CHANGES.txt 1.406.2.50 => 1.406.2.51 === Bugs Fixed + - A fix for the issue addressed by Hotfix 2002-04-15 was + incorporated into the core. + - Fixed table regex parsing bug in ClassicStructuredText thanks to Albert Ting via Zope maillist. From matt@zope.com Mon Apr 15 23:22:31 2002 From: matt@zope.com (Matthew T. Kromer) Date: Mon, 15 Apr 2002 18:22:31 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - ObjectManager.py:1.137.4.9 Message-ID: <200204152222.g3FMMVI28880@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv28873 Modified Files: Tag: Zope-2_4-branch ObjectManager.py Log Message: Remove tabs === Zope/lib/python/OFS/ObjectManager.py 1.137.4.8 => 1.137.4.9 === if hasattr(obj,'aq_parent'): - obj=obj.aq_parent - relativePhysicalPath = ('..',) + relativePhysicalPath + obj=obj.aq_parent + relativePhysicalPath = ('..',) + relativePhysicalPath else: - return vals + return vals x=x+1 return vals From matt@zope.com Mon Apr 15 23:37:49 2002 From: matt@zope.com (Matthew T. Kromer) Date: Mon, 15 Apr 2002 18:37:49 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/OFS - ObjectManager.py:1.145.16.3 Message-ID: <200204152237.g3FMbnQ32722@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/OFS In directory cvs.zope.org:/tmp/cvs-serv32715 Modified Files: Tag: Zope-2_5-branch ObjectManager.py Log Message: Remove tabs! === Zope/lib/python/OFS/ObjectManager.py 1.145.16.2 => 1.145.16.3 === if hasattr(obj,'aq_parent'): - obj=obj.aq_parent - relativePhysicalPath = ('..',) + relativePhysicalPath + obj=obj.aq_parent + relativePhysicalPath = ('..',) + relativePhysicalPath else: - return vals + return vals x=x+1 return vals From tdickenson@geminidataloggers.com Tue Apr 16 07:26:44 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Tue, 16 Apr 2002 02:26:44 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/ZODB - cPickleCache.c:1.60 Message-ID: <200204160626.g3G6QiW26380@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/ZODB In directory cvs.zope.org:/tmp/cvs-serv26372/lib/python/ZODB Modified Files: cPickleCache.c Log Message: really turn off MUCH_RING_CHECKING === Zope/lib/python/ZODB/cPickleCache.c 1.59 => 1.60 === that it uses to report problems. */ -#define MUCH_RING_CHECKING 0 + +/* #define MUCH_RING_CHECKING 1 */ /* Do we want 'engine noise'.... abstract debugging output useful for visualizing cache behavior */ From fdrake@acm.org Tue Apr 16 18:49:40 2002 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Tue, 16 Apr 2002 13:49:40 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/TAL/tests - test_xmlparser.py:1.6 utils.py:1.5 Message-ID: <200204161749.g3GHned31419@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/TAL/tests In directory cvs.zope.org:/tmp/cvs-serv31411 Modified Files: test_xmlparser.py utils.py Log Message: Be more flexible about which versions of Expat / pyexpat are supported. I *think* this fixes the misleading test failure on Windows Python 2.1.*. === Zope/lib/python/TAL/tests/test_xmlparser.py 1.5 => 1.6 === else: parser.parseString(source) - self.assertEquals(parser.get_events(),events) + if utils.oldexpat: + while events[0][0] in ('decl', 'doctype'): + del events[0] + self.assertEquals(parser.get_events(), events) def _run_check_extra(self, source, events): self._run_check(source, events, EventCollectorExtra) === Zope/lib/python/TAL/tests/utils.py 1.4 => 1.5 === # Set skipxml to true if an XML parser could not be found. +pyexpat = None skipxml = 0 try: import pyexpat @@ -22,6 +23,23 @@ import xml.parsers.pyexpat except ImportError: skipxml = 1 + else: + pyexpat = xml.parsers.pyexpat + + +# Set oldexpat if the StartDoctypeDeclHandler and XmlDeclHandler are +# not supported. The tests need to know whether the events reported +# by those handlers should be expected, but need to make sure the +# right thing is returned if they are. +oldexpat = 0 +if pyexpat is not None: + p = pyexpat.ParserCreate() + # Can't use hasattr() since pyexpat supports the handler + # attributes in a broken way. + try: + p.StartDoctypeDeclHandler = None + except AttributeError: + oldexpat = 1 def run_suite(suite, outf=None, errf=None): From matt@zope.com Tue Apr 16 19:05:56 2002 From: matt@zope.com (Matthew T. Kromer) Date: Tue, 16 Apr 2002 14:05:56 -0400 Subject: [Zope-Checkins] CVS: Products/DCOracle2/doc - DCOracle2.pdf:1.1 DCOracle2.aw:NONE DCOracle2.aw.ps:NONE DCOracle2.html:NONE DCOracle2.rtf:NONE Message-ID: <200204161805.g3GI5uJ03016@cvs.baymountain.com> Update of /cvs-repository/Products/DCOracle2/doc In directory cvs.zope.org:/tmp/cvs-serv2962 Added Files: DCOracle2.pdf Removed Files: DCOracle2.aw DCOracle2.aw.ps DCOracle2.html DCOracle2.rtf Log Message: Updated base docs (put in PDF conversion, took out html, postscript, and rtf) === Added File Products/DCOracle2/doc/DCOracle2.pdf === (654/754 lines abridged) %PDF-1.2 %Çì¢ 4 0 obj <> stream xœ¥XÝrÛ¸¾×SàªÝíØXüÛ+Z¢mÎÊ’CRI3³7ŠD'ìXR–¢“É#õ úz=ŒèL3%ÙÏÏw¾óCL1?î}w˜ý9{¿ïfæÏ¼ª˜ô<“”?›ŸfÇÙŸˆZ þmw@7åì·\"ªQù4#˜PÁ‰–¨ÜÍ:/Q!±”)°pîðËb¾n¶»çŠ¡Í¹jþzFw/õ¾BAyõT5ÕqWýZþ ì*D™³KkêŸZôoÄ!Wæ•¢Eý±n·ÏhÞTÛ¶>ÏÆXZ¢7?‰ÁJÄ„¡E=SpE8˜3$¤Š!D9d"PSÍžþö“Æ;t›¯Ö$ÄŽEJsp–ŒÃ/7U»… yõ\mÏUŸ2A¯»€²KãâÚÔ ƒnàB1$I„ãˆóËlž®Šô²®œRÆí]3† àµÉ«}}n›úË)Ú÷èå\¡úˆÎ§—fWÙÿ|¨Ûæz:5‡óúZ·ŸÐ©±ï§—Nûú©ÞÙ^¡mS!Ï sM©ó9ðásÕê¶­öèssúŒÜ£öÓ¶…— |+T<üç2è˜XPa‘ÓÜEîgtzòIïNÐ&‡—s œi·† mûáôÅ\òd>žÚzW]ÁµúŒžÁ’1àS'QÄ(å>w¥¶‘ Y]Yhaˆb÷¼­¡:: ÎøÙ^C× ¸EÙ+ùÒ˜+Æ”.¤Ö§ %Ù¿?1À« ÿ‡„‡"©;”÷§ÝË¡:¶[ÏÇ߀j'¸Ò Ã¶­šzû|¦•Šå%Á<­,UÄ}æÿ®ŒÅŒ©×UUÛðŒŸãöPP.´ °NXªÕíÙp¼ ëÔœ!½oèCeÚo?$¨(!êÔö„ªãnªL#Bº‡S[¡®t`v0}+Op¡+ÖùôÔ~5mä›öü¹Ú™®…›j0Ñû£ UüЯé×#²{>{¯»A¤#ÚcÇÖÊbWÞgò§L&h?sŒs hZäŠõmù.ÉÓþcÝRGZtÇ;0ä"jç •8vfóõÛl‘.†SQ¬™¥¢„aäÍܼÂUF±ì®.²»¬L–ƒ ëŽÎÃL9WóžNùŒ€Ry²*³´¸ (Á¤Yžv3cÅuWóåf‘­î®F…ÂTùРNCôÌÅ]Aûš¯ÖÁá3ëïZXÈ"¿™-icú!+ƒDŒÉ¨k< ›ò¸•멸X„…gQyŸNac!ôk˜q¡,ù#Ž»ÀltB;:2ËTW¡Û‘·nåƒm¢¯ôCšÏïÁPr“-³òý¹(Õ`|Š\`+‡ªÜ•è6+W#î è_Ã.„9ôw U·!‰úΈ±§P2\åD©nBvýÕ‰I’—Ù|³LòòÜf ëdÜ«Î&\éDoH¨ —¸‘ºÁ€”–nSqÂSÌ—Iö.0à‚VU¶U5·«cëT’HzŽ£f¾>¾7Ò·é* )¸Ñ„ÀDºCÅ}²”°Kà±Oëuµ¼ ©\Œjr©šAø °úBÕdrÀóB5Çzyx“9PKåôDúb/³äf™NQKĘûJO)§€b€}¤€p‰Çœ÷ã%OçeÐÍ1uZÚÆ}/ΞJ§#ðÉCrâ3!Ø6qãxœøtvÏ—Wt›)ìGú+² ’A¼ÈþH­)&^iGjM< `*{q„Ee¾ÉÓß‚#•–2kêÔ=¶02ˆz±¹)ʬܔioˆÁ1*]Gõ¼»[¯“m'4ž¾ßK¦ê`F;`‘æoáá²øÇðŒI·0À¼ñ’¾\3öBM hÁÝ&¦=6Eò¹ï8>`½HÊd’¤‚ ;")X郂P:¬Ž0_\Nßo&dHj„,Éñ÷†n6E6S°îvû›Œì÷2®ÁË4Ï7F ÿø5ÈQ¸aÙÖj€üýúÈv†Ãv2,‚(CýƒôØGø­¹æ„ŽóðÑa—(·ù–D±Ö1«_ÐÔOWÓüã:»EÉâmfä4i¦[dn¥‡›ù=êF6¾µý/csâendstream endobj 5 0 obj 2177 endobj 3 0 obj << /Type /Page /MediaBox [0 0 612 792] /Parent 2 0 R /Resources << /ProcSet [/PDF /Text] /Font << /R9 9 0 R /R7 7 0 R /R6 6 0 R >> >> /Contents 4 0 R >> endobj 11 0 obj <> stream xœWkO#9ýž_ai¥…YSïÇHófšz›¡YVB"NÅIÜS¯¶]Ió“ö_î±]U)==BP¾¾ÏsϽåQŸxæ§ÿ,ªÙ—ÙïøýB|û|ø(*òîav~Ÿ? ë™G=/̲<ÂÅÌ]öI4‡@š4‹ÈCuzuùQ²¢äùâòD‘_:±âäŸäž¯¹äuÁxølõf½Z?J’43Zç~ìYuó4 i@áêô–)MºvÅ4'檹‡a”šQD/ƒ+üµ«9‰ÏHày~/èåY–9I? i&NôÓzË÷ä’ßdSq9Ê'Ò7òÑ8œüÛŒ'П;šÁpêáÔ*ˆh”„yo4ëãû¾OýþÜχÓ0ô#{:âœz)’‘Ó—#wÙ´ÏRl¶šüÏÄé¹hÉ•ØÍJr)9Ó¢©%eI¬¤"’£;¾"ükÁ[Mô¶Qœl$«5Š8Q¼07Ébq{syýïO×ôäÄU*!ð²G@žå^`kå‘$ ©Ÿ[·þ~Ñ` Ò$ʧjy¡Uõ°Ьš¢«x­ÉŠ«BŠ%WÖÇ“¢éi–Ÿá­"¬6îk.׬0"•:8³õJÔ›Iò½ LÓ¤7êc(Œº @äÇËR°²TdÝHr÷ŒTÕ”LTÂ9Ö?'{ÉÚ–KÂdÓÁF.G‹ÆÜÜØóò(òóc‹Æ’¿X¬Š&89!û­(¶¤•͉Sƒ…«wäâî† 9dÝÕ¶@¬ú™¾¬ÌÜ'ðÃÞN˜Ó4²Ýã4¼Ì¾u,Œ²(?Nÿ…¶9Ô¢â&mÚTc/…FPgöäà™ñÊx·gÈÉŽ‰’-‘ÃÆÁiÏ—„i›‡ëòûÌÑ…Ü|—g\ÖüDãO™Ç)LúªÓ­Öíççûýž¶®Hܜ릅:U°%Süüªÿ/çð–nuUŽÒûÃúUáoš)g‰¼ün¾lguïÿý/ðGÌb ígù€?ÏRÈÅ1º XÍÐó>Eò‡'åìÓß"Xx‚ó£iÜPG}«n €|08wàP+ׯC/ \içaÙÛä5ëµ(ÈbìSèág„•Hh·ÙNP¿5%&uW-wHó¯š×ÊíÁ±¹Ò4ƒ#¬C!—5ˆiÇ=æ”, Â(8Bîl@QUeÚi/ôÄc.ñÒ0ÏÇ.; ù‡ÜI$­ÓªL#¯™å3QZ2C”HäžÉ%?³J”\£Ÿe}Èöj¤o„ªZ^äײ°±Ñ)¾îÊ3²ì4QHk¹"u£É’ƒ•¿tB‚@[:øHqc A¥4ÍÍÜ@‚Ú߈¨ê0(EÕ6R¿âÁªYuhÍÇSpÚ–í8šT }hÛÑ&Z/ÍŽârÔZÑÇöx½²©-GV¶:>Þ_\Þ^?½ÿøázˆui‹ Éå½s?ZsqÅÑ‘¹)/MOѲ«9•b)a\y0eŠÕ3ÈMÄPdÎ$väe? 3ïØpËPîÇÓÛ«§Û›w÷÷ÿ}º»xxoH­b5´<+Í+…4 DaÑÕÈÑèPÂ8¨j O,((AerQ4uíF®\.> startxref 44397 %%EOF === Removed File Products/DCOracle2/doc/DCOracle2.aw === === Removed File Products/DCOracle2/doc/DCOracle2.aw.ps === === Removed File Products/DCOracle2/doc/DCOracle2.html === === Removed File Products/DCOracle2/doc/DCOracle2.rtf === From matt@zope.com Tue Apr 16 19:07:08 2002 From: matt@zope.com (Matthew T. Kromer) Date: Tue, 16 Apr 2002 14:07:08 -0400 Subject: [Zope-Checkins] CVS: Products/DCOracle2/doc - DCOracle2.pdf:1.2 Message-ID: <200204161807.g3GI78q03976@cvs.baymountain.com> Update of /cvs-repository/Products/DCOracle2/doc In directory cvs.zope.org:/tmp/cvs-serv3891 Modified Files: DCOracle2.pdf Log Message: Oops, fix converted pdf === Products/DCOracle2/doc/DCOracle2.pdf 1.1 => 1.2 === From Anthony Baxter Wed Apr 17 08:44:02 2002 From: Anthony Baxter (Anthony Baxter) Date: Wed, 17 Apr 2002 17:44:02 +1000 Subject: [Zope-Checkins] CVS: Zope/ZServer - FCGIServer.py:1.13.16.2 HTTPResponse.py:1.36.16.1 PCGIServer.py:1.21.16.2 In-Reply-To: Message from Brian Lloyd of "Mon, 15 Apr 2002 16:55:11 -0400." <200204152055.g3FKtBX06156@cvs.baymountain.com> Message-ID: <200204170744.g3H7i2q24653@localhost.localdomain> >>> Brian Lloyd wrote > Update of /cvs-repository/Zope/ZServer > In directory cvs.zope.org:/tmp/cvs-serv6091 > > Modified Files: > Tag: Zope-2_5-branch > FCGIServer.py HTTPResponse.py PCGIServer.py > Log Message: > Fixes for Hotfix issue. as far as I can see, this didn't hit the 2.4 branch. Should it? Anthony -- Anthony Baxter It's never too late to have a happy childhood. From tdickenson@geminidataloggers.com Wed Apr 17 11:38:15 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Wed, 17 Apr 2002 06:38:15 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/ZCatalog - Catalog.py:1.83.14.1 Message-ID: <200204171038.g3HAcFv30942@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/ZCatalog In directory cvs.zope.org:/tmp/cvs-serv28601 Modified Files: Tag: toby-catalog-cmp-collision-branch Catalog.py Log Message: Optimisation for sorted catalog queries. What happens if two objects have the same value for the sort key? The order is arbitrary. The old implementation would sometimes determine the order by instanciating and comparing brains objects, which is slow. === Zope/lib/python/Products/ZCatalog/Catalog.py 1.83 => 1.83.14.1 === from Products.PluginIndexes.common.randid import randid -import time +import time, sys class Catalog(Persistent, Acquisition.Implicit, ExtensionClass.Base): """ An Object Catalog @@ -509,6 +509,13 @@ return used def _build_sorted_results(self,rs,sort_index,append): + # This function will .append pairs where the first item + # in the pair is a sort key, and the second item in the + # pair is a squence of results which share the same + # sort key. Later on the list to which these things + # are .append()ed will be .sort()ed, and the first element + # of each pair stripped. + # # The two 'for' loops in here contribute a significant # proportion of the time to perform an indexed search. # Try to avoid all non-local attribute lookup inside @@ -534,16 +541,28 @@ # Is this ever true? intset = keys() append((k,_lazymap(_self__getitem__, intset))) + # Note that sort keys are unique. else: if hasattr(rs, 'keys'): rs=rs.keys() _sort_index_keyForDocument = sort_index.keyForDocument _keyerror = KeyError for did in rs: try: - append((_sort_index_keyForDocument(did), - _lazymap(_self__getitem__,[did]))) + key = _sort_index_keyForDocument(did) except _keyerror: + # This document is not in the sort key index. + # skip it. pass + else: + # We want the sort keys to be unique so that + # .sort()ing the list does not involve comparing + # _lazymap objects, which is slow. To ensure + # uniqueness the first element of each pair is + # actually a tuple of: + # (real sort key, some unique number) + lm = _lazymap(_self__getitem__,[did]) + key = (key,id(lm)) + append((key,lm)) def searchResults(self, REQUEST=None, used=None, **kw): From tdickenson@geminidataloggers.com Wed Apr 17 11:39:28 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Wed, 17 Apr 2002 06:39:28 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/Products/ZCatalog - Catalog.py:1.84 Message-ID: <200204171039.g3HAdSJ31071@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/Products/ZCatalog In directory cvs.zope.org:/tmp/cvs-serv31063 Modified Files: Catalog.py Log Message: merged toby-catalog-cmp-collision-branch === Zope/lib/python/Products/ZCatalog/Catalog.py 1.83 => 1.84 === from Products.PluginIndexes.common.randid import randid -import time +import time, sys class Catalog(Persistent, Acquisition.Implicit, ExtensionClass.Base): """ An Object Catalog @@ -509,6 +509,13 @@ return used def _build_sorted_results(self,rs,sort_index,append): + # This function will .append pairs where the first item + # in the pair is a sort key, and the second item in the + # pair is a squence of results which share the same + # sort key. Later on the list to which these things + # are .append()ed will be .sort()ed, and the first element + # of each pair stripped. + # # The two 'for' loops in here contribute a significant # proportion of the time to perform an indexed search. # Try to avoid all non-local attribute lookup inside @@ -534,16 +541,28 @@ # Is this ever true? intset = keys() append((k,_lazymap(_self__getitem__, intset))) + # Note that sort keys are unique. else: if hasattr(rs, 'keys'): rs=rs.keys() _sort_index_keyForDocument = sort_index.keyForDocument _keyerror = KeyError for did in rs: try: - append((_sort_index_keyForDocument(did), - _lazymap(_self__getitem__,[did]))) + key = _sort_index_keyForDocument(did) except _keyerror: + # This document is not in the sort key index. + # skip it. pass + else: + # We want the sort keys to be unique so that + # .sort()ing the list does not involve comparing + # _lazymap objects, which is slow. To ensure + # uniqueness the first element of each pair is + # actually a tuple of: + # (real sort key, some unique number) + lm = _lazymap(_self__getitem__,[did]) + key = (key,id(lm)) + append((key,lm)) def searchResults(self, REQUEST=None, used=None, **kw): From tdickenson@geminidataloggers.com Wed Apr 17 12:39:32 2002 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Wed, 17 Apr 2002 07:39:32 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/App/dtml - cacheGC.dtml:1.5 Message-ID: <200204171139.g3HBdWw13894@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/App/dtml In directory cvs.zope.org:/tmp/cvs-serv13887/App/dtml Modified Files: cacheGC.dtml Log Message: changed wording to be less confusing, and more correct === Zope/lib/python/App/dtml/cacheGC.dtml 1.4 => 1.5 ===
- Remove all objects from the ZODB in-memory cache + Remove all objects from all ZODB in-memory caches
From brian@zope.com Wed Apr 17 15:25:11 2002 From: brian@zope.com (Brian Lloyd) Date: Wed, 17 Apr 2002 10:25:11 -0400 Subject: [Zope-Checkins] CVS: Zope/ZServer - PCGIServer.py:1.21.16.3 Message-ID: <200204171425.g3HEPBG26301@cvs.baymountain.com> Update of /cvs-repository/Zope/ZServer In directory cvs.zope.org:/tmp/cvs-serv26189 Modified Files: Tag: Zope-2_5-branch PCGIServer.py Log Message: Fixed bug in PCGIPipe shutdown code (nameerror). === Zope/ZServer/PCGIServer.py 1.21.16.2 => 1.21.16.3 === if self._shutdown: - try: r=self._shutdown[0] - except: r=0 - sys.ZServerExitCode=r self._channel.push(ShutdownProducer(), 0) Wakeup(lambda: asyncore.close_all()) else: From brian@zope.com Wed Apr 17 15:27:36 2002 From: brian@zope.com (Brian Lloyd) Date: Wed, 17 Apr 2002 10:27:36 -0400 Subject: [Zope-Checkins] CVS: Zope/lib/python/ZPublisher - HTTPResponse.py:1.46.20.3 Publish.py:1.150.32.1 Message-ID: <200204171427.g3HERa227314@cvs.baymountain.com> Update of /cvs-repository/Zope/lib/python/ZPublisher In directory cvs.zope.org:/tmp/cvs-serv27305 Modified Files: Tag: Zope-2_4-branch HTTPResponse.py Publish.py Log Message: Backported hotfix 04-15-02 === Zope/lib/python/ZPublisher/HTTPResponse.py 1.46.20.2 => 1.46.20.3 === return self.__class__(stdout=self.stdout, stderr=self.stderr) - + + _shutdown_flag = None + def _requestShutdown(self, exitCode=0): + """Request that the server shut down with exitCode after fulfilling + the current request.""" + sys.ZServerExitCode = exitCode + self._shutdown_flag = 1 + + def _shutdownRequested(self): + """Returns true if this request requested a server shutdown.""" + return self._shutdown_flag is not None + def setStatus(self, status, reason=None): '''\ Sets the HTTP status code of the response; the argument may === Zope/lib/python/ZPublisher/Publish.py 1.150 => 1.150.32.1 === if must_die: + # Try to turn exception value into an exit code. + try: + if hasattr(must_die[1], 'code'): + code = must_die[1].code + else: code = int(must_die[1]) + except: + code = must_die[1] and 1 or 0 + if hasattr(request.response, '_requestShutdown'): + request.response._requestShutdown(code) + try: raise must_die[0], must_die[1], must_die[2] finally: must_die=None From brian@zope.com Wed Apr 17 15:27:56 2002 From: brian@zope.com (Brian Lloyd) Date: Wed, 17 Apr 2002 10:27:56 -0400 Subject: [Zope-Checkins] CVS: Zope/ZServer - FCGIServer.py:1.12.32.2 HTTPResponse.py:1.32.16.3 PCGIServer.py:1.20.32.2 Message-ID: <200204171427.g3HERuu27334@cvs.baymountain.com> Update of /cvs-repository/Zope/ZServer In directory cvs.zope.org:/tmp/cvs-serv27321 Modified Files: Tag: Zope-2_4-branch FCGIServer.py HTTPResponse.py PCGIServer.py Log Message: Backported hotfix 04-15-02 === Zope/ZServer/FCGIServer.py 1.12.32.1 => 1.12.32.2 === self.stderr.close() - # The following was adapted from PCGIPipe.finish and PCGIPipe.close - # I don't really understand it enough to know if I got it right... - shutdown = 0 - if self.headers.get('bobo-exception-type','') == \ - 'exceptions.SystemExit': - r = self.headers.get('bobo-exception-value','0') - try: r=string.atoi(r) - except: r = r and 1 or 0 - shutdown = r, - if not self.channel.closed: self.channel.push_with_producer(LoggingProducer(self.channel, self.stdout.length, 'log_request'), 0) - if shutdown: - sys.ZServerExitCode = shutdown[0] + if self._shutdownRequested(): self.channel.push(ShutdownProducer(), 0) Wakeup(lambda: asyncore.close_all()) else: === Zope/ZServer/HTTPResponse.py 1.32.16.2 => 1.32.16.3 === lambda t=('E', id(self._request)): apply(DebugLogger.log, t)), 0) if self._shutdown: - try: r=self._shutdown[0] - except: r=0 - sys.ZServerExitCode=r self._channel.push(ShutdownProducer(), 0) Wakeup() else: @@ -343,9 +340,6 @@ DebugLogger.log('E', id(self._request)) if self._shutdown: - try: r=self._shutdown[0] - except: r=0 - sys.ZServerExitCode=r Wakeup(lambda: asyncore.close_all()) else: Wakeup() @@ -356,13 +350,8 @@ def flush(self): pass # yeah, whatever def finish(self, response): - if response.headers.get('bobo-exception-type', '') == \ - 'exceptions.SystemExit': - - r=response.headers.get('bobo-exception-value','0') - try: r=string.atoi(r) - except: r = r and 1 or 0 - self._shutdown=r, + if response._shutdownRequested(): + self._shutdown = 1 if response.headers.get('connection','') == 'close' or \ response.headers.get('Connection','') == 'close': self._close=1 === Zope/ZServer/PCGIServer.py 1.20.32.1 => 1.20.32.2 === if self._shutdown: - try: r=self._shutdown[0] - except: r=0 - sys.ZServerExitCode=r self._channel.push(ShutdownProducer(), 0) Wakeup(lambda: asyncore.close_all()) else: @@ -465,10 +462,6 @@ self._channel=None def finish(self, response): - if response.headers.get('bobo-exception-type','') == \ - 'exceptions.SystemExit': - r=response.headers.get('bobo-exception-value','0') - try: r=string.atoi(r) - except: r = r and 1 or 0 - self._shutdown=r, + if response._shutdownRequested(): + self._shutdown = 1 self._channel.reply_code=response.status From matt@zope.com Wed Apr 17 16:14:07 2002 From: matt@zope.com (Matthew T. Kromer) Date: Wed, 17 Apr 2002 11:14:07 -0400 Subject: [Zope-Checkins] CVS: Products/DCOracle2/doc - Implementation.pdf:1.1 Implementation.aw:1.2 Implementation.aw.ps:NONE Implementation.html:NONE Implementation.rtf:NONE Message-ID: <200204171514.g3HFE7506546@cvs.baymountain.com> Update of /cvs-repository/Products/DCOracle2/doc In directory cvs.zope.org:/tmp/cvs-serv6459 Modified Files: Implementation.aw Added Files: Implementation.pdf Removed Files: Implementation.aw.ps Implementation.html Implementation.rtf Log Message: Remove postscript, rtf, and html versions, add PDF version === Added File Products/DCOracle2/doc/Implementation.pdf === (500/600 lines abridged) %PDF-1.2 %Çì¢ 4 0 obj <> stream xœm“QoÓ0…ßó+îc+­®¯¯íؼ•2$ÄÛˆ@B} ©×’¦s¢òø—ØIWZ¢ÄNäã3ž®ÓXµÙsöï/Yzmã3·‚C“i×ó4Ùf»ìpØáe¨Zx]dóG ¤¡xÊ8ã\rnóŠ*1¤3VƒRši h'o–}Y5NL‹ïƒÊaiPÍÐ0ž ˜IWC±ž,á®<:‹ûwiy¡9ák;Ð81«MÔåñ³NÂG׸òàž8¨¤”ö #I¥1­_ì}Ýæ7 8#+çhB’£I†ÑÜLX6¢>”!l]ƒ÷¾k?#²RÄØñ¨BúHѺýÑ×›m€ß‰É2Ž|øÚí,;¿ï|ên÷oxA†Ì^³”%vM¦ÿ/¾L£¢3» ÆEò¥˜Ðƒú®|Š•‡à pÕv×5ÝæK· ƒiÎóSó9#%.c)$¸÷õ®rp»îK¿†OÁ;Î¥D¹ -XNÊÚKõ[ïÖÎ×Õ÷Ÿ~sŸ „äæåj‹tâ¥/•«‰1f5’r&‰¬&‡²q‡Õ4igƒmKVë±3¦ðÊö6„ý«ù¼ï{ö+ÖǪ®MºÛâAù#LÈØendstream endobj 5 0 obj 474 endobj 3 0 obj << /Type /Page /MediaBox [0 0 612 792] /Parent 2 0 R /Resources << /ProcSet [/PDF /Text] /Font << /R7 7 0 R /R6 6 0 R >> >> /Contents 4 0 R >> endobj 10 0 obj <> stream xœ¥X]oÛ:}ϯ îS $ ¿DJÝ'ÅQŽíJr{Säű•Fwc+•åd»lÿÞ)Q¢b¥¸ÀEѺ)Μ3gÎŒJ0EDÿj?×Û“Ÿ'_à÷ODÍÏíÇz‹.²“óD"*QöprF0¡TPÿZŸ4S¤’>ÃAÀP¶ý0'Ñ,>fÁƒ Q¦„ç§”qó AgŒaÂá«Í‡$ßûº*îuQîÐj·A‡}ŽŠÚ—‡j›ŸÜ»Uõ =”ÕvŠ^‹ú••ù,5Ú–›â¡X¯ô§hUåHG71îSÚÆ¤ûÔ1Ÿój[Ôu¾AÏUùRlà/õ㪆?rˆñôT¾»h]î6…¾soîDÛ¼þÔÀP.& >àò±b¾Žñ¿c ¢=KŽÑïQù`a¯ËM޶‡}ª¼^:¹Õ}ù¢¿zþU?k´+ëbŸÂwÅ=ÁMú žœ›`g:3*°ôMf=®SCî5ä³~Zۼ¿«k(p@Ù;X ¨ïý*@rÊj¡BA6€ÿ÷ÐZ¨BH)ñwÁ¢–áM¹>ló]½²j<¡•ðMÕ£D0ÿHTÛUWÅêiß‹ÊÕÜê ÿG´ áKA]Zg«mÝïËu±ªmÐïås®[Ä|NÊ깬D†f ÝçºÏ€å»MYíû®a’QL9p!`Û–uŽš:Õ{´Ð/pÏ|ÑTf_>Ô¯ºclîŸóµnPx¨Ðm[éÞÛuáÈ@Œ7é~¯“6w¿…òxäžDº<Þ Õ±NW»V¤¯àû25¼mÍ^T—'‰GÆd¹Zÿ{W¾>å›ZiŸzƒ·ŠÎI8”!âL³Ú鬟›Ü¡yù<9`“¿Ž y[CÕi~ïÒ#£>ãG¼ÏïÿÊ!Îâp-ö¨E»—¢*w:Yt÷á±®Ÿ?Ÿ¿¾¾âÿB0¼.·çwñlO*ϳEèPÄÐSký|•ŸÝ}§†XFpàµ}Ÿ/"'éÀ÷šÖXÒ&=™'‹yfñ|Öe$ð¥é€@`&Ú.g}F$`T“'pÄÞ5Ë’øb™Í“£YX·žlÈB µò5úz‡øF| I;Ú†­jåh3I(æ¤Mc‡Ä=D‡j+I±o„³[§F@¾=¡×s"ús‘D©# ¸G)SJɱîUslžô÷áûæpÏ–(¾YLc·ÔÒæãÁ)‹T•„³,ŽÒSGLR#l?ÀŠ‚Œš g“éò2ž}vNòÆ<”‡•M ÊäèGÅÛrzÌιsDAúÍh;‚9ý4oâÌÁ¡oô×Þ„òšÝ ðén6'.ãt2 ã›è£ž-hTå½á>žµ0Ðq6¦ÌZSÖ*£¯ÑÌÑ(Dñ)”“^‡Óé˜W Þëî=¯<2ËqJ2時ÀÃ96Ç3Á˜|Ï4‡ŽO ˆQ¶I^8)z”RµríLz‡ÓhL[BâÀöþ[Mu({ßNtæà[Â.ã$šdN;ÃRßx18Wg€ñìèøi»‘ âlµ`_0ú Ý¦Îœ·;g@1³ÚHÑ$vAC“¥"˜ÛøÑŸØE˜ÜžŽVŠëÅð¸RJ[4+° Ý¨„—×/KÈâ:a!;Þ:A í¨å'¼ ?ƒûŒ¶®ÿÆ·9†rÿÖ·™Â¶)Þ±mðPâw2yß®)&VM»&VЀÖ{`U™,“èÆváÀfX3F|VשyÓ…]¥sõty‘fq¶Ì¢þ]ŽQC¬ò1·6õy>¿»ÂÇÂn5o=S5´{ƒ0’¯ñ$JÿÕï½±Yý% Û Óy:2D`‰¢ÞÈ6 M°PX1,ÓÈÕs×q¼çú2ÌÂQ‘ sÀFD ·4À  ”öË# ˜ÓÛÍ„ô  qX;Þ^t±Lãᜂ•·Yߤ‡¥ì<‹’d¹Ðfx÷ÑÁ(ZŒ°ë s«Ãüõü8·“‡ƒvQî|{m½Fû‰ëæÍáx+í¡jÓîª3ˆ¡I‹ùxÌë´l¦´¾²6[É<¹=0ÚЕ¸¯(o¸b+_ôæl¶G R´=.!!»»\G°§§Ÿž`mrd|R¢àݿո4) ÆL˜pàÁà,ÍkÌfM!…94ÉÆ@€£Kw¼áJ,è;µ•˜m,h¾Æ…x¿ &ÙÀ¬âaßv]ºë­Ñ ( …m/úwa·|/GLtÞ½ë¹6Õ/ߤŸYƒå»oÕkd™F#1œ,ÝÝËô0†û&íÃ2Fè‡}v»DµËx‰Øw½ý9=@ítÕÍ?\¢ã+^~µ@‚&¬ºiÜîôð£t9¹FÍÈ6ÿeèËÉ—“ÿËò£Õendstream endobj 11 0 obj 2167 endobj 9 0 obj << /Type /Page /MediaBox [0 0 612 792] /Parent 2 0 R /Resources << /ProcSet [/PDF /Text] /Font << /R12 12 0 R /R7 7 0 R /R6 6 0 R >> [-=- -=- -=- 500 lines omitted -=- -=- -=-] 0000005085 00000 n 0000032372 00000 n 0000032293 00000 n 0000007070 00000 n 0000005290 00000 n 0000007049 00000 n 0000032208 00000 n 0000032127 00000 n 0000009227 00000 n 0000007266 00000 n 0000009206 00000 n 0000011292 00000 n 0000009423 00000 n 0000011271 00000 n 0000013484 00000 n 0000011488 00000 n 0000013463 00000 n 0000014358 00000 n 0000013680 00000 n 0000014338 00000 n 0000016269 00000 n 0000014542 00000 n 0000016248 00000 n 0000032051 00000 n 0000031968 00000 n 0000018189 00000 n 0000016465 00000 n 0000018168 00000 n 0000019851 00000 n 0000018373 00000 n 0000019830 00000 n 0000021433 00000 n 0000020023 00000 n 0000021412 00000 n 0000026739 00000 n 0000021641 00000 n 0000026718 00000 n 0000029714 00000 n 0000026899 00000 n 0000029693 00000 n 0000031808 00000 n 0000029864 00000 n 0000031787 00000 n 0000032943 00000 n trailer << /Size 59 /Root 1 0 R /Info 58 0 R >> startxref 33031 %%EOF === Products/DCOracle2/doc/Implementation.aw 1.1 => 1.2 === (608/708 lines abridged) - +