I had to do some work on a ZenOSS system last week which ended up in my dropping to the ZenOSS console AKA zendmd. Finding API references is tricky, but they do allow tab completion / option listing. On a main device in /Devices/Server, I get the following 614 options, but without an API reference, I have no idea what most of them do.

>>> d.
Display all 614 possibilities? (y or n)
d.COPY(                                 	d.manage_addSiteRootForm(
d.DELETE(                               	d.manage_addUserCommand(
d.HDDIO(                                	d.manage_addUserFolder(
d.HEAD(                                 	d.manage_addZenMenu(
d.LOCK(                                 	d.manage_addZenMenuItem(
d.MKCOL(                                	d.manage_changeOwnershipType(
d.MOVE(                                 	d.manage_changePermissions(
d.OPTIONS(                              	d.manage_changeProperties(
d.PROPFIND(                             	d.manage_changePropertyTypes(
d.PROPPATCH(                            	d.manage_change_history(
d.PUT(                                  	d.manage_change_history_page(
d.SQLConnectionIDs(                     	d.manage_clone(
d.SiteRootAdd(                          	d.manage_copyObjects(
d.TRACE(                                	d.manage_copyright(
d.UNLOCK(                               	d.manage_createEventMap(
d.ZQueryIds(                            	d.manage_cutObjects(
d.absolute_url(                         	d.manage_defined_roles(
d.absolute_url_path(                    	d.manage_delLocalRoles(
d.ac_inherited_permissions(             	d.manage_delObjects(
d.access_debug_info(                    	d.manage_delProperties(
d.acquiredRolesAreUsedBy(               	d.manage_deleteAdministrativeRole(
d.addDTMLDocument(                      	d.manage_deleteBatchEvents(
d.addDTMLMethod(                        	d.manage_deleteEvents(
d.addDeviceGroup(                       	d.manage_deleteHeartbeat(
d.addLocalTemplate(                     	d.manage_deleteMaintenanceWindow(
d.addLocation(                          	d.manage_deleteObjects(
d.addManufacturer(                      	d.manage_deleteUserCommand(
d.addRelation(                          	d.manage_deleteZenMenu(
d.addSystem(                            	d.manage_deleteZenMenuItem(
d.addToZenPack(                         	d.manage_doUserCommand(
d.adminRoles(                           	d.manage_editAdministrativeRoles(
d.all_meta_types(                       	d.manage_editDevice(
d.allowedRolesAndUsers(                 	d.manage_editLocalRoles(
d.applyDataMap(                         	d.manage_editProperties(
d.applyProductContext(                  	d.manage_editRoles(
d.aqBaseHasAttr(                        	d.manage_editUserCommand(
d.availability(                         	d.manage_editedDialog(
d.bindTemplates(                        	d.manage_exportObject(
d.bobobase_modification_time(           	d.manage_fixupOwnershipAfterAdd(
d.breadCrumbs(                          	d.manage_form_title(
d.buildMenus(                           	d.manage_getPermissionMapping(
d.buildRelations(                       	d.manage_getUserRolesAndPermissions(
d.cacheComponents(                      	d.manage_hasId(
d.cacheRRDValue(                        	d.manage_historicalComparison(
d.callZenScreen(                        	d.manage_historyCompare(
d.changeDeviceClass(                    	d.manage_historyCopy(
d.changeOwnership(                      	d.manage_importExportForm(
d.changePythonClass(                    	d.manage_importObject(
d.checkRelations(                       	d.manage_index_main(
d.checkRemotePerm(                      	d.manage_linkObjects(
d.checkValidId(                         	d.manage_listAdministrativeRoles(
d.collectDevice(                        	d.manage_listLocalRoles(
d.comments                              	d.manage_main(
d.compile(                              	d.manage_menu(
d.convertEventField(                    	d.manage_options
d.createHierarchyObj(                   	d.manage_owner(
d.createdTime                           	d.manage_page_footer(
d.creator(                              	d.manage_page_header(
d.custPropertyIds(                      	d.manage_page_style.css(
d.custPropertyMap(                      	d.manage_pasteObjects(
d.defaultTimeout                        	d.manage_permission(
d.default_catalog                       	d.manage_permissionForm(
d.deleteDevice(                         	d.manage_propertiesForm(
d.deleteZenProperty(                    	d.manage_propertyTypeForm(
d.dependencies(                         	d.manage_removeRelation(
d.dependents(                           	d.manage_renameForm(
d.detailKeys                            	d.manage_renameObject(
d.details(                              	d.manage_renameObjects(
d.device(                               	d.manage_reportUserPermissions(
d.deviceClass(                          	d.manage_role(
d.doCommandForTarget(                   	d.manage_roleForm(
d.editableDeviceList(                   	d.manage_saveMenuItemOrdering(
d.eligiblePacks(                        	d.manage_setEventStates(
d.event_key                             	d.manage_setLocalRoles(
d.exportXml(                            	d.manage_setPermissionMapping(
d.exportXmlHook(                        	d.manage_snmpCommunity(
d.exportXmlProperties(                  	d.manage_tabs(
d.exportXmlRelationships(               	d.manage_takeOwnership(
d.exportZProperties(                    	d.manage_top_frame(
d.factory_type_information              	d.manage_undeleteBatchEvents(
d.fetchRRDValue(                        	d.manage_undeleteEvents(
d.fetchRRDValues(                       	d.manage_undo_transactions(
d.filtered_manage_options(              	d.manage_unlinkObjects(
d.filtered_meta_types(                  	d.manage_workspace(
d.findChild(                            	d.manage_zmi_logout(
d.findObject(                           	d.manage_zmi_prefs(
d.followNextHopIps(                     	d.meta_type
d.fullRRDPath(                          	d.meta_types
d.get(                                  	d.modelerLock
d.getAdministrativeRoles(               	d.monitor
d.getAqChainForUserCommands(            	d.monitorDevice(
d.getAttribute(                         	d.monitors(
d.getAttributeNode(                     	d.moveMeBetweenRels(
d.getAttributes(                        	d.moveObject(
d.getAvailableTemplates(                	d.name(
d.getBreadCrumbName(                    	d.objectIds(
d.getBreadCrumbUrlPath(                 	d.objectIds_d(
d.getChildNodes(                        	d.objectItems(
d.getCreatedTimeString(                 	d.objectItems_d(
d.getDataForJSON(                       	d.objectMap(
d.getDataSourceOptions(                 	d.objectMap_d(
d.getDefaultGraphDefs(                  	d.objectValues(
d.getDeviceClassName(                   	d.objectValues_d(
d.getDeviceClassPath(                   	d.os(
d.getDeviceComponents(                  	d.owner_info(
d.getDeviceComponentsNoIndexGen(        	d.pastSnmpMaxFailures(
d.getDeviceGroupNames(                  	d.path(
d.getDeviceIp(                          	d.perfServer(
d.getDeviceIpAddress(                   	d.permission_settings(
d.getDeviceLink(                        	d.permissionsOfRole(
d.getDeviceMacaddress(                  	d.portal_type
d.getDeviceName(                        	d.possible_permissions(
d.getDeviceUrl(                         	d.preMWProductionState
d.getDmd(                               	d.prepId(
d.getDmdKey(                            	d.primaryAq(
d.getDmdObj(                            	d.primarySortKey(
d.getDmdRoot(                           	d.priority
d.getElementsByTagName(                 	d.productionState
d.getEventDetail(                       	d.propdict(
d.getEventDetailFromStatusOrHistory(    	d.propertyDescription(
d.getEventHistory(                      	d.propertyIds(
d.getEventManager(                      	d.propertyItems(
d.getEventOwnerList(                    	d.propertyLabel(
d.getEventSummary(                      	d.propertyMap(
d.getExpandedLinks(                     	d.propertyValues(
d.getFirstChild(                        	d.propertysheets
d.getGraphDef(                          	d.pushConfig(
d.getGraphDefUrl(                       	d.rackSlot
d.getHTMLEventSummary(                  	d.redirectToUserCommands(
d.getHWManufacturerName(                	d.reindex_all(
d.getHWProductClass(                    	d.relationshipManagerPathRestriction
d.getHWProductKey(                      	d.removeLocalRRDTemplate(
d.getHWProductName(                     	d.removeRelation(
d.getHWSerialNumber(                    	d.removeZDeviceTemplates(
d.getHWTag(                             	d.rename(
d.getHierarchyObj(                      	d.renameDevice(
d.getIconPath(                          	d.renameDeviceInEvents(
d.getId(                                	d.renameDeviceInPerformance(
d.getIdLink(                            	d.restrictedTraverse(
d.getLastChange(                        	d.rolesOfPermission(
d.getLastChangeString(                  	d.rrdPath(
d.getLastChild(                         	d.saveCustProperties(
d.getLastPollSnmpUpTime(                	d.saveZenProperties(
d.getLinks(                             	d.security
d.getLocationLink(                      	d.selectedRoles
d.getLocationName(                      	d.sendEventWhenBlocked(
d.getMaintenanceWindows(                	d.sendEventWhenBlockedFlag
d.getManageInterface(                   	d.sendEventWhenResultBlocked(
d.getManageIp(                          	d.setAdminLocalRoles(
d.getManageIpObj(                       	d.setGroups(
d.getMenus(                             	d.setHWProduct(
d.getModificationTimeString(            	d.setHWProductKey(
d.getMonitoredComponents(               	d.setHWSerialNumber(
d.getNetworkRoot(                       	d.setHWTag(
d.getNextLockableParent(                	d.setLastChange(
d.getNextSibling(                       	d.setLastPollSnmpUpTime(
d.getNodeName(                          	d.setLocation(
d.getNodeType(                          	d.setManageIp(
d.getNodeValue(                         	d.setOSProduct(
d.getNonLoopbackIpAddresses(            	d.setOSProductKey(
d.getNowString(                         	d.setPerformanceMonitor(
d.getOSManufacturerName(                	d.setPriority(
d.getOSProcessMatchers(                 	d.setProdState(
d.getOSProductKey(                      	d.setProductInfo(
d.getOSProductName(                     	d.setSendEventWhenBlockedFlag(
d.getObjByPath(                         	d.setSiteManager(
d.getOverriddenObjects(                 	d.setSnmpLastCollection(
d.getOwner(                             	d.setSystems(
d.getOwnerDocument(                     	d.setTerminalServer(
d.getOwnerTuple(                        	d.setTitle(
d.getParentNode(                        	d.setZenProperty(
d.getPeerDeviceClassNames(              	d.smallRolesWidget
d.getPerformanceServer(                 	d.snmpAgeCheck(
d.getPerformanceServerName(             	d.snmpAgent
d.getPhysicalPath(                      	d.snmpContact
d.getPhysicalRoot(                      	d.snmpDescr
d.getPingStatus(                        	d.snmpIgnore(
d.getPingStatusNumber(                  	d.snmpLocation
d.getPingStatusString(                  	d.snmpMonitorDevice(
d.getPrettyLink(                        	d.snmpOid
d.getPreviousSibling(                   	d.snmpSysName
d.getPrimaryDmdId(                      	d.snmpindex
d.getPrimaryId(                         	d.sub_meta_types
d.getPrimaryParent(                     	d.superValues(
d.getPrimaryPath(                       	d.sysUpTime(
d.getPrimaryUrlPath(                    	d.sysedgeLicenseMode
d.getPriority(                          	d.systems(
d.getPriorityString(                    	d.tabs_path_default(
d.getProdState(                         	d.tabs_path_info(
d.getProductionStateString(             	d.this(
d.getProperty(                          	d.title
d.getPropertyType(                      	d.titleOrId(
d.getRRDContextData(                    	d.title_and_id(
d.getRRDDataPoint(                      	d.title_or_id(
d.getRRDDataPoints(                     	d.todayDate(
d.getRRDFileName(                       	d.tpURL(
d.getRRDNames(                          	d.tpValues(
d.getRRDPaths(                          	d.traceRoute(
d.getRRDSum(                            	d.undoable_transactions(
d.getRRDTemplate(                       	d.unindex_ips(
d.getRRDTemplateByName(                 	d.unindex_object(
d.getRRDTemplateName(                   	d.unlock(
d.getRRDTemplates(                      	d.unrestrictedTraverse(
d.getRRDValue(                          	d.unsetSendEventWhenBlockedFlag(
d.getRRDValues(                         	d.upToOrganizerBreadCrumbs(
d.getRelationshipManagerId(             	d.updateDevice(
d.getRelationshipNames(                 	d.updateProcesses(
d.getRelationships(                     	d.uptimeStr(
d.getReportableComponents(              	d.urlLink(
d.getSiteManager(                       	d.userCanTakeOwnership(
d.getSnmpConnInfo(                      	d.userCommands(
d.getSnmpLastCollection(                	d.userdefined_roles(
d.getSnmpLastCollectionString(          	d.users_with_local_role(
d.getSnmpStatus(                        	d.validClipData(
d.getSnmpStatusNumber(                  	d.validRoles(
d.getSnmpStatusString(                  	d.valid_property_id(
d.getStatus(                            	d.valid_roles(
d.getStatusCssClass(                    	d.validate_roles(
d.getStatusImgSrc(                      	d.values(
d.getStatusString(                      	d.view(
d.getSubObjects(                        	d.viewName(
d.getSystemNames(                       	d.virtual_url_path(
d.getSystemNamesString(                 	d.visibleCustPropertyMap(
d.getTagName(                           	d.write(
d.getThresholdInstances(                	d.yesterdayDate(
d.getThresholds(                        	d.zCollectorClientTimeout
d.getTreeItems(                         	d.zCollectorDecoding
d.getUnusedId(                          	d.zCollectorPlugins
d.getUrlForUserCommands(                	d.zCommandCommandTimeout
d.getUserCommand(                       	d.zCommandExistanceTest
d.getUserCommandEnvironment(            	d.zCommandLoginTimeout
d.getUserCommandIds(                    	d.zCommandLoginTries
d.getUserCommandTargets(                	d.zCommandPassword
d.getUserCommands(                      	d.zCommandPath
d.getWrappedOwner(                      	d.zCommandPort
d.getXMLEdges(                          	d.zCommandProtocol
d.getZ(                                 	d.zCommandSearchPath
d.getZenRootNode(                       	d.zCommandUsername
d.getZopeObj(                           	d.zDeviceTemplates
d.get_local_roles(                      	d.zFileSystemMapIgnoreNames
d.get_local_roles_for_userid(           	d.zFileSystemMapIgnoreTypes
d.get_request_var_or_attr(              	d.zFileSystemSizeOffset
d.get_valid_userids(                    	d.zHardDiskMapMatch
d.groups(                               	d.zIcon
d.hasChildNodes(                        	d.zIfDescription
d.hasObject(                            	d.zInterfaceMapIgnoreNames
d.hasProperty(                          	d.zInterfaceMapIgnoreTypes
d.has_local_roles(                      	d.zIpServiceMapMaxPort
d.has_order_support                     	d.zKeyPath
d.helpLink(                             	d.zLinks
d.hw(                                   	d.zLocalInterfaceNames
d.icon                                  	d.zLocalIpAddresses
d.id                                    	d.zMaxOIDPerRequest
d.index_html                            	d.zMySqlPassword
d.index_object(                         	d.zMySqlUsername
d.ipAddressAsInt(                       	d.zPingMonitorIgnore
d.isAnObjectManager                     	d.zProdStateThreshold
d.isInTree                              	d.zPythonClass
d.isLocal(                              	d.zRouteMapCollectOnlyIndirect
d.isLocalName(                          	d.zRouteMapCollectOnlyLocal
d.isLockedFromDeletion(                 	d.zRouteMapMaxRoutes
d.isLockedFromUpdates(                  	d.zSnmpAuthPassword
d.isPrincipiaFolderish                  	d.zSnmpAuthType
d.isResultLockedFromDeletion(           	d.zSnmpCommunities
d.isResultLockedFromUpdates(            	d.zSnmpCommunity
d.isTempDevice(                         	d.zSnmpEngineId
d.isTopLevelPrincipiaApplicationObject  	d.zSnmpMonitorIgnore
d.isUnlocked(                           	d.zSnmpPort
d.items(                                	d.zSnmpPrivPassword
d.keys(                                 	d.zSnmpPrivType
d.listDAVObjects(                       	d.zSnmpSecurityName
d.list_imports(                         	d.zSnmpTimeout
d.location(                             	d.zSnmpTries
d.lockFromDeletion(                     	d.zSnmpVer
d.lockFromUpdates(                      	d.zStatusConnectTimeout
d.lockStatus(                           	d.zSysedgeDiskMapIgnoreNames
d.lockWarning(                          	d.zTelnetEnable
d.lookupSchema(                         	d.zTelnetEnableRegex
d.maintenanceWindows(                   	d.zTelnetLoginRegex
d.makeLocalRRDTemplate(                 	d.zTelnetPasswordRegex
d.manage(                               	d.zTelnetPromptTimeout
d.manageIp                              	d.zTelnetSuccessRegexList
d.manage_CopyContainerAllItems(         	d.zTelnetTermLength
d.manage_CopyContainerFirstItem(        	d.zWinEventlog
d.manage_DAVget(                        	d.zWinEventlogMinSeverity
d.manage_FTPlist(                       	d.zWinPassword
d.manage_FTPstat(                       	d.zWinUser
d.manage_UndoForm(                      	d.zWmiMonitorIgnore
d.manage_access(                        	d.zenPropIsPassword(
d.manage_ackBatchEvents(                	d.zenPropertyIds(
d.manage_ackEvents(                     	d.zenPropertyItems(
d.manage_addAdministrativeRole(         	d.zenPropertyMap(
d.manage_addDTMLDocument(               	d.zenPropertyOptions(
d.manage_addDTMLMethod(                 	d.zenPropertyPath(
d.manage_addDocument(                   	d.zenPropertyString(
d.manage_addFile(                       	d.zenScreenUrl(
d.manage_addFolder(                     	d.zenpathjoin(
d.manage_addImage(                      	d.zenpathsplit(
d.manage_addItemsToZenMenu(             	d.zentinelTabs(
d.manage_addLocalRoles(                 	d.zmanage_addProperty(
d.manage_addLogMessage(                 	d.zmanage_delObjects(
d.manage_addMaintenanceWindow(          	d.zmanage_delProperties(
d.manage_addOrderedFolder(              	d.zmanage_editProperties(
d.manage_addProduct                     	d.zmanage_exportObject(
d.manage_addProperty(                   	d.zmanage_importObject(
d.manage_addRelation(                   	d.zmanage_importObjects(
d.manage_addSiteRoot(                   	d.zope_quick_start(
Written on January 8th, 2012 , Informative

I had a PS/2 keyboard that broke on me and the thought occurred to me that it might be nice to have a PS/2 extension cable for those other keyboards that have short cables (sooo many keyboards like this…).

 

Matching the wires to the pinouts

This was the only unknown part. I stripped back the cut end of the cable to the wires and got my multimeter out. Now, when I looked up the pinouts, there is a +5V, a CLK, a data, and a ground connection. The +5V I can determine by plugging the cable into a PC and checking, but the others you would need an oscilloscope for. Because there is already an end on the cable though, we can just use the continuity tester and verify the pinouts that way. Clip to a wire, then check each pin on the other end. Match that pin against the picture and you will know what that wire is supposed to be (actually, you don’t need to know what it is, you just need the pin number to wire it up the same way). Also note that the shield (ring) carries -5V. The colors in each cable DO vary somewhat so I haven’t even bothered to print what my results were.


Pin Function
1 Data
2 (reserved)
3 Ground
4 +5V
5 Clock
6 (reserved)

 

 

 

Soldering the pins

On the keyboard end we have a male connector so I purchased a female PS/2 connector. The end we solder onto though is the back of the female, which is actually male. I printed off the above diagrams and marked the paper diagram with the colors that were supposed to go on the pin to make it easier. When I was done, I tested this, it worked (yay). I poured some glue into the holder to act as insulation on the wires and now I have an extension cord. Camera phones suck for this kind of work so one of the shots is blurry but I find it’s the only device I’m willing to use to take photos for a blog as I usually have it on my and I don’t need a cable to transfer the photos.

 

My wire colors

Front view (cover not fitted)

 

Written on September 26th, 2011 , Informative

I was converting an online time tracking sheet to an Openoffice Calc spread sheet and ran into this problem. Converting time to decimal wasn’t much of a problem – it is well documented and there are a couple of methods to do it. However, getting around the fact that Calc uses a wrapping 24 hour clock took a bit more effort. If you enter a time of: 25:00 for 25 hours, it will wrap this and display 01:00. If you base any calculation on this field, it will use the 1hr result, not the 25. Getting around this requires reformatting the cell to use the Time format [HH]:MM (i.e. wrapping the HH section is square brackets). This is not a selectable option, and must be manually entered.

Making this change will cause the cell format to display correctly as 25:00, but Calc will still use a value of 1hr for any calculations you base off this cell. None of the time functions allow you to convert a time value to number of seconds, number of minutes, or number of hours, so it is not possible to fully convert this number. The trick to getting Calc to acknowledge more than 24 hours in a calculation is to take that value and divide it by 24. You see, Calc stores time formats internally as the number of days. So 25:00 is actually stored by Calc as the value 1 and 1/24 (in decimal of course). By multiplying any time value by 24, we convert it to a decimal number, and because we use the internal format of number of days, it does not wrap. Even 366 days should still be represented as 366 days, so this should never wrap. You formula becomes:

=H1*24

Where H1 is the cell storing the time value. You can include this formula inside another formula to make further calculations on the 24hr+ time.

Written on February 24th, 2011 , Informative

This is a real snapshot of a dev Virtualmin server we had running at work showing the quota usage of a domain:

98.25 MB (98.02 MB by server administrator, 10 MB by mail / FTP users)

The above is accessed from the System Information, clicking on a domain, and exposing the Quota and Limits section. It is obviously not correct! But why?

The first insight into Virtualmin quotas is that they are based on the underlying system / user quotas. This is true. But it is not the end of it. It is also based on group quotas.

If you have a domain, testing.com, virtualmin will create the user ‘testing’ and group ‘testing’ for this domain. Imagine you also create an email user ‘test1@testing.com’. Now, depending on the user name scheme you have selected, this can result in the user ‘test1@testing.com’ being created on the underlying OS.

If you create a 10MB file as root, in the home directory for testing, it will not show in any quota listing for that domain / users of that domain. This is because according to the underlying OS quotas, those users have not increased their disk usage – it is just a file that root has placed into their home directory.

Now, chown the file to the user ‘testing’. The quota usage for the user ‘testing’ will increase, but the quota usage for the domain will not. On the surface this doesn’t make sense: the sum of the quota usage of all users defined in that domain should be the total usage for that domain. Yes, except Virtualmin does not calculate the usage this way. It relies on the fact that the group ID for ever user in the domain is the same and thus it can just pull the quota details for the group. The result is that, with shell access or a badly written program, it is possible to have a user go over quota without the domain itself going over quota.

This concept can also be exploited in the event that you want a user to have a larger possible quota than the domain allows for instance. The user quotas make complete sense to me, the reason for the incorrect quota for the domain took me a little longer to figure out so hopefully this helps someone else.

Written on February 12th, 2011 , Informative

I used ZenOSS back in the 2.x days and found that the SSH modeling was too clunky – it didn’t detect very much unless one went about doing it manually. I’ve been wanting to try version 3 for a while, but it took a little while for the VMWare image to come out. I tried it out this week and was impressed, but disappointed when I tried to login to the local console to poke around. All the information I could find on the web said that the default root password was blank. Well it’s not – at least not in the 3.03 image. I have no idea what it is either. The simplest way to go about resetting it is to boot into single user mode, which will drop you to a root prompt without the password prompt where you can reset it. To do this:

1. When booting, press enter at the boot selection screen

2. There is only a single entry so press ‘e’ to edit it.

3. Move to the second line where the kernel path is written and press ‘e’ to edit it

4. Append the word ‘single’ to the end of the line and press enter to save

5. Press ‘b’ to boot

You will be dropped to a root prompt where you can just type ‘passwd’ to reset the root password.

Written on January 14th, 2011 , Informative

I bought a new phone (HTC Legend / Android 2.1) to replace my aging iPhone 3G (yay). It took me 3 solid days of research and testing to figure out how to get it to sync between my Mac and Zimbra (blah). Here’s what I finally settled on.

Zimbra Open Source Edition supports open standards for syncing contacts (cardDAV) and calendars (calDAV). Unfortunately, as is often the case with “open” standards, there is still limited support for these: Thunderbird, an opensource email program still doesn’t support cardDAV. For all the complaining open source advocates do about closed source standards, it’s pretty weak that they take forever to comply with those standards are open. Support for MS Office Open XML really gets me down; I find every other office system to be fundamentally flawed because no one implements this open standard properly. Honestly, I don’t really care for open source, I care about quality end-use products with good development API’s.

Anyway I digress. The problem is that Mac OS X Leopard’s AddressBook doesn’t support cardDAV. iCal does support calDAV though. Next, the HTC Legend (Android 2.1) has no support for cardDAV or cardDAV. Again, an entire OS is open source and doesn’t support open sync standards that have been around for years. Android doesn’t even support SyncML out of the box. So, the open standards don’t help much. Now, there is (one, ONLY ONE) app on the Android market (Calendar Sync) to support calDAV and since Leopard supports calDAV, we can sync calendars fine. Easy, except the app config gave me some trouble, but that’s just the result of being new to a system :)

Ok so on to contacts. Looking in the addressbook configuration for Leopard, it has an option to sync to Google. Part of the point of a groupware server is that data is centralised there, but since the Zimbra iSync connector requires a licensed version of their software. The free Appliance version will work, but I can’t get the VMDK’s to work in VirtualBox and I despise VMWare Server Edition. Actually, if you have the Appliance version of Zimbra, this whole point becomes moot, because it supports ActiveSync to Android and iSync to Mac ;)

So endeavoring to use Google as a middle ground for syncing, I check that box. There aren’t really any other options other than login details. So I add some contacts and wait. They don’t appear on Google straight away. They don’t appear after an hour. Or after 24 hours. Ok so what went wrong? Oh, Apple forgot to mention that the sync isn’t automatic: It happens when you sync your iTunes device (iPod, iPad, iPhone). You don’t have one? Well, you are unworthy of getting assistance from Apple to sync your addressbook to Google then. Actually, there is a well known hack to get this to work, but I don’t like having to hack commercial software. Commercial software has a tendency to detect the hack and undo it without letting you know this has occurred :/

Ok so syncing Addressbook to Google won’t work. You could use SpanningSync actually, if you want to buy a license. It does work quite well. Even if we did that though, how do we get the data back to Zimbra? Google is supposed to be just a middle man, not the authority on the data. The ONLY way I could find to do this is to install a Funambol server and use the connectors available. Actually, they have an Android connector too, which makes syncing really easy. The Funambol server simply acts as a gateway to the Zimbra data. Unfortunately, the Zimbra connector for Funambol seems to be unmaintained, and most of the documentation on getting this to work is via the forums. Sounds like hit and miss to me. Plus, I didn’t want to have to install another service onto the Zimbra server. It’s more to maintain, more to learn, more to break!

I had the idea of using this program available for Android called LVContacts. Sync the data between the Mac and the Phone, and then let LVContacts sync it back to Zimbra. I bought this app and discovered that it only does 1-way syncs: It will download contacts from the Zimbra server, but not update them on the server when you have added new contacts to the phone. Not helpful, especially given that the official site for the app doesn’t say anything about this.

So, the only way I could find of syncing contacts between Zimbra and the Mac was using a Thunderbird extension called Zindus. I was initially just looking for an EMail app that supported cardDAV and read / write access to the mac Addressbook. I couldn’t find one. After messing with Thunderbird, I found that it provides read-only access to the Mac Addressbook. Also, Zindus won’t sync the imported addresses to Zimbra, even after renaming the Mac OS Addressbook group in Thunderbird to zindus/Mac.

The result of this is that I couldn’t find a way to sync my Mac Addressbook with Zimbra. So I had to rethink my strategy and involve using Thunderbird as my main email application. I only use the Addressbook for emailing people and looking up a phone number when I want to dial out with a landline anyway. There is no other external integration with other apps. In this respect I am lucky.

Thunderbird also has an extension called Lightning which is a calendar application. It does support calDAV and so will sync to the Zimbra server directly. Thus, I can work in Thunderbird exclusively and know what my data will be synced to Zimbra.

Ok, now back to getting the contacts on to the Android phone. SyncMate requires a Google account to sync to the Legend, so that just adds another level of complexity to this process. Mark / Space’s The Missing Sync will only sync the Mac Addressbook, which will miss all the contacts I am managing in Thunderbird. So, we come back to using Google as the middle man. Zindus will sync out to Google and Zimbra at the same time. I.e. when a contact is added to Zimbra, it will add it to the Google account. When a contact is added to Google, it will sync it to the Zimbra account. This completes our sync triangle.

What we have now looks like this:

And gives us a complete Over-The-Air sync solution for free, with Zimbra OSE still being the authority on data. Oh how painful (but free) open source can be. Don’t get me wrong though, proprietary software isn’t the answer. I mean, why is it easier for people to pirate Microsoft Windows than it is to use the licensed version? Really, pirate versions don’t make you phone Microsoft when you replace the mainboard just because the system ID changes. At least I know that no matter whether an organization adopts an open source philosophy or a proprietary systems approach, I will still have a job in IT!

Written on December 2nd, 2010 , Informative

I was going to title this “Unlocking the iPhone 3GS 3.1.3″ and then I realised that there are a billion posts out there like that, and there doesn’t seem to be a one-size-fits-all answer to this. So, here’s what worked on mine.

1. Grab a copy of Spirit (has Mac and Win versions)

2. Make sure you have already activated your iPhone (i.e. turned it on and synched to iTunes and you are able to register with the cellphone network)

3. Connect the iPhone and run Spirit, hit Jailbreak

4. Install Ulstrasn0w and you have unlocked the iPhone :)

NOTE: I’ve discovered and confirmed Ultrasn0w doesn’t work with baseband 05.12.01 yet.

The difficulty for me with the 3GS was that the older methods of unlocking it didn’t work for me, because I have a native 3.1.3 model…which has intermittent success depending on the actual model number. Spirit worked though.

Written on May 21st, 2010 , Informative

I had a power outage the other night and it looks like one of my VirtualBox virtual images got a little corrupt and it’s UUID changed. This isn’t espcially a problem, but VirtualBox identifies images by the UUID and therefore refused to start the VM this is attached to throwing the error:

UUID {b6e58671-d821-4dba-b723-f12defc2650a} of the medium ‘/home/admin1/vimages/zen.vdi’ does not match the value {c14b3de3-78c8-40a1-8106-badd0e0fb9c2} stored in the media registry (‘/home/admin1/.VirtualBox/VirtualBox.xml’)

I hacked the VirtualBox.xml file to reflect the new UUID but it still gave me the same error. I guess VirtualBox must cache it somewhere.

I ran:

VBoxManage internalcommands setuuid “/home/admin1/vimages/zen.vdi”

Which said it ran successfully, but then gave me the same error when I tried to start the VM. Weird. Cloning the VDI also fails with the same message, so I can’t generate a new virtual image from this one either.

I have in fact had this issue when using the Mac version of VirtualBox, and I removed the image from the HD listing and re-added it, forcing VirtualBox to accept the new UUID of the image. Unfortunately, I couldn’t find in the manual how to perform this step on the command line. Simly detaching and reattaching the media does not force VirtualBox to change the media registry.

Eventually after molesting Google to broaden my search way beyond my error message (effectively looking at everyone who had UUID errors in VirtualBox!) I came accross the unregisterimage command. Intuitively I discovered there is an identical reverse command called registerimage. These commands control the media library from the command line. They appear to be compeltely undocumented in the VirtualBox Manual. It’s quite stupid really, they should be in the same section where the GUI describes how to do this.
A quick detachment of the drive from my VM:

VBoxManage storageattach zen –storagectl “IDE Controller” –port 0 –device 0 –medium none

Followed by resetting the image registration:

VBoxManage unregister “/home/admin1/vimages/ubuntu.vdi”
VBoxManage register “/home/admin1/vimages/ubuntu.vdi”

And re-attaching the drive:

VBoxManage storageattach zen –storagectl “IDE Controller” –port 0 –device 0 –type hdd –medium “/home/admin1/vimages/ubuntu.vdi”

And all was good!

UPDATE 11th OCT 2011: This won’t work in Virtualbox 4.x as they changed the commands. I cannot see any VBoxManage command to take the place of the register / unregister commands and I have resorted to using PHPVirtualBox to do this as it has a media manager built in but still allows me to run the server headless.

Written on March 25th, 2010 , Informative

When my Samsung CLP-300N failed, I had about $200 worth of new unused toner sitting around and so I bought a 2nd hand CLP-300 (the network version is rare and so prohibitively expensive). This worked ok for about another 6 months, but before I can even change the toner, the black imager is dying again. So I investigated sub $500 color laser printers, and I found that the Dell is one of the cheapest capital expenditures while still giving good quality. I think this is because they sell the toner with the imaging unit, which makes the toner about $100 per color, very expensive. However, it should prolong the printer. I saw these on special at $180 from Dell’s site and picked one up last month. I hadn’t set it up because of the shift though. Now, in the new place, in a hurry to print something, I unboxed it and set it up, only to find that:

1) Mac OS 10.5.8 does not support the printer natively

2) The driver disc Dell included includes only the electonic version of the manual, in about 10 languages, in the Mac OS mount partition (obviously the Windows drivers are on the Windows partition).

Googling tells me there is no driver, and to use a Fujixerox driver that uses the same electronics, and so will print, but will not give any options. Great. I couldn’t even find the driver they were talking about. However, dispelling these myths and the myths of Dell’s lack of support for Mac OS X, they do indeed have a Mac OS X driver on their site. And it’s just the driver – 550kb download or so. The application has been split. I like this. It works perfectly now. Thanks Dell! :D

Written on February 22nd, 2010 , Informative

I have just had to write a web application that links to the local file system (NFS actually) to open a directory that stores common business files in FireFox 3. It doesn’t allow it. I found many sites saying this, but not offering any real helpful workaround. Mozilla is quite clear about this fact, and the appropriate work around:

For security purposes, Mozilla applications block links to local files (and directories) from remote files. This includes linking to files on your hard drive, on mapped network drives, and accessible via Uniform Naming Convention (UNC) paths.

http://kb.mozillazine.org/Links_to_local_pages_do_not_work

The solution is to alter the security settings for the site in question, with the exact settings shown above. Note that the settings do not require using the user.js / prefs.js file and can be enabled in about:config, although doing that on many computers might be a drag!

Written on February 10th, 2010 , Informative

SirSpanky.com – The Secret Diary of James Pearce Aged 20-Something is proudly powered by WordPress and the Theme Adventure by Eric Schwarz
Entries (RSS) and Comments (RSS).

SirSpanky.com – The Secret Diary of James Pearce Aged 20-Something

Personal jorunal of a professional geek – James Pearce in Perth, Australia