From eacb14f2966b24b56732c9f0a3ede93f58d51fd7 Mon Sep 17 00:00:00 2001 From: Mathew McBride Date: Wed, 9 Jul 2008 10:17:56 +1000 Subject: [PATCH] Initial commit --- nbactions.xml | 31 ++ pom.xml | 126 ++++++++ src/main/assemblies/netbeans-run.xml | 21 ++ .../funambol/bundle/ReleaseObject.java | 178 +++++++++++ .../bionicmessage/funambol/bundle/SetupUtils.java | 220 ++++++++++++++ .../net/bionicmessage/funambol/bundle/fnblGet.java | 180 +++++++++++ .../bionicmessage/funambol/bundle/postConfig.java | 330 +++++++++++++++++++++ .../bionicmessage/funambol/bundle/postConfig.java~ | 145 +++++++++ .../funambol/bundle/citadel.properties | 6 + .../funambol/bundle/egroupware.properties | 6 + .../funambol/bundle/opengroupware.properties | 6 + .../funambol/bundle/SetupUtilsTest.java | 52 ++++ .../funambol/bundle/ReleaseObject.class | Bin 0 -> 2902 bytes .../bionicmessage/funambol/bundle/SetupUtils.class | Bin 0 -> 5705 bytes .../funambol/bundle/citadel.properties | 6 + .../funambol/bundle/egroupware.properties | 6 + .../bionicmessage/funambol/bundle/fnblGet.class | Bin 0 -> 8482 bytes .../funambol/bundle/opengroupware.properties | 6 + .../bionicmessage/funambol/bundle/postConfig.class | Bin 0 -> 10907 bytes target/funambol-bundle-postconfig-1.0-SNAPSHOT.jar | Bin 0 -> 17581 bytes target/maven-archiver/pom.properties | 5 + ...ionicmessage.funambol.bundle.SetupUtilsTest.xml | 90 ++++++ ...ionicmessage.funambol.bundle.SetupUtilsTest.txt | 4 + .../funambol/bundle/SetupUtilsTest.class | Bin 0 -> 1744 bytes 24 files changed, 1418 insertions(+) create mode 100644 nbactions.xml create mode 100644 pom.xml create mode 100644 src/main/assemblies/netbeans-run.xml create mode 100644 src/main/java/net/bionicmessage/funambol/bundle/ReleaseObject.java create mode 100644 src/main/java/net/bionicmessage/funambol/bundle/SetupUtils.java create mode 100644 src/main/java/net/bionicmessage/funambol/bundle/fnblGet.java create mode 100644 src/main/java/net/bionicmessage/funambol/bundle/postConfig.java create mode 100644 src/main/java/net/bionicmessage/funambol/bundle/postConfig.java~ create mode 100644 src/main/resources/net/bionicmessage/funambol/bundle/citadel.properties create mode 100644 src/main/resources/net/bionicmessage/funambol/bundle/egroupware.properties create mode 100644 src/main/resources/net/bionicmessage/funambol/bundle/opengroupware.properties create mode 100644 src/test/java/net/bionicmessage/funambol/bundle/SetupUtilsTest.java create mode 100644 target/classes/net/bionicmessage/funambol/bundle/ReleaseObject.class create mode 100644 target/classes/net/bionicmessage/funambol/bundle/SetupUtils.class create mode 100644 target/classes/net/bionicmessage/funambol/bundle/citadel.properties create mode 100644 target/classes/net/bionicmessage/funambol/bundle/egroupware.properties create mode 100644 target/classes/net/bionicmessage/funambol/bundle/fnblGet.class create mode 100644 target/classes/net/bionicmessage/funambol/bundle/opengroupware.properties create mode 100644 target/classes/net/bionicmessage/funambol/bundle/postConfig.class create mode 100644 target/funambol-bundle-postconfig-1.0-SNAPSHOT.jar create mode 100644 target/maven-archiver/pom.properties create mode 100644 target/surefire-reports/TEST-net.bionicmessage.funambol.bundle.SetupUtilsTest.xml create mode 100644 target/surefire-reports/net.bionicmessage.funambol.bundle.SetupUtilsTest.txt create mode 100644 target/test-classes/net/bionicmessage/funambol/bundle/SetupUtilsTest.class diff --git a/nbactions.xml b/nbactions.xml new file mode 100644 index 0000000..91e81fe --- /dev/null +++ b/nbactions.xml @@ -0,0 +1,31 @@ + + + + run + + jar + + + package + org.codehaus.mevenide:netbeans-run-plugin:RELEASE:run-jar + + + /tmp/fnblbundle/Funambol/ds-server + + + + debug + + jar + + + package + org.codehaus.mevenide:netbeans-run-plugin:RELEASE:run-jar + + + /tmp/fnblbundle/Funambol/ds-server + true + -Xdebug -Djava.compiler=none -Xnoagent -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} + + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..fe128eb --- /dev/null +++ b/pom.xml @@ -0,0 +1,126 @@ + + + 4.0.0 + bmessage + funambol-bundle-postconfig + jar + 1.0-SNAPSHOT + funambol-bundle-postconfig + http://maven.apache.org + + + + maven-compiler-plugin + RELEASE + + 1.5 + 1.5 + + + + org.apache.maven.plugins + maven-jar-plugin + + + + net.bionicmessage.funambol.bundle.postConfig + + + + + + + + + netbeans-public + + + netbeans.execution + true + + + + + + maven-assembly-plugin + + + nb + package + + directory + + + ${basedir}/src/main/assemblies/netbeans-run.xml + executable + + + + + + maven-jar-plugin + + + + true + lib + net.bionicmessage.funambol.bundle.fnblGet + + + + + + + + + + + junit + junit + 3.8.1 + test + + + funambol + admin + 6.5.12 + compile + + + funambol + ds-server + 6.5.14 + compile + + + funambol + server-framework + 6.5.8 + compile + + + bmessage + httpauth + 1.0-SNAPSHOT + compile + + + bmessage + funambol-citadel-connector + 2.0 + compile + + + bmessage + funambol-groupdav-connector + 2.1 + compile + + + org.codehaus.plexus + plexus-utils + 1.1 + compile + + + diff --git a/src/main/assemblies/netbeans-run.xml b/src/main/assemblies/netbeans-run.xml new file mode 100644 index 0000000..c026f7b --- /dev/null +++ b/src/main/assemblies/netbeans-run.xml @@ -0,0 +1,21 @@ + + + netbeans +false + + + target + + + *.jar + + + + + + lib + false + runtime + + + diff --git a/src/main/java/net/bionicmessage/funambol/bundle/ReleaseObject.java b/src/main/java/net/bionicmessage/funambol/bundle/ReleaseObject.java new file mode 100644 index 0000000..77e504e --- /dev/null +++ b/src/main/java/net/bionicmessage/funambol/bundle/ReleaseObject.java @@ -0,0 +1,178 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package net.bionicmessage.funambol.bundle; + +public class ReleaseObject implements Comparable { + + String product; + String version; + String changeLog; + String location; + long timestamp; + String replaceFile; + String outFile; + String[] userConfigFiles; + + public ReleaseObject() { + } + + /** + * Returns the value of version. + */ + public String getVersion() { + return version; + } + + /** + * Sets the value of version. + * @param version The value to assign version. + */ + public void setVersion(String version) { + this.version = version; + } + boolean isStable; + + /** + * Returns the value of isStable. + */ + public boolean getIsStable() { + return isStable; + } + + /** + * Sets the value of isStable. + * @param isStable The value to assign isStable. + */ + public void setIsStable(boolean isStable) { + this.isStable = isStable; + } + + /** + * Returns the value of changeLog. + */ + public String getChangeLog() { + return changeLog; + } + + /** + * Sets the value of changeLog. + * @param changeLog The value to assign changeLog. + */ + public void setChangeLog(String changeLog) { + this.changeLog = changeLog; + } + + /** + * Returns the value of timestamp. + */ + public long getTimestamp() { + return timestamp; + } + + /** + * Sets the value of timestamp. + * @param timestamp The value to assign timestamp. + */ + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + /** + * Returns the value of replaceFile. + */ + public String getReplaceFile() { + return replaceFile; + } + + /** + * Sets the value of replaceFile. + * @param replaceFile The value to assign replaceFile. + */ + public void setReplaceFile(String replaceFile) { + this.replaceFile = replaceFile; + } + + /** + * Returns the value of outFile. + */ + public String getOutFile() { + return outFile; + } + + /** + * Sets the value of outFile. + * @param outFile The value to assign outFile. + */ + public void setOutFile(String outFile) { + this.outFile = outFile; + } + + /** + * Returns the value of userConfigFiles. + */ + public String[] getUserConfigFiles() { + return userConfigFiles; + } + + /** + * Sets the value of userConfigFiles. + * @param userConfigFiles The value to assign userConfigFiles. + */ + public void setUserConfigFiles(String[] userConfigFiles) { + this.userConfigFiles = userConfigFiles; + } + + /** + * Returns the value of product. + */ + public String getProduct() { + return product; + } + + /** + * Sets the value of product. + * @param product The value to assign product. + */ + public void setProduct(String product) { + this.product = product; + } + + /** + * Returns the value of location. + */ + public String getLocation() { + return location; + } + + /** + * Sets the value of location. + * @param location The value to assign location. + */ + public void setLocation(String location) { + this.location = location; + } + + public String toString() { + String str = String.format("Product: %s, Version %s, Time %s, Location %s, Replaces %s with %s \r\n%s", + product, + version, + Long.toString(timestamp), + location, + replaceFile, + outFile, + changeLog); + return str; + } + + public int compareTo(Object o) { + ReleaseObject r2 = (ReleaseObject) o; + if (this.getTimestamp() > r2.getTimestamp()) { + return 1; + } else if (this.getTimestamp() == r2.getTimestamp()) { + return 0; + } + return -1; + } +} \ No newline at end of file diff --git a/src/main/java/net/bionicmessage/funambol/bundle/SetupUtils.java b/src/main/java/net/bionicmessage/funambol/bundle/SetupUtils.java new file mode 100644 index 0000000..4e1968b --- /dev/null +++ b/src/main/java/net/bionicmessage/funambol/bundle/SetupUtils.java @@ -0,0 +1,220 @@ +/* + * Post configuration utility for Funambol/Groupware sync server + * Copyright (C) 2008 Mathew McBride + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by + * the Free Software Foundation with the addition of the following permission + * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED + * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE + * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program 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 General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program; if not, see http://www.gnu.org/licenses or write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA. + * + * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite + * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License + * version 3, these Appropriate Legal Notices must retain the display of the + * "Powered by Funambol" logo. If the display of the logo is not reasonably + * feasible for technical reasons, the Appropriate Legal Notices must display + * the words "Powered by Funambol". + */ +package net.bionicmessage.funambol.bundle; + +import com.funambol.admin.util.WSTools; +import java.io.InputStream; +import java.util.*; + +import com.funambol.framework.engine.source.ContentType; +import com.funambol.framework.engine.source.SyncSourceInfo; +import com.funambol.framework.filter.Clause; +import com.funambol.framework.filter.WhereClause; +import com.funambol.framework.server.Sync4jSource; +import java.beans.XMLEncoder; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.net.URL; +import net.bionicmessage.funambol.BVersion; +import net.bionicmessage.funambol.framework.Constants; +import net.bionicmessage.funambol.groupdav.calendar.CalendarSyncSource; +import net.bionicmessage.funambol.groupdav.contacts.ContactSyncSource; + +public class SetupUtils { + + /** Load a property file from the JAR with the default paths for the server + * + * @param srvType Server type (citadel/opengroupware/egroupware from 1-3 respectively) + * @return Filled Properties instance. + * @throws java.lang.Exception + */ + public static Properties getDefaultURLsForServer(int srvType) throws Exception { + String server = "citadel"; //failsafe default + if (srvType == 2) { + server = "egroupware"; + } else if (srvType == 3) { + server = "opengroupware"; + } + String resourcePath = "/net/bionicmessage/funambol/bundle/"+server+".properties"; + InputStream is = SetupUtils.class.getResourceAsStream(resourcePath); + Properties po = new Properties(); + po.load(is); + return po; + } + + /** Serialize an object + * @param obj Object to serialize + * @return Object serialized to XML + */ + public static String serializeObject(Object obj) throws Exception { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + XMLEncoder e = new XMLEncoder(bos); + e.writeObject(obj); + e.close(); + return bos.toString(); + } + + + public static String setupCalendarSyncSource(String serverURL, + String path, + String type, + String uri, + String stDirRoot) throws Exception { + CalendarSyncSource css = new CalendarSyncSource(); + css.setSourceURI(uri); + css.setName(uri); + Properties syncSourceProperties = new Properties(); + + // ctypes and syncsourceinfo + ContentType ctype = new ContentType(); + ctype.setType(type); + ctype.setVersion("1.0"); + ContentType[] ctypes = new ContentType[]{ctype}; + SyncSourceInfo ssInfo = new SyncSourceInfo(ctypes, 0); + css.setInfo(ssInfo); + + // basic properties + syncSourceProperties.setProperty(Constants.SERVER_HOST, serverURL); + + syncSourceProperties.setProperty(Constants.SOURCE_LOCATION_BASE + "default", path); + syncSourceProperties.setProperty(Constants.SINGLE_LOG, ""); + + String storePath = stDirRoot + File.separator + uri; + syncSourceProperties.setProperty(Constants.STOREDIR_PATH, storePath); + css.setConnectorProperties(syncSourceProperties); + return serializeObject(css); + } + + public static String setupContactSyncSource(String serverURL, + String path, + String type, + String uri, + String stDirRoot) throws Exception { + ContactSyncSource css = new ContactSyncSource(); + css.setSourceURI(uri); + css.setName(uri); + Properties syncSourceProperties = new Properties(); + + // ctypes and syncsourceinfo + ContentType ctype = new ContentType(); + ctype.setType(type); + if (type.equals("text/x-vcard")) { + ctype.setVersion("2.1"); + } else { + ctype.setVersion("1.0"); + } + ContentType[] ctypes = new ContentType[]{ctype}; + SyncSourceInfo ssInfo = new SyncSourceInfo(ctypes, 0); + css.setInfo(ssInfo); + + // basic properties + syncSourceProperties.setProperty(Constants.SERVER_HOST, serverURL); + + syncSourceProperties.setProperty(Constants.SOURCE_LOCATION_BASE + "default", path); + syncSourceProperties.setProperty(Constants.SINGLE_LOG, ""); + + String storePath = stDirRoot + File.separator + uri; + syncSourceProperties.setProperty(Constants.STOREDIR_PATH, storePath); + css.setConnectorProperties(syncSourceProperties); + return serializeObject(css); + } + + public static String setupS60CalendarSyncSource(String serverURL, + String calPath, + String taskPath, + String stDirRoot) throws Exception { + CalendarSyncSource css = new CalendarSyncSource(); + css.setSourceURI("groupdav-s60-v"); + css.setName("groupdav-s60-v"); + Properties syncSourceProperties = new Properties(); + + // ctypes and syncsourceinfo + ContentType ctype = new ContentType(); + ctype.setType("text/x-vcalendar"); + ctype.setVersion("1.0"); + ContentType[] ctypes = new ContentType[]{ctype}; + SyncSourceInfo ssInfo = new SyncSourceInfo(ctypes, 0); + css.setInfo(ssInfo); + + // basic properties + syncSourceProperties.setProperty(Constants.SERVER_HOST, serverURL); + + syncSourceProperties.setProperty(Constants.SOURCE_LOCATION_BASE + "default", calPath); + syncSourceProperties.setProperty(Constants.SOURCE_LOCATION_BASE + "tasks",taskPath); + syncSourceProperties.setProperty(Constants.SINGLE_LOG, ""); + + String storePath = stDirRoot + File.separator + "groupdav-s60-v"; + syncSourceProperties.setProperty(Constants.STOREDIR_PATH, storePath); + css.setConnectorProperties(syncSourceProperties); + return serializeObject(css); + } + + /** + * Does sync source already exist? + * @param ssId Sync Source URI + * @param fnbl WSTools instance to query with + * @return true if sync source is defined. + */ + public static boolean doesSyncSourceExist(String ssId, WSTools fnbl) throws Exception { + Clause clause = getClauseForSync4jSourceUriAndNameCheck(ssId, null); + String[] searchArg = new String[]{SetupUtils.serializeObject(clause)}; + Sync4jSource[] sources = (Sync4jSource[]) fnbl.invoke("getSync4jSources", searchArg); + if (sources.length > 0) { + return true; + } + return false; + } + /** Function copied from SyncSourceController */ + private static Clause getClauseForSync4jSourceUriAndNameCheck(String uri, String name) { + + List clauses = new ArrayList(); + + if (uri == null && name == null) { + return null; + } + + Clause uriClause = null; + + if (uri != null) { + uriClause = new WhereClause("uri", + new String[]{uri}, + WhereClause.OPT_EQ, + false); + clauses.add(uriClause); + } + + return uriClause; + } +} diff --git a/src/main/java/net/bionicmessage/funambol/bundle/fnblGet.java b/src/main/java/net/bionicmessage/funambol/bundle/fnblGet.java new file mode 100644 index 0000000..1f592ec --- /dev/null +++ b/src/main/java/net/bionicmessage/funambol/bundle/fnblGet.java @@ -0,0 +1,180 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package net.bionicmessage.funambol.bundle; + +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.xml.*; +import javax.xml.xpath.*; +import javax.xml.parsers.*; +import org.w3c.dom.*; + +public class fnblGet { + + ArrayList releasesForProduct = null; + ArrayList toUpdate = null; + //URL repoURL = + static URL repoURL = null; + File[] modules = null; + File dsServerRoot = null; + DocumentBuilderFactory dbf = null; + DocumentBuilder db = null; + Logger log = null; + + public fnblGet(String rootPath) { + dsServerRoot = new File(rootPath); + modules = new File(dsServerRoot, "modules").listFiles(); + log = Logger.getLogger("fnblGet"); + ConsoleHandler ch = new ConsoleHandler(); + ch.setLevel(Level.ALL); + log.addHandler(ch); + log.setLevel(Level.ALL); + log.info(modules.length + " files found in modules dir"); + toUpdate = new ArrayList(); + } + + public void fillReleaseForProductArray() throws Exception { + releasesForProduct = new ArrayList(); + dbf = DocumentBuilderFactory.newInstance(); + db = dbf.newDocumentBuilder(); + + InputStream repoStream = repoURL.openStream(); + Document repoDoc = db.parse(repoStream); + NodeList products = repoDoc.getElementsByTagName("product"); + for (int i = 0; i < products.getLength(); i++) { + Element product = (Element) products.item(i); + String name = product.getAttribute("name"); + NodeList releases = product.getElementsByTagName("release"); + for (int j = 0; j < releases.getLength(); j++) { + Element release = (Element) releases.item(j); + ReleaseObject rObj = new ReleaseObject(); + rObj.setProduct(name); + rObj.setVersion(release.getAttribute("version")); + + boolean isStable = Boolean.valueOf(getStringValueFromElement(release, "isStable")).booleanValue(); + rObj.setIsStable(isStable); + + String changeLog = getStringValueFromElement(release, "changelog"); + rObj.setChangeLog(changeLog); + + String times = getStringValueFromElement(release, "timestamp"); + rObj.setTimestamp(Long.parseLong(times)); + + String location = getStringValueFromElement(release, "location"); + rObj.setLocation(location); + + NodeList userConfigFiles = release.getElementsByTagName("userConf"); + + Element file = (Element) release.getElementsByTagName("file").item(0); + rObj.setReplaceFile(file.getAttribute("replaces")); + rObj.setOutFile(getStringValueFromElement(release, "file")); + releasesForProduct.add(rObj); + } + } + Collections.sort(releasesForProduct); /* Sort the array in desending order + * so when we scan it the newest release + * is the first we hit */ + + } + + public void checkModules() { + for (int i = 0; i < modules.length; i++) { + File file = modules[i]; + if (file.isFile() && file.getName().contains(".s4j")) { + log.finer("Module " + file.getName()); + ReleaseObject latest = getLatestReleaseForModule(file.getName()); + if (latest != null) { + log.fine("Latest release: " + latest.getVersion() + " ts:" + latest.getTimestamp()); + long curTimestamp = file.lastModified() / 1000; + if (latest.getTimestamp() > curTimestamp) { + log.info(file.getName() + " has a newer version"); + //todo: add stable check + toUpdate.add(latest); + } + } + } + } + } + + /** Download all available updates and write the files */ + public void downloadUpdates() throws Exception { + Iterator u = toUpdate.iterator(); + while (u.hasNext()) { + ReleaseObject update = u.next(); + File toUpdate = new File(dsServerRoot, "modules" + File.separator + update.getReplaceFile()); + URL toDownload = new URL(update.getLocation()); + URLConnection uc = toDownload.openConnection(); + int clength = uc.getContentLength(); + File tempFile = File.createTempFile("fnblupd", ".s4j"); + log.finer("Using temporary file: " + tempFile.getPath()); + FileOutputStream tempFileOutput = new FileOutputStream(tempFile); + InputStream is = uc.getInputStream(); + int readSoFar = 0; + while (readSoFar != clength) { + byte[] temp = new byte[65535]; + int read = is.read(temp); + readSoFar = readSoFar + read; + tempFileOutput.write(temp, 0, read); + float percentage = ((float) readSoFar / (float) clength) * 100; + System.out.print("\rRead " + percentage + "% of " + clength); + } + is.close(); + tempFileOutput.close(); + boolean oldDeleted = toUpdate.delete(); + if (!oldDeleted) { + throw new Exception("Old module " + toUpdate.getName() + " refused to delete"); + } + tempFile.renameTo(toUpdate); + tempFile.setLastModified(uc.getLastModified()); + } + } + + public ReleaseObject getLatestReleaseForModule(String file) { + Iterator it = releasesForProduct.iterator(); + while (it.hasNext()) { + ReleaseObject current = it.next(); + if (current.getReplaceFile().equals(file)) { + return current; + } + } + return null; + } + + public static void main(String[] args) { + System.out.println("FnblGet updater for Funambol"); + if (args.length == 0) { + System.out.println("Please specify the root path for ds-server"); + } + fnblGet fg = new fnblGet(args[0]); + try { + repoURL = new URL("http://latest.bionicmessage.net/fnbl-get/repo.xml"); + fg.fillReleaseForProductArray(); + fg.checkModules(); + fg.downloadUpdates(); + System.out.println("Done"); + } catch (Exception ex) { + Logger.getLogger(fnblGet.class.getName()).log(Level.SEVERE, null, ex); + ex.printStackTrace(); + } + } + + private String getStringValueFromElement(Element parent, String childTag) { + NodeList child = parent.getElementsByTagName(childTag); + Element tag = (Element) child.item(0); + if (tag != null && tag.getFirstChild() != null && tag.getFirstChild().getNodeType() == Node.TEXT_NODE) { + String value = tag.getFirstChild().getNodeValue(); + return value; + } + return ""; + } +} diff --git a/src/main/java/net/bionicmessage/funambol/bundle/postConfig.java b/src/main/java/net/bionicmessage/funambol/bundle/postConfig.java new file mode 100644 index 0000000..652f876 --- /dev/null +++ b/src/main/java/net/bionicmessage/funambol/bundle/postConfig.java @@ -0,0 +1,330 @@ +/* + * Post configuration utility for Funambol/Groupware sync server + * Copyright (C) 2008 Mathew McBride + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by + * the Free Software Foundation with the addition of the following permission + * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED + * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE + * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program 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 General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program; if not, see http://www.gnu.org/licenses or write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA. + * + * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite + * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License + * version 3, these Appropriate Legal Notices must retain the display of the + * "Powered by Funambol" logo. If the display of the logo is not reasonably + * feasible for technical reasons, the Appropriate Legal Notices must display + * the words "Powered by Funambol". + */ +package net.bionicmessage.funambol.bundle; + +import com.funambol.admin.util.*; +import com.funambol.server.config.*; +import com.funambol.framework.filter.*; +import net.bionicmessage.funambol.httpauth.HTTPAuthenticationOfficer; +import net.bionicmessage.funambol.citadel.sync.CitadelSyncSource; +import net.bionicmessage.funambol.citadel.store.CtdlFnblConstants; + +import com.funambol.framework.engine.source.ContentType; +import com.funambol.framework.engine.source.SyncSourceInfo; + +import java.io.*; +import java.util.*; + +import com.funambol.framework.server.*; +import com.funambol.server.inventory.PSDeviceInventory; +import java.net.URL; +import org.apache.log4j.LogManager; +import org.apache.log4j.varia.NullAppender; + +public class postConfig { + + public static final String HTTPAUTHBEAN = "net/bionicmessage/funambol/httpauth/HTTPAuthenticationOfficer.xml"; + private static String adminPass = null; + private static String WSPath = null; + private static String adminUser = null; + + /** Main method */ + public static void main(String args[]) { + if (args.length < 1) { + System.out.println("No arguments specified, exiting"); + System.out.println("Operations: "); + System.out.println("usehttpauth [server] [servertype] - Use HTTP Auth"); + System.out.println("usedefaultauth - Use the default UserProvisioningOfficer"); + System.out.println("queryofficer - Get bean for current officer"); + System.out.println("createcitadel [ctdlhost] [storeroot] - Creates a citadel sync source"); + System.out.println("createpim [server] [storeroot] [servertype] - Create PIM sync sources"); + System.out.println("doesexist [syncsourcename] - does a sync source URI exist?"); + System.out.println("setusepushnotify - set to use SMS Push for all new devices"); + System.out.println("changeadminpw - change administrator password"); + return; + } + String operation = args[0]; + try { + /* Silence log4j: http://forum.springframework.org/showthread.php?t=52297 */ + + System.setProperty("log4j.defaultInitOverride", "tr ue"); + LogManager.resetConfiguration(); + LogManager.getRootLogger().addAppender(new NullAppender()); + /* Load the server configuration */ + File serverPropsFile = new File("funambolserver.properties"); + WSPath = "http://localhost:8080/funambol/services/admin"; + adminUser = "admin"; + adminPass = "sa"; + if (serverPropsFile.exists()) { + Properties alternativeConfiguration = new Properties(); + alternativeConfiguration.load(new FileInputStream(serverPropsFile)); + WSPath = alternativeConfiguration.getProperty("wspath"); + adminUser = alternativeConfiguration.getProperty("user"); + adminPass = alternativeConfiguration.getProperty("pass"); + } + WSTools fnbl = new WSTools(WSPath, adminUser, adminPass); + ServerConfiguration config = (ServerConfiguration) fnbl.invoke("getServerConfiguration", null); + EngineConfiguration eConfig = config.getEngineConfiguration(); + System.out.println("Current officer: " + eConfig.getOfficer()); + if (operation.equals("usehttpauth") && args.length >= 2) { + eConfig.setOfficer(HTTPAUTHBEAN); + String[] setupArgs = new String[]{ + HTTPAUTHBEAN, + setupAndSerializeHTTPAuth(args[1],Integer.parseInt(args[2])) + }; + fnbl.invoke("setServerBean", setupArgs); + fnbl.invoke("setServerConfiguration", new ServerConfiguration[]{config}); + } else if (operation.equals("usedefaultauth")) { + eConfig.setOfficer(EngineConfiguration.DEFAULT_OFFICER); + fnbl.invoke("setServerConfiguration", new ServerConfiguration[]{config}); + } else if (operation.equals("queryofficer")) { + String officer = (String) fnbl.invoke("getServerBean", new String[]{eConfig.getOfficer()}); + System.out.println(officer); + } else if (operation.equals("createcitadel") && args.length == 3) { + if (!SetupUtils.doesSyncSourceExist("mail", fnbl)) { + String ss = setupCitadelSyncSource(args[1], args[2]); + String[] createArgs = new String[]{ + "bmCitadel", + "citadel", + "citadelMail", + ss + }; + fnbl.invoke("addSource", createArgs); + } else { + System.out.println("Mail sync source not created (already exists)"); + } + } else if (operation.equals("createpim") && args.length == 4) { + setupGroupDAVSyncSources(args[1], args[2], Integer.parseInt(args[3]), fnbl); + } else if (operation.equals("doesexist") && args.length == 2) { + System.out.println(SetupUtils.doesSyncSourceExist(args[1], fnbl)); + } else if (operation.equals("setusepushnotify")) { + setPushToSMS(fnbl); + } else if (operation.equals("changeadminpw")) { + setAdminPassword(fnbl); + } + // Save configuration file + Properties pcProps = new Properties(); + pcProps.setProperty("wspath", WSPath); + pcProps.setProperty("user", adminUser); + pcProps.setProperty("pass", adminPass); + pcProps.store(new PrintStream("funambolserver.properties"), "Properties for postconfig tool"); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** Sets up a CitadelSyncSource and serializes it for submission + * @param server Citadel server (i.e uncensored.citadel.org) + * @param storeRootPath Root path for stores (i.e /opt/Funambol/stores) + */ + public static String setupCitadelSyncSource(String server, String storeRootPath) + throws Exception { + String host = null; + String port = null; + if (server.contains(":")) { + String[] srvParts = server.split(":"); + host = srvParts[0]; + port = srvParts[1]; + } else { + host = server; + port = "504"; + } + String stPath = storeRootPath + File.separator + "mail"; + CitadelSyncSource css = new CitadelSyncSource(); + Properties syncSourceProps = new Properties(); + syncSourceProps.setProperty(CtdlFnblConstants.SERVER_HOST, server); + syncSourceProps.setProperty(CtdlFnblConstants.SERVER_PORT, port); + syncSourceProps.setProperty(CtdlFnblConstants.ROOM_MAIL, "Mail"); + syncSourceProps.setProperty(CtdlFnblConstants.STORE_LOC, stPath); + SyncSourceInfo ssInfo = new SyncSourceInfo(); + ContentType[] ctypes = new ContentType[]{ + new ContentType("application/vnd.omads-email+xml", "1.2"), + new ContentType("application/vnd.omads-folder+xml", "1.2") + }; + ssInfo.setSupportedTypes(ctypes); + css.setInfo(ssInfo); + css.setSyncSourceProperties(syncSourceProps); + css.setSourceURI("mail"); + css.setName("mail"); + return SetupUtils.serializeObject(css); + } + + /** Sets up a HTTPAuthenticationOfficer bean for the specified URL + * and returns the serialized bean + * @param server The HTTP URL to authenticate against + */ + public static String setupAndSerializeHTTPAuth(String server, int srvType) throws Exception { + Properties defaultPaths = SetupUtils.getDefaultURLsForServer(srvType); + HTTPAuthenticationOfficer newOfficer = new HTTPAuthenticationOfficer(); + URL authPath= new URL(new URL(server),defaultPaths.getProperty("calendar")); + newOfficer.setAuthenticationPath(authPath.toExternalForm()); + return SetupUtils.serializeObject(newOfficer); + } + + public static void setPushToSMS(WSTools fnbl) throws Exception { + String[] srvBean = new String[]{"com/funambol/server/inventory/PSDeviceInventory.xml"}; + PSDeviceInventory dI = (PSDeviceInventory) fnbl.invoke("getServerBean", srvBean); + dI.getDevicePersistentStore().setDefaultNotificationSender("smsnotify/bmclickatell/bmclickatell.xml"); + String serialized = SetupUtils.serializeObject(dI); + String[] save = new String[]{"com/funambol/server/inventory/PSDeviceInventory.xml", serialized}; + fnbl.invoke("setServerBean", save); + System.out.println("Server now set to use SMS notification. You will need"); + System.out.println("to configure the SMS notification in the configuration too"); + System.out.println("as well as configure the phone number (MSISDN) for the device"); + System.out.println("after first sync"); + } + + /** Sets up the default GroupDAV sync sources + * @param server The GroupDAV HTTP server host and port (i.e "http://comalies.citadel.org:2000") + * @param stDirRoot The root dir for stores (i.e /opt/Funambol); + * @param srvType Server type id + * @param fnbl WSTools instance to use + */ + public static void setupGroupDAVSyncSources(String server, + String stDirRoot, + int srvType, + WSTools fnbl) throws Exception { + Properties defaultPaths = SetupUtils.getDefaultURLsForServer(srvType); + if (!SetupUtils.doesSyncSourceExist("groupdav-cal-s", fnbl)) { + String source = SetupUtils.setupCalendarSyncSource(server, + defaultPaths.getProperty("calendar"), + "text/x-s4j-sife", + "groupdav-cal-s", + stDirRoot); + String[] createArgs = new String[]{ + "groupdav", + "groupdav", + "groupdavCal", + source + }; + fnbl.invoke("addSource", createArgs); + } + if (!SetupUtils.doesSyncSourceExist("groupdav-cal-v", fnbl)) { + String source = SetupUtils.setupCalendarSyncSource(server, + defaultPaths.getProperty("calendar"), + "text/x-vcalendar", + "groupdav-cal-v", + stDirRoot); + String[] createArgs = new String[]{ + "groupdav", + "groupdav", + "groupdavCal", + source + }; + fnbl.invoke("addSource", createArgs); + } + if (!SetupUtils.doesSyncSourceExist("groupdav-task-s", fnbl)) { + String source = SetupUtils.setupCalendarSyncSource(server, + defaultPaths.getProperty("task"), + "text/x-s4j-sift", + "groupdav-task-s", + stDirRoot); + String[] createArgs = new String[]{ + "groupdav", + "groupdav", + "groupdavCal", + source + }; + fnbl.invoke("addSource", createArgs); + } + if (!SetupUtils.doesSyncSourceExist("groupdav-task-v", fnbl)) { + String source = SetupUtils.setupCalendarSyncSource(server, + defaultPaths.getProperty("task"), + "text/x-vcalendar", + "groupdav-task-v", + stDirRoot); + String[] createArgs = new String[]{ + "groupdav", + "groupdav", + "groupdavCal", + source + }; + fnbl.invoke("addSource", createArgs); + } + if (!SetupUtils.doesSyncSourceExist("groupdav-addr-v", fnbl)) { + String source = SetupUtils.setupContactSyncSource(server, + defaultPaths.getProperty("address"), + "text/x-vcard", + "groupdav-addr-v", + stDirRoot); + String[] createArgs = new String[]{ + "groupdav", + "groupdav", + "groupdavContact", + source + }; + fnbl.invoke("addSource", createArgs); + } + if (!SetupUtils.doesSyncSourceExist("groupdav-addr-s", fnbl)) { + String source = SetupUtils.setupContactSyncSource(server, + defaultPaths.getProperty("address"), + "text/x-s4j-sifc", + "groupdav-addr-s", + stDirRoot); + String[] createArgs = new String[]{ + "groupdav", + "groupdav", + "groupdavContact", + source + }; + fnbl.invoke("addSource", createArgs); + } + if (!SetupUtils.doesSyncSourceExist("groupdav-s60-v", fnbl)) { + String source = SetupUtils.setupS60CalendarSyncSource(server, + defaultPaths.getProperty("calendar"), + defaultPaths.getProperty("task"), + stDirRoot); + String[] createArgs = new String[]{ + "groupdav", + "groupdav", + "groupdavCal", + source + }; + fnbl.invoke("addSource", createArgs); + } + } + + private static void setAdminPassword(WSTools fnbl) throws Exception { + WhereClause wc = new WhereClause("username", new String[]{"admin"}, WhereClause.OPT_EQ, false); + String clause = SetupUtils.serializeObject(wc); + Sync4jUser[] result = (Sync4jUser[]) fnbl.invoke("getUsers", new String[]{clause}); + Sync4jUser admin = result[0]; + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + System.out.println("Please enter a new password for the Funambol admin account"); + adminPass = br.readLine(); + admin.setPassword(adminPass); + fnbl.invoke("setUser", new Object[]{admin}); + } +} diff --git a/src/main/java/net/bionicmessage/funambol/bundle/postConfig.java~ b/src/main/java/net/bionicmessage/funambol/bundle/postConfig.java~ new file mode 100644 index 0000000..0c83190 --- /dev/null +++ b/src/main/java/net/bionicmessage/funambol/bundle/postConfig.java~ @@ -0,0 +1,145 @@ +/* +* Post configuration utility for Funambol/Groupware sync server +* Copyright (C) 2008 Mathew McBride +* +* This program is free software; you can redistribute it and/or modify it under +* the terms of the GNU Affero General Public License version 3 as published by +* the Free Software Foundation with the addition of the following permission +* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED +* WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE +* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. +* +* This program 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 General Public License for more +* details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program; if not, see http://www.gnu.org/licenses or write to +* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +* MA 02110-1301 USA. +* +* You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite +* 305, Redwood City, CA 94063, USA, or at email address info@funambol.com. +* +* The interactive user interfaces in modified source and object code versions +* of this program must display Appropriate Legal Notices, as required under +* Section 5 of the GNU Affero General Public License version 3. +* +* In accordance with Section 7(b) of the GNU Affero General Public License +* version 3, these Appropriate Legal Notices must retain the display of the +* "Powered by Funambol" logo. If the display of the logo is not reasonably +* feasible for technical reasons, the Appropriate Legal Notices must display +* the words "Powered by Funambol". +*/ +package net.bionicmessage.funambol.bundle; +import com.funambol.admin.util.*; +import com.funambol.server.config.*; +import net.bionicmessage.funambol.httpauth.HTTPAuthenticationOfficer; +import net.bionicmessage.funambol.citadel.sync.CitadelSyncSource; +import net.bionicmessage.funambol.citadel.store.CtdlFnblConstants; + +import com.funambol.framework.engine.source.ContentType; +import com.funambol.framework.engine.source.SyncSourceInfo; + +import java.io.*; +import java.beans.XMLEncoder; +import java.util.Properties; +public class postConfig { + public static final String HTTPAUTHBEAN = "net/bionicmessage/funambol/httpauth/HTTPAuthenticationOfficer.xml"; + /** Sets up a CitadelSyncSource and serializes it for submission + * @param server Citadel server (i.e uncensored.citadel.org) + * @param storeRootPath Root path for stores (i.e /opt/Funambol/stores) + */ + public static String setupSyncSource(String server, String storeRootPath) + throws Exception{ + String host = null; + String port = null; + if (server.contains(":")) { + String[] srvParts = server.split(":"); + host = srvParts[0]; + port = srvParts[1]; + } else { + host = server; + port = "504"; + } + String stPath = storeRootPath+File.pathSeparator+"mail"; + CitadelSyncSource css = new CitadelSyncSource(); + Properties syncSourceProps = new Properties(); + syncSourceProps.setProperty(CtdlFnblConstants.SERVER_HOST, server); + syncSourceProps.setProperty(CtdlFnblConstants.SERVER_PORT, port); + syncSourceProps.setProperty(CtdlFnblConstants.ROOM_MAIL, "Mail"); + syncSourceProps.setProperty(CtdlFnblConstants.STORE_LOC, stPath); + SyncSourceInfo ssInfo = new SyncSourceInfo(); + ContentType[] ctypes = new ContentType[]{ + new ContentType("application/vnd.omads-email+xml", "1.2"), + new ContentType("application/vnd.omads-folder+xml", "1.2") + }; + ssInfo.setSupportedTypes(ctypes); + css.setInfo(ssInfo); + css.setSyncSourceProperties(syncSourceProps); + css.setSourceURI("mail"); + css.setName("mail"); + return serializeObject(css); + } + /** Serialize an object + * @param obj Object to serialize + * @return Object serialized to XML + */ + public static String serializeObject(Object obj) throws Exception { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + XMLEncoder e = new XMLEncoder(bos); + e.writeObject(obj); + e.close(); + return bos.toString(); + } + /** Sets up a HTTPAuthenticationOfficer bean for the specified URL + * and returns the serialized bean + * @param server The HTTP URL to authenticate against + */ + public static String setupAndSerializeHTTPAuth(String server) throws Exception { + HTTPAuthenticationOfficer newOfficer = new HTTPAuthenticationOfficer(); + newOfficer.setAuthenticationPath(server); + return serializeObject(newOfficer); + } + /** Main method */ + + public static void main(String args[]) { + if (args.length < 1) { + System.out.println("No arguments specified, exiting"); + System.out.println("Operations: "); + System.out.println("usehttpauth [http://server:port/path] - Use HTTP Auth"); + System.out.println("usedefaultauth - Use the default UserProvisioningOfficer"); + System.out.println("queryofficer - Get bean for current officer"); + System.out.println("createcitadel [ctdlhost] [storeroot] - Creates a citadel sync source"); + return; + } + String operation = args[0]; + try { + /* Load the server configuration */ + WSTools fnbl = new WSTools("http://localhost:8080/funambol/services/admin","admin","sa"); + ServerConfiguration config = (ServerConfiguration)fnbl.invoke("getServerConfiguration",null); + EngineConfiguration eConfig = config.getEngineConfiguration(); + System.out.println("Current officer: "+eConfig.getOfficer()); + if (operation.equals("usehttpauth") && args.length > 1) { + eConfig.setOfficer(HTTPAUTHBEAN); + String[] setupArgs = new String[]{ + HTTPAUTHBEAN, + setupAndSerializeHTTPAuth(args[1]) + }; + fnbl.invoke("setServerBean",setupArgs); + } + else if (operation.equals("usedefaultauth")) { + eConfig.setOfficer(EngineConfiguration.DEFAULT_OFFICER); + } else if (operation.equals("queryofficer")) { + String officer = (String)fnbl.invoke("getServerBean",new String[]{eConfig.getOfficer()}); + System.out.println(officer); + } + // Save configuration + fnbl.invoke("setServerConfiguration",new ServerConfiguration[]{config}); + } + catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/resources/net/bionicmessage/funambol/bundle/citadel.properties b/src/main/resources/net/bionicmessage/funambol/bundle/citadel.properties new file mode 100644 index 0000000..1371761 --- /dev/null +++ b/src/main/resources/net/bionicmessage/funambol/bundle/citadel.properties @@ -0,0 +1,6 @@ +# To change this template, choose Tools | Templates +# and open the template in the editor. + +calendar=/groupdav/Calendar/ +task=/groupdav/Tasks/ +address=/groupdav/Contacts/ \ No newline at end of file diff --git a/src/main/resources/net/bionicmessage/funambol/bundle/egroupware.properties b/src/main/resources/net/bionicmessage/funambol/bundle/egroupware.properties new file mode 100644 index 0000000..a09a6fc --- /dev/null +++ b/src/main/resources/net/bionicmessage/funambol/bundle/egroupware.properties @@ -0,0 +1,6 @@ +# To change this template, choose Tools | Templates +# and open the template in the editor. + +calendar=/egroupware/groupdav.php/calendar/ +task=/egroupware/groupdav.php/infolog/ +address=/egroupware/groupdav.php/addressbook/ diff --git a/src/main/resources/net/bionicmessage/funambol/bundle/opengroupware.properties b/src/main/resources/net/bionicmessage/funambol/bundle/opengroupware.properties new file mode 100644 index 0000000..1d3fc06 --- /dev/null +++ b/src/main/resources/net/bionicmessage/funambol/bundle/opengroupware.properties @@ -0,0 +1,6 @@ +# To change this template, choose Tools | Templates +# and open the template in the editor. + +calendar=/zidestore/dav/%USER%/Overview +task=/zidestore/dav/%USER%/Tasks +address=/zidestore/dav/%USER%/Contacts \ No newline at end of file diff --git a/src/test/java/net/bionicmessage/funambol/bundle/SetupUtilsTest.java b/src/test/java/net/bionicmessage/funambol/bundle/SetupUtilsTest.java new file mode 100644 index 0000000..b1fb6f6 --- /dev/null +++ b/src/test/java/net/bionicmessage/funambol/bundle/SetupUtilsTest.java @@ -0,0 +1,52 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package net.bionicmessage.funambol.bundle; + +import java.util.Properties; +import junit.framework.TestCase; + +/** + * + * @author matt + */ +public class SetupUtilsTest extends TestCase { + + public SetupUtilsTest(String testName) { + super(testName); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + public void testGetPathsForServer() throws Exception { + Properties forCitadel = SetupUtils.getDefaultURLsForServer(1); + System.out.println(forCitadel.toString()); + } + public void testSetupCalendarSyncSource() throws Exception { + String setup = SetupUtils.setupCalendarSyncSource("http://comalies.citadel.org", + "/groupdav/Calendar", + "text/x-s4j-sife", + "groupdav-s-cal", + "/opt/Funambol/stores"); + System.out.println(setup); + } + public void testSetupContactSyncSource() throws Exception { + String setup = SetupUtils.setupContactSyncSource("http://comalies.citadel.org", + "/groupdav/Contacts", + "text/x-vcard", + "groupdav-v-addr", + "/opt/Funambol/stores"); + System.out.println(setup); + } + +} diff --git a/target/classes/net/bionicmessage/funambol/bundle/ReleaseObject.class b/target/classes/net/bionicmessage/funambol/bundle/ReleaseObject.class new file mode 100644 index 0000000000000000000000000000000000000000..d836981f43d4f6a12b1bddb5f21e9765be302dce GIT binary patch literal 2902 zcwUv2-BTM?6u{3Wn{2XdAqEnKstrXn0c-@n`Xy3Qi(p!irO|-4Zo(3_lk76Pn>yp@ zlaKo3_+)4L=z~(H&J^u9qvNxGl;b(OHygOzJP5=6I5{7`^O4Ix|Nik80L+7-f(EN; z7=blfKA@#a%S~Et(Xvj<1}z`bvY7&1fh`qoLrsN`;9~{qD$2JN*pWavaGl+5)0ZGy zy=UAv%5B4Lm37~>?A8_h_`d0SmSanhZtmkJX4Pp)kZL6cjZPG0fTt$wA^&swN+Oeh!E$k8yWZXR#Ku*V4~x%FOSD2wQl#ZPYY zjmi~E!d7KHfpWem&?PJiy3w083L0IgMAc}Zs5t#w%6CE^n6u}*G=@&+z;MkihpRbj zU1=2u$2mF8QCDN`0>;*zuG=d`_C(_^kc|fCprFARjB4-#yr@BrPS3(~8jRCvf|j%J zyari1q!^`m7x#zeY16z1WF#S7% z=A71oNqmYlkl-0e;{%5!1^O9ddyegSwqqNDeVpAV*pB@Oc5GN+B~cS`oy6PgxJ$Sv zW_}0hS3JbvJgzG46i`MNQ+U!sC3p#@ahKp_c!fDAM-HAq>~Z8E83@OP#ziPG<3-e_ zK*^ceBZ%?gC(-77;2|GsF%NX28c^UFm=%D;4>^#M5M&NsJq2?12;w}*JlZS_0HLB% z;0wZv$b3aE3PH-^ipV_3653oF0Fq-B!Fi5AVi8E<5eKp&1X&0MA_R%!FM*spf&>q; zjy4+uKxhmJNAm5Z&WGMpq0;Qz2oE^$2e}YzzQ)%?NOb?u1557!K z;f!8S5~*HSXsGpiibhJWXGkjRPhq$^+s`88c!*JcJjSuiIF|5sjd3hPg>iK8@ue@| z)a>6da&zW4$jss2_YWZ?89f*)fw%Yn11~Ahi2wiq literal 0 HcwPel00001 diff --git a/target/classes/net/bionicmessage/funambol/bundle/SetupUtils.class b/target/classes/net/bionicmessage/funambol/bundle/SetupUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..4a95b2725403063701feeefcac99894676314e85 GIT binary patch literal 5705 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 literal 0 HcwPel00001 diff --git a/target/classes/net/bionicmessage/funambol/bundle/citadel.properties b/target/classes/net/bionicmessage/funambol/bundle/citadel.properties new file mode 100644 index 0000000..1371761 --- /dev/null +++ b/target/classes/net/bionicmessage/funambol/bundle/citadel.properties @@ -0,0 +1,6 @@ +# To change this template, choose Tools | Templates +# and open the template in the editor. + +calendar=/groupdav/Calendar/ +task=/groupdav/Tasks/ +address=/groupdav/Contacts/ \ No newline at end of file diff --git a/target/classes/net/bionicmessage/funambol/bundle/egroupware.properties b/target/classes/net/bionicmessage/funambol/bundle/egroupware.properties new file mode 100644 index 0000000..a09a6fc --- /dev/null +++ b/target/classes/net/bionicmessage/funambol/bundle/egroupware.properties @@ -0,0 +1,6 @@ +# To change this template, choose Tools | Templates +# and open the template in the editor. + +calendar=/egroupware/groupdav.php/calendar/ +task=/egroupware/groupdav.php/infolog/ +address=/egroupware/groupdav.php/addressbook/ diff --git a/target/classes/net/bionicmessage/funambol/bundle/fnblGet.class b/target/classes/net/bionicmessage/funambol/bundle/fnblGet.class new file mode 100644 index 0000000000000000000000000000000000000000..cc1925bf54055ad78a7573c33c7dfc480ca16b6a GIT binary patch literal 8482 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
JB~=9#(ntbcqk>oL0D-1!+Ql#6dVy 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�T zqyV)KI-0ta%i+nrY_C(9O0-5OeY1%k=&O!@+ujm;(3dm)B{t*k!adJ`{H8ubWwWW* z{+keEkteq&b-}k!1uI`k_dlW7UpXi^twyy;6t=|5JJ46{HkQO2wwNP3?q!x4)uc!9 zM>47!3)SWPjLopew-UA_@3_-9?FL7qf@QaU4~xpY;&AuPYU$yU*_P#%AE}RR ztG)56{FX0&Nr3B&iuZ-Ht=_dg$n~B}@T(k8Rmligu$!ehXBn8*eaGV~R(bcD{qhJe zCH&^C+c&S>4KKrdZ+geftH1*0^*Z~?^ezW+w}Koh+m4}iR2pv^-TgTmFT1Q9C0`O5 z7W^d6D~)-LZ|xIR(JyQYZbY!6o8-(XorukMjhwemvt%KmZQ_@^!c1}Rj`T&dHsY}! z!`)-eMrt<*RWF)Us$w)>>x}Xh^uy1^e>ga*9GY(LqW5eshA0C_)2}`&XmcB)+6%DX zI$qGqcNDI9O{hesUS7jwP&FCP~#W5FJ;?yZiI_C82`fl6>PU2LaUVlijBTajjVdyvm~KJav4= zc*?3rw-@f~ z&bh=X<0u7v@k#ycp&wfW$&fohrpipe!L=>bn{$0~mjo)j&hRND)0MH+AgxN6d=b3Y9Pf#M$*oR*v%vHRep3`kT z>Akb5+dNBjkka`17JGWgi`tjyO|jN-A=ge4MtnSprYAHVNqM>t6BPDc$EbE66}2z9 zNRH>!T%Oyxs8&*c=&=<>XlRif5D8+nUd0fG3PdB8dY})WF+HYc)J6sB-NG~28R85( zkGV|Ct}z_1I+Ftkg~-epc&VCrW}Uv3`3<@4!2~4>KQuP!Jg1j(o(jWd3t-xp3)WdP zR$^EHS;K^nS02Gih2rR`!h}zmQ5`^Ae~u_?Bfo{Yd@FD=vkstX*v^6Zh#N%B9&d=J zP@ug_=AXr$h|Wf~R4qb+x@#VY9horMPQ>p%z3RHaSnXx2!}SVIJ|YHC2Qo$%VC%>> zp>PESygLysIre9#rEeJ0>AYnn1WP{iLAHL9GFNu4?qMqIYJOVj zn#|Ox+c(8`x;Eu*-5G6^7NBnVB*Hm@->MSU%b$$KoV!gfH*n|mMwvnW3$o5_t!y_5 z`Y|pl-AC60EBVzJ`;sev?RmsKHyUGRo9Vt-*(W}Ws5zCaG3ffzGJDk_k@ra0fG>_# z^^JqR#r0)W9|vorX~tgH8jLLa%st6H`Wa@FprvCq`?MEQ&>|teVO!y0X9)S>wM_X&0wEj$sc;0>FOY zQ8b6DnLXFtir?~=rKf!>`B@zcl?JV%PkfNhwqwWF3@Zp@#%>v&(UZW=a0=N8MT>4CY>lvL zb7<>9(NpopQt51Ci#LvtE0lgWM~BZptA3y;uFjK4XY~m1qeF?B|CT(WWpEs79L;

6;@noSgYCbRRG`9_B=uUz5z}?x*>@aN$1BV8n(c`Y?jT%`0e20WptJ8tB+7uc7YC?mxRYWC~doTX-vz?iZk3`7%5 z1gT{%Gfo)^28)z%Sp3eRVL}&I;wK_I-b3$lS;9Wmi8A#Bk7Om*FQ+s|iSN8{YR`ge zrYVW+uHfx2EJ@fV*d64vbpe=;c;#G?SPrFk1n17A#M-V+d`XbKV1} z^wOnLJ%3qhMS#tpV-mE#H_59Clb2Uc&f^VUBIqn%9EnublUwFEW_@nYQxqIlrcES4 z!$W|>B&w=haUunK${F^=$6U{igXg?b-bn`+z`p-#Xg{I-pqYy@v5oN6-bW6D73#aE zha-_`S0QF`%TV13r9s!rU6sD5>tNzBn40%-RHe7dDiBF*MYN{w+HsC>w3cyseE?js z#)d!KOi^1NDCzOpU~(2%AgK}Jy*(iPaZm+IYyuUmQ?Otx>H1Ns8OHc^nY;Z;_S%e zgOb|EwFVQU&ab)cSNl%bcSbyW=XRc< zLjC>05aR^U3O3=8CB+rniC!cAvY%az3OG8l#dt(N_rLeO_rZPVGX%?o1WI-*(Eid{ zPTI#q{W5L0rzfiq%$<-`YM-#jE0IzI|IEfPIu=6F3U(QLCTb=*W2++L7=wYUFI^2@ zhdDgW?1N~URP;G+>A3yF=#nBT10wm}NLb+G=|eoCBk=nWNkRJ!2`1B67JoU9a40QlS!*S?-T%WJq_FDryXR zif06rS-pEj%qh$LeX2MJfCq-B$d*H*~EAuLtBwcqZOk3h-{2bg2eO@+D7I?E#j$#yI$=`XekLpodo0Q zA=qH4VDiy;8$p-HbByv3zD7-Sxs;HiyzZfrPRJ@`v$GgnV%ldd-8-f`r@WYk^@Ud* zNxrHE9~F`-&u{ZftUwlN;z)QY?(Ss1=p<5Pp?v}S9b4){QO#qXXG5eq`#s1@_KA_C zfV%r=j!z140gY-fPRIRM9z|PGNjPrQ4dT)Upv@5nbvZSCb`BqlC;R}El9sPOTp+4Z zG`70+k_&2T9#GBFv?y!CE7<&!ypt*=X9xLm0Am$ro(p-t_O zxU-n{Ay-M9VhSw|C4bET;Hl^1yRD+3+oVkd5A&ai>;EwOYwG$xMtLYT$X^rL{~7qNnB)I7eh2;n@(&*Q zzqdg97YhW?zvh+ydwcwUu^0GD`+wq@|KaGbnC5>t^8C+^{)cz|$722!^ZXy9Jhc69 z`TO5I^gko~nHl~Ef;ZUTLHJ9a_&kdobO=#9q0e9 z4f)SO{J9bM51bavzk~DVw%|X<@#l+zKm0$@{vH2+ac%JD5dK`^`vW46>F+@Nx#0Jo zjtu1g`Sttbf6DV0iQvCC#`zax6yE=o82)=N?Em6L>OXk-kBQ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/target/surefire-reports/net.bionicmessage.funambol.bundle.SetupUtilsTest.txt b/target/surefire-reports/net.bionicmessage.funambol.bundle.SetupUtilsTest.txt new file mode 100644 index 0000000..fbbb71e --- /dev/null +++ b/target/surefire-reports/net.bionicmessage.funambol.bundle.SetupUtilsTest.txt @@ -0,0 +1,4 @@ +------------------------------------------------------------------------------- +Test set: net.bionicmessage.funambol.bundle.SetupUtilsTest +------------------------------------------------------------------------------- +Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.178 sec diff --git a/target/test-classes/net/bionicmessage/funambol/bundle/SetupUtilsTest.class b/target/test-classes/net/bionicmessage/funambol/bundle/SetupUtilsTest.class new file mode 100644 index 0000000000000000000000000000000000000000..926dc0c1bfb5001efabb717fbea9be5717a207fa GIT binary patch literal 1744 zcwVhkZC4XV6n+L0c8y!03j}p+0^IV3qxKDv)5%9FWI^Z z_YXtSHAJBu{L;_nYD+#(s1*zJK$u-__Vu<@b)kAfQA$gyYGim*#0 ztDnQcFy9ttOSE_zo4qHsVNskbJuIIlh3O#`zR*T=NPIG-a_6#)NK$;17?P;q9ZHxT z1!T1;GZj-rsXR*CGb8XAoUT2^)b6}KO_0fm_xAttj4ZXNN2;E5?9<q#g}&EEp0XBbSInYt4(A6b7jTgl+o{s&p&jQRio literal 0 HcwPel00001 -- 2.11.4.GIT