using System; using System.Collections; using System.Xml; using System.IO; namespace Repository { /// ///

Describes Repository archives.
/// Serialized in archives.xml. Named ArchiveRep in PHP version.

///

Copyright (c) 2002 Alexis Grandemange
/// Mail: alexis.grandemange@pagebox.net

///
This program is free software; you can redistribute it and/or
	/// modify it under the terms of the GNU Lesser General Public
	/// License as published by the Free Software Foundation; version
	/// 2.1 of the License.
	/// This library is distributed in the hope that it will be useful,
	/// but WITHOUT ANY WARRANTY; without even the implied warranty of
	/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
	/// GNU Lesser General Public License for more details.
	/// A copy of the GNU Lesser General Public License lesser.txt should be
	/// included in the distribution.
///
public class RepoArchs : Deployer { /// ///

Array of archives.
/// Key: archive name.
/// Value: archive publisher (owner).

///
public Hashtable archives = null; private Hashtable internalArchs = new Hashtable(); /// ///

Array of archive documentation URLs.
/// Key: archive name.
/// Value: archive documentation URL.

/// public Hashtable docs = null; public Hashtable internalDocs = new Hashtable(); /// /// Array of administrators. Administrators can see and unpublish any archive. /// They can also publish archives. /// Hashtable administrators = new Hashtable(); /// /// Array of publishers. Publishers can see and unpublish the archives that they have published. /// They can also publish archives. /// Hashtable publishers = new Hashtable(); /// /// This URL ../download /// string downloadURL; /// /// This directory ../download /// public string downloadPath; /// /// Subscriber repository. RepoSubsObj in PHP version. /// RepoSubs subRep; /// /// Creation of a new Archive repository. /// public RepoArchs() { archives = Hashtable.Synchronized(internalArchs); docs = Hashtable.Synchronized(internalDocs); } /// /// Restore administrators and publishers from authorization.xml. /// private void restoreAuth() { if (!File.Exists(Global.path + "\\authorization.xml")) return; XmlTextReader r = new XmlTextReader(Global.path + "\\authorization.xml"); r.WhitespaceHandling = WhitespaceHandling.None; r.ReadStartElement("authorization"); restoreHash(administrators, r, "administrators"); restoreHash(publishers, r, "publishers"); r.Close(); } /// /// Populate a Hashtable, either administrators or publishers. /// /// Hashtable to populate /// XML stream to read /// Element to process private void restoreHash(Hashtable h, XmlReader r, string elt) { r.ReadStartElement(elt); while (true) { if (r.NodeType == XmlNodeType.Element) { if (r.LocalName.Equals("user")) { string user = r.ReadElementString("user"); h.Add(user, true); } else return; } if ((r.NodeType == XmlNodeType.EndElement) && r.LocalName.Equals(elt)) break; if (r.NodeType == XmlNodeType.None) return; } r.ReadEndElement(); } /// /// Archive repository initialization. /// /// download URL /// Archive repository /// download path public void init(string du, RepoSubs rs, string dp) { downloadURL = du; subRep = rs; downloadPath = dp; restoreAuth(); } /// /// Unserialization of an existing Archive repository. /// /// XML stream to unserialize public RepoArchs(XmlReader r) { r.ReadStartElement("RepoArchs"); restoreHash2(internalArchs, r, "archives"); restoreHash2(internalDocs, r, "docs"); archives = Hashtable.Synchronized(internalArchs); docs = Hashtable.Synchronized(internalDocs); } /// /// Restore internalArchs or internalDocs. /// Invoked in the RepArchs constructor. /// /// Publisher table to restore /// XML stream to unserialize /// Element to process private void restoreHash2(Hashtable h, XmlReader r, string elt) { r.ReadStartElement(elt); while (true) { if (r.NodeType == XmlNodeType.Element) { if (r.LocalName.Equals("entry")) { r.Read(); string arch = r.ReadElementString("arch"); string val = r.ReadElementString("val"); // owner or doc URL h.Add(arch, val); } else return; } if ((r.NodeType == XmlNodeType.EndElement) && r.LocalName.Equals(elt)) break; if (r.NodeType == XmlNodeType.None) return; r.Read(); } r.ReadEndElement(); } /// /// Serializer. /// /// Stream where the Repository archives must be serialized public void WriteXml(XmlWriter w) { w.WriteStartElement("RepoArchs"); w.WriteStartElement("archives"); IDictionaryEnumerator ide = internalArchs.GetEnumerator(); while(ide.MoveNext()) { w.WriteStartElement("entry"); w.WriteElementString("arch", (string)ide.Key); w.WriteElementString("val", (string)ide.Value); w.WriteEndElement(); } w.WriteEndElement(); w.WriteStartElement("docs"); ide = internalDocs.GetEnumerator(); while(ide.MoveNext()) { w.WriteStartElement("entry"); w.WriteElementString("arch", (string)ide.Key); w.WriteElementString("val", (string)ide.Value); w.WriteEndElement(); } w.WriteEndElement(); w.WriteEndElement(); } /// /// Adds an archive to the repository. /// /// status /// user who issued the command /// host which issued the command /// archive name /// archive owner /// documentation URL public string add(string user, string host, string arch, string owner, string docURL) { lock(this) { string status = null; IDictionaryEnumerator ide = null; Subscriber sub = null; if (archives.Contains(arch)) { status = "'" + arch + "' updated"; ide = subRep.asubscribers.GetEnumerator(); while(ide.MoveNext()) { sub = (Subscriber)ide.Value; if (sub.state.Equals("pending unsubscribe")) continue; if (sub.archs.Contains(arch)) { string d = deploy(user, host, (string)ide.Key, arch, owner, docURL, downloadURL); if (d != null) { sub.archs[arch] = d; subRep.dirty = true; } } } if (docs.Contains(arch)) // Should be the case docs[arch] = docURL; else docs.Add(arch, docURL); } else { status = "'" + arch + "' created"; archives.Add(arch, owner); docs.Add(arch, docURL); Global.saveArchRep(); } ide = subRep.subscribers.GetEnumerator(); while(ide.MoveNext()) { sub = (Subscriber)ide.Value; if (sub.state.Equals("pending unsubscribe")) continue; string d = deploy(user, host, (string)ide.Key, arch, owner, docURL, downloadURL); if (d != null) { if (sub.archs.Contains(arch)) sub.archs[arch] = d; // Shouldn't happen else sub.archs.Add(arch, d); subRep.dirty = true; } } if (subRep.dirty) Global.saveSubRep(); return status; } } /// /// Remove an archive from the repository. /// /// status /// user who issued the command /// host which issued the command /// archive name /// isForce bool If true remove the archive from the subscriber even /// if the subscriber cannot be contacted public string delete(string user, string host, string arch, bool isForce) { lock(this) { if (!archives.Contains(arch)) return "'" + arch + "' doesn't exist"; delete(user, host, subRep.subscribers, arch, isForce); delete(user, host, subRep.asubscribers, arch, isForce); archives.Remove(arch); docs.Remove(arch); if (File.Exists(downloadPath + arch)) File.Delete(downloadPath + arch); Global.saveArchRep(); if (subRep.dirty) Global.saveSubRep(); return arch + " deleted"; } } /// /// Cleanup a subscriber list when an archive is removed. /// /// user who issued the command /// host which issued the command /// subscribers or asubscribers /// archive name /// If true remove the archive from the subscriber even /// if the subscriber cannot be contacted private void delete(string user, string host, Hashtable h, string arch, bool isForce) { Hashtable subs = (Hashtable)h.Clone(); IDictionaryEnumerator ide = subs.GetEnumerator(); while(ide.MoveNext()) { Subscriber sub = (Subscriber)ide.Value; if (sub.archs.Contains(arch)) { bool rc = true; string status = (string)sub.archs[arch]; if (!status.Equals("pending deploy")) rc = undeploy(user, host, (string)ide.Key, arch, (string)archives[arch], downloadURL); if (rc || isForce) { sub.archs.Remove(arch); if (sub.state.Equals("pending unsubscribe") && (sub.archs.Count == 0)) h.Remove(ide.Key); } else sub.archs[arch] = "pending undeploy"; subRep.dirty = true; } } } /// /// Check if the user is an administrator. /// /// User name /// public bool isAdministrator(string user) { if (administrators.Contains(user)) return true; else return false; } /// /// Check if the user is a publisher. /// /// User name /// public bool isPublisher(string user) { if (publishers.Contains(user)) return true; else return false; } } }