Changeset 1796

Show
Ignore:
Timestamp:
02/22/07 01:42:57 (2 years ago)
Author:
abaumann
Message:

* specify (hardcoded, at least for now) capabilities
* start updating to new internal XML format, unresolved issues are:

  • RRULE handling is totally different now and not working
  • same for Exception date/rule handling

the code still contains debug printfs and is barely tested

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • plugins/moto-sync/motosync.py

    r1793 r1796  
    4747# object types supported by this plugin 
    4848SUPPORTED_OBJTYPES = ['event', 'contact'] 
     49 
     50CAPABILITIES = """<?xml version="1.0"?> 
     51<capabilities> 
     52    <contact> 
     53        <Address /> 
     54        <Birthday /> 
     55        <Categories /> 
     56        <EMail /> 
     57        <FormattedName /> 
     58        <Name /> 
     59        <Nickname /> 
     60        <Telephone /> 
     61    </contact> 
     62    <event> 
     63        <Summary /> 
     64        <DateStarted /> 
     65        <DateEnd /> 
     66        <Duration /> 
     67        <Alarm /> 
     68        <RecurrenceRule /> 
     69        <ExceptionDateTime /> 
     70    </event> 
     71</capabilities> 
     72""" 
    4973 
    5074# my phone doesn't like it if you read more than this many entries at a time 
     
    79103] 
    80104 
    81 # mapping from phone's contact type to vcard number types 
    82 MOTO_CONTACT_TYPES = { 
    83     0: 'work', 
    84     1: 'home', 
    85     2: 'voice', 
    86     3: 'cell', 
    87     4: 'fax', 
    88     5: 'pager', 
    89     11: 'voice' # shows up as "other", seen on a RAZR V3x 
     105# mapping from phone's contact type to XML number types 
     106MOTO_PHONE_CONTACT_TYPES = { 
     107    2: 'Voice', 
     108    3: 'Cellular', 
     109    4: 'Fax', 
     110    5: 'Pager', 
     111    11: 'Voice' # shows up as "other", seen on a RAZR V3x 
     112
     113 
     114# as above, but to TelephoneLocation 
     115MOTO_PHONE_CONTACT_LOCATIONS = { 
     116    0: 'Work', 
     117    1: 'Home' 
    90118} 
    91119 
    92120# reverse of the above (almost): mapping from vcard to phone's contact type 
    93121VCARD_CONTACT_TYPES = { 
    94     'work':  0, 
    95     'home':  1, 
    96     'voice': 2, 
    97     'cell': 3, 
    98     'car':   3, 
    99     'pcs':   3
    100     'fax':   4, 
    101     'pager': 5, 
     122    'Work':     0, 
     123    'Home':     1, 
     124    'Voice':    2, 
     125    'Cellular': 3, 
     126    'Car':      3, 
     127    'Message':  5
     128    'Fax':      4, 
     129    'Pager':    5, 
    102130} 
    103131 
     
    105133# can also have dom/intl/postal/parcel... these don't really make sense here 
    106134VCARD_ADDRESS_TYPES = { 
    107     'work':  0, 
    108     'home':  1, 
     135    'Work':  0, 
     136    'Home':  1, 
    109137} 
    110138 
    111139# reverse of the above 
    112140MOTO_ADDRESS_TYPES = { 
    113     0: 'work', 
    114     1: 'home', 
     141    0: 'Work', 
     142    1: 'Home', 
    115143} 
    116144 
     
    139167XML_NAME_PARTS = 'Prefix FirstName Additional LastName Suffix'.split() 
    140168XML_ADDRESS_PARTS = ('Street ExtendedAddress' 
    141                      + ' City Region PostalCode Country').split() 
     169                     + ' Locality Region PostalCode Country').split() 
    142170 
    143171# legal characters in telephone numbers 
     
    264292    """ 
    265293     
     294    # XXX FIXME: whole function needs reworkign for new XML format 
     295    return (MOTO_REPEAT_NONE, []) 
     296     
    266297    # can't support multiple rules 
    267298    if len(rulenodes) != 1: 
     
    271302    # build hash of rule parts 
    272303    rules = {} 
    273     for rule in map(getXMLText, rulenode.getElementsByTagName('Rule'))
    274         key, val = rule.split('=', 1
    275         key = key.lower() 
     304    for node in rulenode.childNodes
     305        key = node.nodeName.lower(
     306        val = getXMLText(node).lower() 
    276307        if key[:1] == 'by': 
    277308            val = set(val.split(',')) 
     
    279310 
    280311    # extract the parts 
    281     assert(rules.has_key('freq')) # required by RFC2445 
    282     freq = rules['freq'].lower() 
     312    assert(rules.has_key('content')) # required 
     313    freq = rules['content'].lower() 
    283314    bymonth = rules.get('bymonth') 
    284315    byweekno = rules.get('byweekno') 
     
    335366 
    336367    # recombine the rule parts into a single string, and parse into an rruleset 
    337     rulestr = ';'.join(map(getXMLText, rulenode.getElementsByTagName('Rule'))) 
    338     ruleset = dateutil.rrule.rrulestr(rulestr, dtstart=eventdt, forceset=True) 
     368    # XXX FIXME: totally different rrule format 
     369    # rulestr = ';'.join(map(getXMLText, rulenode.getElementsByTagName('Rule'))) 
     370    # ruleset = dateutil.rrule.rrulestr(rulestr, dtstart=eventdt, forceset=True) 
    339371 
    340372    # are there any future occurrences of this event? 
     
    348380    # add in the exception dates and rules (if any) 
    349381    for node in exdates: 
    350         ruleset.exdate(dateutil.parser.parse(getXMLField(node, 'Content'))) 
    351     for node in exrules: 
    352         ruleset.exrule(dateutil.rrule.rrulestr(getXMLField(node, 'Content'))) 
     382        for e in getElementsByTagNames(node, 'Content'): 
     383            ruleset.exdate(dateutil.parser.parse(getXMLText(e))) 
     384 
     385    # XXX FIXME: totally different rrule format 
     386    #for node in exrules: 
     387    #    ruleset.exrule(dateutil.rrule.rrulestr(getXMLField(node, 'Content'))) 
    353388 
    354389    # are there any future occurrences of this event if we consider exceptions? 
     
    878913        """Returns OpenSync XML representation of this event.""" 
    879914        impl = xml.dom.minidom.getDOMImplementation() 
    880         doc = impl.createDocument(None, 'vcal', None) 
    881         top = doc.createElement('Event') 
    882         doc.documentElement.appendChild(top) 
     915        doc = impl.createDocument(None, 'event', None) 
     916        top = doc.documentElement 
    883917 
    884918        e = doc.createElement('Summary') 
     
    891925        else: 
    892926            dtstart = self.eventdt.strftime(VCAL_DATE) 
    893             appendXMLChild(doc, e, 'Value', 'DATE') 
     927            e.setAttribute('DateValue', 'DATE') 
    894928        appendXMLChild(doc, e, 'Content', dtstart) 
    895929        top.appendChild(e) 
     
    901935        else: 
    902936            dtend = endtime.strftime(VCAL_DATE) 
    903             appendXMLChild(doc, e, 'Value', 'DATE') 
     937            e.setAttribute('DateValue', 'DATE') 
    904938        appendXMLChild(doc, e, 'Content', dtend) 
    905939        top.appendChild(e) 
     
    908942            alarm = doc.createElement('Alarm') 
    909943            appendXMLChild(doc, alarm, 'AlarmAction', 'DISPLAY') 
    910             appendXMLChild(doc, alarm, 'AlarmDescription', self.name) 
     944            e = doc.createElement('AlarmDescription') 
     945            appendXMLChild(doc, e, 'Content', self.name) 
     946            alarm.appendChild(e) 
    911947            alarmtime = self.alarmdt.strftime(VCAL_DATETIME) 
    912948            appendXMLChild(doc, alarm, 'AlarmTrigger', alarmtime) 
     
    915951        e = doc.createElement('RecurrenceRule') 
    916952        if self.repeat_type == MOTO_REPEAT_DAILY: 
    917             appendXMLChild(doc, e, 'Rule', 'FREQ=DAILY') 
     953            appendXMLChild(doc, e, 'Content', 'DAILY') 
    918954        elif self.repeat_type == MOTO_REPEAT_WEEKLY: 
    919             appendXMLChild(doc, e, 'Rule', 'FREQ=WEEKLY') 
     955            appendXMLChild(doc, e, 'Content', 'WEEKLY') 
    920956        elif self.repeat_type == MOTO_REPEAT_MONTHLY_DATE: 
    921             appendXMLChild(doc, e, 'Rule', 'FREQ=MONTHLY') 
    922             appendXMLChild(doc, e, 'Rule', 'BYMONTHDAY=%d' % self.eventdt.day
     957            appendXMLChild(doc, e, 'Content', 'MONTHLY') 
     958            appendXMLChild(doc, e, 'ByMonthDay', str(self.eventdt.day)
    923959        elif self.repeat_type == MOTO_REPEAT_MONTHLY_DAY: 
    924             appendXMLChild(doc, e, 'Rule', 'FREQ=MONTHLY') 
     960            appendXMLChild(doc, e, 'Content', 'MONTHLY') 
    925961            day = VCAL_DAYS[self.eventdt.weekday()] 
    926962            # compute the week number that the event falls in 
     
    929965            else: 
    930966                weeknum = self.eventdt.day / 7 + 1 
    931             appendXMLChild(doc, e, 'Rule', 'BYDAY=%d%s' % (weeknum, day)) 
     967            appendXMLChild(doc, e, 'ByDay', '%d%s' % (weeknum, day)) 
    932968        elif self.repeat_type == MOTO_REPEAT_YEARLY: 
    933             appendXMLChild(doc, e, 'Rule', 'FREQ=YEARLY') 
    934             appendXMLChild(doc, e, 'Rule', 'BYMONTH=%d' % self.eventdt.month
    935             appendXMLChild(doc, e, 'Rule', 'BYMONTHDAY=%d' % self.eventdt.day
     969            appendXMLChild(doc, e, 'Content', 'YEARLY') 
     970            appendXMLChild(doc, e, 'ByMonth', str(self.eventdt.month)
     971            appendXMLChild(doc, e, 'ByMonthDay', str(self.eventdt.day)
    936972 
    937973        if e.hasChildNodes(): 
     
    963999            # work out which dates the exceptions correspond to and 
    9641000            # generate ExceptionDate nodes for them 
     1001            e = doc.createElement('ExceptionDateTime') 
     1002            e.setAttribute('DateValue', 'DATE') 
    9651003            for exnum in self.exceptions: 
    966                 e = doc.createElement('ExclusionDate') 
    9671004                appendXMLChild(doc, e, 'Content', 
    9681005                               format_time(rrule[exnum], VCAL_DATE)) 
    969                 appendXMLChild(doc, e, 'Value', 'DATE') 
     1006            if e.hasChildNodes(): 
    9701007                top.appendChild(e) 
    9711008 
     
    10141051        PhoneEvent.__init__(self) 
    10151052        doc = xml.dom.minidom.parseString(data) 
    1016         event = doc.getElementsByTagName('Event')[0] 
     1053        event = doc.getElementsByTagName('event')[0] 
    10171054 
    10181055        def getField(tagname, subtag='Content'): 
     
    10271064            raise UnsupportedDataError('Event is too old') 
    10281065 
    1029         durationstr = getField('Duration') 
    1030         if durationstr != '': 
    1031             self.duration = parse_ical_duration(durationstr) 
     1066        if event.getElementsByTagName('Duration') != []: 
     1067            duration = event.getElementsByTagName('Duration')[0] 
     1068            def tryint(s): 
     1069                if s == '': 
     1070                    return 0 
     1071                else: 
     1072                    return int(s) 
     1073            weeks = tryint(getXMLField(duration, 'Weeks')) 
     1074            days = tryint(getXMLField(duration, 'Days')) 
     1075            hours = tryint(getXMLField(duration, 'Hours')) 
     1076            mins = tryint(getXMLField(duration, 'Minutes')) 
     1077            secs = tryint(getXMLField(duration, 'Seconds')) 
     1078            self.duration = datetime.timedelta(weeks * 7 + days, (hours * 60 + mins) * 60 + secs) 
    10321079        else: 
    10331080            endstr = getField('DateEnd') 
     
    10591106 
    10601107        rrules = event.getElementsByTagName('RecurrenceRule') 
    1061         exdates = event.getElementsByTagName('ExclusionDate') 
    1062         exrules = event.getElementsByTagName('ExclusionRule') 
     1108        exdates = event.getElementsByTagName('ExceptionDateTime') 
     1109        exrules = event.getElementsByTagName('ExceptionRule') 
    10631110        (self.repeat_type, self.exceptions) = convert_rrule(rrules, exdates, 
    10641111                                                          exrules, self.eventdt) 
     
    12561303        PhoneContact.__init__(self) 
    12571304        doc = xml.dom.minidom.parseString(data) 
     1305        contact = doc.getElementsByTagName('contact')[0] 
    12581306 
    12591307        def getField(tagname, subtag='Content'): 
    12601308            """utility function for the XML processing below""" 
    1261             return getXMLField(doc, tagname, subtag) 
     1309            return getXMLField(contact, tagname, subtag) 
    12621310 
    12631311        # handle the name and formatted name fields 
     
    13061354                # filter out any illegal characters from the phone number 
    13071355                content = filter(lambda c: c in TEL_NUM_DIGITS, content) 
    1308                 ical_types = [getXMLText(e).lower() 
    1309                               for e in elt.getElementsByTagName('Type')] 
    1310                 is_pref = 'pref' in ical_types 
     1356                ical_types = elt.getAttribute('Type').split(';') 
     1357                is_pref = elt.hasAttribute('Preferred') and elt.getAttribute('Preferred') in ['1', 'true'] 
    13111358                moto_type = MOTO_CONTACT_DEFAULT 
    13121359                for t in ical_types: 
     
    13381385        for adr in doc.getElementsByTagName('Address'): 
    13391386            address = [getXMLField(adr, p) for p in XML_ADDRESS_PARTS] 
    1340             ical_types = [getXMLText(e).lower() for e in  
    1341                           adr.getElementsByTagName('Type')] 
     1387            ical_types = adr.getAttribute('Location').split(';') 
    13421388            for t in ical_types: 
    13431389                if VCARD_ADDRESS_TYPES.has_key(t): 
     
    14311477        else: 
    14321478            e = doc.createElement('Telephone') 
    1433             appendXMLChild(doc, e, 'Type', 
    1434                            MOTO_CONTACT_TYPES[self.contacttype].upper()) 
     1479            if MOTO_PHONE_CONTACT_TYPES.has_key(self.contacttype): 
     1480                e.setAttribute('Type', MOTO_PHONE_CONTACT_TYPES[self.contacttype]) 
     1481            elif MOTO_PHONE_CONTACT_LOCATIONS.has_key(self.contacttype): 
     1482                e.setAttribute('Location', MOTO_PHONE_CONTACT_LOCATIONS[self.contacttype]) 
    14351483            if self.primaryflag: 
    1436                 appendXMLChild(doc, e, 'Type', 'PREF'
     1484                e.setAttribute('Preferred', "1"
    14371485        appendXMLChild(doc, e, 'Content', self.contact) 
    14381486        ret.append(e) 
     
    14441492            if e.hasChildNodes(): 
    14451493                if MOTO_ADDRESS_TYPES.has_key(self.contacttype): 
    1446                     appendXMLChild(doc, e, 'Type', 
     1494                    e.setAttribute('Location', 
    14471495                                   MOTO_ADDRESS_TYPES[self.contacttype].upper()) 
    14481496                ret.append(e) 
     
    15841632            else: 
    15851633                xmldata = entry.to_xml() 
     1634            print xmldata 
    15861635            data = opensync.Data(xmldata, self.objformats[objtype]) 
    15871636            data.objtype = objtype 
     
    17521801            raise opensync.Error('unsupported objtype %s' % change.objtype, 
    17531802                                 opensync.ERROR_NOT_SUPPORTED) 
     1803        if change.changetype != opensync.CHANGE_TYPE_DELETED: 
     1804            print "\nOpenSync wants me to write:\n", change.data.data 
    17541805        if change.changetype == opensync.CHANGE_TYPE_DELETED: 
    17551806            success = (self.access.uid_seen(change.uid) 
     
    18051856    version.modelversion = str(comms.read_model()) 
    18061857    version.identifier = str(comms.read_serial()) 
    1807     # FIXME: discover and set capabilities 
    18081858    comms.disconnect() 
    18091859    info.version = version 
     1860    info.capabilities = opensync.capabilities_parse(CAPABILITIES) 
    18101861 
    18111862    # for now, all objtypes are supported on all devices