PyXR

c:\projects\bitpim\src \ phones \ com_samsungspha840_telus.py



0001 ### BITPIM
0002 ###
0003 ### Copyright (C) 2006 Denis Tonn <denis@tonn.ca>
0004 ### Inspiration and code liberally adopted from:
0005 ### Stephen A. Wood and Joe Pham
0006 ###
0007 ### This program is free software; you can redistribute it and/or modify
0008 ### it under the terms of the BitPim license as detailed in the LICENSE file.
0009 ###
0010 ### $Id$
0011 
0012 """Communicate with a Samsung SPH-A840 from Telus Canada"""
0013 
0014 # Notes: 
0015 #
0016 # This Phone does not cleanly return from BREW mode, so everything is
0017 # done through modem mode. 
0018 #
0019 # Groups are handled differently on this phone, so I have hard coded
0020 # them. In any event, there is no way to query them as part of a
0021 # PBentry. Restoring data to a phone loses group assignments.  
0022 # at#pbgrw does not modify group names - seems to be ignored in phone
0023 # even though it returns OK.   
0024 #
0025 # Cannot query/extract Ringtones so that is hard coded. Built in tones
0026 # are ok and can be changed through BitPim.
0027 #
0028 # Cannot query/extract Wallpaper so builtin values are hardcoded and
0029 # everything else is maintained through a write to phone  
0030 #
0031 # Special case email and url fields. If these are blank they MUST have
0032 # a quoted space in the write or phone data is corrupted.
0033 #
0034 # uslot 1 should not be used. I have not done anything in this code to
0035 # prevent it, but the phone will complain if you try and edit a
0036 # pbentry with uslot = 1. Change the "location" on the phone and it's
0037 # fine.
0038 #
0039 # There is no way of setting (or unsetting) a "secret" pbentry on this
0040 # phone.
0041 # 
0042 # Calendar writes fail (ERROR) unless start_time and end_time are the
0043 # same. 
0044 #
0045 # Occasionally the phone will have position 0 as the speeddial number,
0046 # when it has only one number even when that number isn't in position
0047 # 0.
0048 #
0049 
0050 import time
0051 import datetime
0052 
0053 import sha
0054 import re
0055 import struct
0056 
0057 import bpcalendar
0058 import prototypes
0059 import todo
0060 import memo
0061 
0062 import common
0063 import commport
0064 import p_brew
0065 import p_samsungspha840_telus
0066 import com_brew
0067 import com_phone
0068 import com_samsung_packet
0069 import helpids
0070 
0071 numbertypetab=('home','office','cell','pager','fax')
0072 
0073 
0074 ### Phone class 
0075 
0076 parentphone=com_samsung_packet.Phone
0077 class Phone(parentphone):
0078     "Talk to a Samsung SPH-A840 phone (Telus)"
0079 
0080     __read_timeout=0.5
0081     __cal_end_datetime_value=None
0082     __cal_alarm_values={0: -1, 1: 0, 2: 10, 3: 30, 4: 60 }
0083     __cal_max_name_len=32
0084     _cal_max_events_per_day=5
0085 
0086     desc="SPH-A840 (Telus)"
0087     helpid=helpids.ID_PHONE_SAMSUNGOTHERS
0088     protocolclass=p_samsungspha840_telus
0089     serialsname='spha840T'
0090     
0091     builtin_ringtones=(
0092         (0, ['Default Tone']),
0093         (1, ['Ring %02d'%x for x in range(1, 6)]),
0094         (6, ['Melody %02d'%x for x in range(1, 6)]),
0095         )
0096 
0097 # wallpaper values 
0098 # 8 = no image
0099 # 3 = human  1-20
0100 # 4 = animal 1-15
0101 # 5 = others 1-10
0102 # 2 = gallery - and wallpaper_pic_path points to the file name
0103 # 7 = image clips 
0104 
0105 # wallpaper_modifier   
0106 # selects specific image in human, animal, others
0107 # selects offset in file for image clips
0108 # must be 0 if no image
0109 # value ignored if gallery image
0110 
0111     builtin_pictures=(
0112         (0, ['Human %02d'%x for x in range(1, 21)]),
0113         (30, ['Animal %02d'%x for x in range(1, 16)]),
0114         (60, ['Other %02d'%x for x in range(1, 11)]),
0115         (80, ['On Phone Image']),
0116         )
0117 
0118     def __init__(self, logtarget, commport):
0119         com_samsung_packet.Phone.__init__(self, logtarget, commport)
0120         self.numbertypetab=numbertypetab
0121         self.mode=self.MODENONE
0122 
0123     def getfundamentals(self, results):
0124         """Gets information fundamental to interoperating with the phone and UI."""
0125     # use a hash of ESN and other stuff (being paranoid)
0126         self.log("Retrieving fundamental phone information")
0127         self.log("Phone serial number")
0128         self.setmode(self.MODEMODEM)
0129         results['uniqueserial']=sha.new(self.get_esn()).hexdigest()
0130     # getting ringtone-index
0131         self.log("Setting up Built in Ring Tone index")
0132         results['ringtone-index']=self._get_builtin_index(self.builtin_ringtones)
0133     # getting wallpaper-index
0134         self.log("Setting up Built in Wallpaper index")
0135         results['wallpaper-index']=self.get_wallpaper_index()
0136         self.log("Ignoring Corrupted Phone group information")
0137     # groups are hard coded since this phone corrupts the read of groups
0138         results['groups']=self.read_groups()
0139         self.log("Fundamentals retrieved")
0140         return results
0141         
0142     def _get_builtin_index(self, builtin_list):
0143         _res={}
0144         for _starting_idx,_list in builtin_list:
0145             _idx=_starting_idx
0146             for _entry in _list:
0147                 _res[_idx]={ 'name': _entry,
0148                              'origin': 'builtin' }
0149                 _idx+=1
0150         return _res
0151 
0152     def get_wallpaper_index(self):
0153         _res=self._get_builtin_index(self.builtin_pictures)
0154         return _res
0155 
0156     def pblinerepair(self, line):
0157         "Extend incomplete lines"
0158         nfields=24                      # Can we get this from packet def?
0159         ncommas=self.countcommas(line)
0160         if ncommas<0:                   # Un terminated quote
0161             line+='"'
0162             ncommas = -ncommas
0163         if nfields-ncommas>1:
0164             line=line+","*(nfields-ncommas-1)
0165         return line
0166 
0167     def countcommas(self, line):
0168         inquote=False
0169         ncommas=0
0170         for c in line:
0171             if c == '"':
0172                 inquote = not inquote
0173             elif not inquote and c == ',':
0174                 ncommas+=1
0175         if inquote:
0176             ncommas = -ncommas
0177         return ncommas
0178         
0179     def savewallpapers(self, result):
0180         raise NotImplementedError()
0181 
0182     def saveringtones(self, result):
0183         raise NotImplementedError()
0184         
0185     def getringtones(self, results):
0186         raise NotImplementedError()
0187         
0188     def getwallpapers(self, results):
0189         raise NotImplementedError()
0190 
0191     def read_groups(self):
0192   # This phone returns crap for group names which causes an assertion error in the database
0193   # because of duplicate "blank" names in the groups. 
0194   # so to bypass I have set the group names manually
0195         g={}
0196         g[0]={'name': "Friends"}
0197         g[1]={'name': "Business"}
0198         g[2]={'name': "Family"}
0199         g[3]={'name': "General"}
0200         g[4]={'name': "No Group"}
0201         return g
0202 
0203 
0204     def savegroups(self, data):
0205         """This phone doesn't save or read groups properly
0206         so we are skipping the save"""
0207         return
0208 
0209 
0210 
0211 #
0212 #
0213 # Called by extractphonebookentry to extract wallpaper from phone entry data 
0214 #
0215 #
0216     def _extract_wallpaper(self, res, entry, fundamentals):
0217 # wallpaper values 
0218 # 8 = no image
0219 # 3 = human  1-20 res index 1-20
0220 # 4 = animal 1-15 res index 30-45
0221 # 5 = others 1-10 res index 60-70
0222 # 2 = gallery - and wallpaper_pic_path points to the file name
0223 # 6 or 7 = image clips - modifier selects offset in image file
0224 # 1 = I assume downloaded - never downloaded a wallpaper
0225 # gallery and images and downloads are treated separately as index 80
0226 #   - save just keeps whatever wallpaper data the phone already has and is not managed by bitpim
0227 
0228 # wallpaper_modifier   
0229 # selects specific image in human, animal, others
0230 # selects offset in file for image clips
0231 # must be 0 if no image
0232 # value ignored if gallery image file name
0233         _wp_index=fundamentals.get('wallpaper-index', {})
0234         if entry.wallpaper==8:
0235             return # no image  
0236         if entry.wallpaper in (0,1,2,6,7):
0237             wallpaper_index=80  # use "on phone" dict entry name in bitpim and recycle current phone data
0238         if entry.wallpaper==3:
0239             wallpaper_index=entry.wallpaper_modifier
0240         if entry.wallpaper==4:
0241             wallpaper_index=30+entry.wallpaper_modifier
0242         if entry.wallpaper==5:
0243             wallpaper_index=60+entry.wallpaper_modifier
0244    # get the name out of the dict  
0245         _wp_name=_wp_index.get(wallpaper_index, {}).get('name', None)
0246         if _wp_name:
0247             res['wallpapers']=[{ 'wallpaper': _wp_name,  'use': 'call' }]
0248 
0249 #
0250 #
0251 # Called by extractphonebookentry to extract ringtone from phone entry data 
0252 #
0253 #
0254     def _extract_ringtone(self, res, entry, fundamentals):
0255         _rt_index=fundamentals.get('ringtone-index', {})
0256         _rt_name=_rt_index.get(entry.ringtone, {}).get('name', None)
0257         if _rt_name:
0258             res['ringtones']=[{ 'ringtone': _rt_name, 'use': 'call' }]
0259 
0260 #
0261 #
0262 # Called by getphonebook to extract single phone entry data 
0263 #
0264 #
0265     def extractphonebookentry(self, entry, fundamentals):
0266         res={}
0267         res['serials']=[ {'sourcetype': self.serialsname,
0268                           'slot': entry.slot,
0269                           'sourceuniqueid': fundamentals['uniqueserial']} ]
0270     # only one name
0271         res['names']=[ {'full': entry.name} ]
0272     # only one category
0273         cat=fundamentals['groups'].get(entry.group, {'name': "Unassigned"})['name']
0274         if cat!="Unassigned":
0275             res['categories']=[ {'category': cat} ]
0276     # only one email
0277         if len(entry.email):
0278             res['emails']=[ {'email': entry.email} ]
0279     # only one url
0280         if len(entry.url):
0281             res['urls']=[ {'url': entry.url} ]
0282         res['numbers']=[]
0283         secret=0
0284         speeddialtype=entry.speeddial
0285         speeddial_has_been_set=0 # need this for fix for bad phonebook data
0286         numberindex=0
0287         for type in self.numbertypetab:
0288             if len(entry.numbers[numberindex].number):
0289                 numhash={'number': entry.numbers[numberindex].number, 'type': type }
0290 #                if entry.numbers[numberindex].secret==1:
0291 #                    secret=1
0292                 self.log("ENTRY -speeddial : "+str(speeddialtype)+" -index : "+str(numberindex)+" -uslot : "+str(entry.slot))
0293            # fix possible bad phone data - always force dial entry to first number as safety measure
0294            # Otherwise we will lose the uslot data completely
0295                 if speeddial_has_been_set==0:
0296                     numhash['speeddial']=entry.uslot
0297                     speeddial_has_been_set=1
0298                 if speeddialtype==numberindex:
0299                     numhash['speeddial']=entry.uslot
0300                     speeddial_has_been_set=1
0301                 self.log("EXIT -speeddial : "+str(speeddialtype)+" -index : "+str(numberindex)+" -uslot : "+str(entry.slot))
0302                 res['numbers'].append(numhash)
0303             numberindex+=1
0304 
0305     # Field after each number is secret flag.  Setting secret on
0306     # phone sets secret flag for every defined phone number
0307         res['flags']=[ {'secret': secret} ]
0308         _args=(res, entry, fundamentals)
0309         self._extract_wallpaper(*_args)
0310         self._extract_ringtone(*_args)
0311         return res
0312 
0313 #
0314 #
0315 # Get the phone book
0316 #
0317 #
0318     def getphonebook(self, result):
0319         """Read the phonebook data."""
0320         pbook={}
0321         self.setmode(self.MODEPHONEBOOK)
0322 
0323         count=0
0324         req=self.protocolclass.phonebookslotrequest()
0325         lastname=""
0326         for slot in range(1,self.protocolclass.NUMPHONEBOOKENTRIES+1):
0327             req.slot=slot
0328             res=self.sendpbcommand(req, self.protocolclass.phonebookslotresponse, fixup=self.pblinerepair)
0329             if len(res) > 0:
0330                 lastname=res[0].entry.name
0331                 if len(lastname)>0: 
0332                    self.log(`slot`+": "+lastname+" uSlot : "+str(res[0].entry.uslot))
0333                 entry=self.extractphonebookentry(res[0].entry, result)
0334                 pbook[count]=entry
0335                 count+=1
0336             self.progress(slot, self.protocolclass.NUMPHONEBOOKENTRIES, lastname)
0337         result['phonebook']=pbook
0338         cats=[]
0339         for i in result['groups']:
0340             if result['groups'][i]['name']!='Unassigned':
0341                 cats.append(result['groups'][i]['name'])
0342         result['categories']=cats
0343         self.setmode(self.MODEMODEM)
0344         return pbook
0345 
0346 #
0347 #
0348 # Called by savephonebook to create an initial phone book entry
0349 #
0350 #
0351     def makeentry(self, entry, data):
0352         e=self.protocolclass.pbentry()
0353         for k in entry:
0354          # special treatment for lists
0355             if k=='numbertypes' or k=='secrets':
0356                 continue
0357          # get a phone index for the ring tone name
0358             if k=='ringtone':
0359                 _rt_index=data.get('ringtone-index', {})
0360                 for rgt in _rt_index.keys():
0361                   _rt_name=_rt_index.get(rgt, {}).get('name', None)
0362                   if _rt_name==entry['ringtone']:
0363                       e.ringtone=rgt # and save it for the phonebook entry 
0364                 continue
0365         # get a a pair of indexs for the wallpaper name - wallpaper and wallpaper_modifier
0366             elif k=='wallpaper':
0367         # setup default values - no image
0368                 e.wallpaper=8
0369                 e.wallpaper_modifier=0
0370                 e.wallpaper_file=""
0371         # now see if we have anything stored in the database
0372                 _wp_index=data.get('wallpaper-index', {})
0373                 for wpn in _wp_index.keys():
0374                     _wp_name=_wp_index.get(wpn, {}).get('name', None)
0375                     if _wp_name==entry['wallpaper']: # found the name, now convert to a pair of phone indexes
0376                          if wpn<30:                   # built in Human type, modifier is wpn
0377                              e.wallpaper=3
0378                              e.wallpaper_modifier=wpn
0379                          if wpn>29 and wpn<60:        # built in Animals type, modifier is wpn-30
0380                              e.wallpaper=4
0381                              e.wallpaper_modifier=wpn-30
0382                          if wpn>59 and wpn<80:        # built in Others type, modifier is wpn-60
0383                              e.wallpaper=5
0384                              e.wallpaper_modifier=wpn-60
0385                          if wpn==80:                   # on phone - special processing in caller code
0386                              e.wallpaper=8
0387                              e.wallpaper_modifier=8   # will not be stored on phone just a sig
0388                 continue
0389             elif k=='numbers':
0390                 for numberindex in range(self.protocolclass.NUMPHONENUMBERS):
0391                     enpn=self.protocolclass.phonenumber()
0392                     e.numbers.append(enpn)
0393                 for i in range(len(entry[k])):
0394                     numberindex=entry['numbertypes'][i]
0395                     e.numbers[numberindex].number=entry[k][i]
0396 #                    e.numbers[numberindex].secret=entry['secrets'][i]
0397                     e.numbers[numberindex].secret=0
0398                 continue
0399           # everything else we just set
0400             setattr(e, k, entry[k])
0401 
0402         return e
0403 
0404 #
0405 #
0406 # Save the phone book
0407 #
0408 #
0409     def savephonebook(self, data):
0410         "Saves out the phonebook"
0411 
0412         pb=data['phonebook']
0413         keys=pb.keys()
0414         keys.sort()
0415         keys=keys[:self.protocolclass.NUMPHONEBOOKENTRIES]
0416 
0417         self.setmode(self.MODEPHONEBOOK)
0418   # 1- Read the existing phonebook so that we cache birthday field and wallpaper file path and stuff
0419   # 2- Erase all entries. 
0420         uslots={}
0421         names={}
0422         birthdays={}
0423         wallpaper_s={}
0424         wallpaper_files={}
0425         wallpaper_modifiers={}
0426         req=self.protocolclass.phonebookslotrequest()
0427 
0428         self.log('Erasing '+self.desc+' phonebook')
0429         progressmax=self.protocolclass.NUMPHONEBOOKENTRIES+len(keys)
0430         for slot in range(1,self.protocolclass.NUMPHONEBOOKENTRIES+1):
0431             req.slot=slot
0432             self.progress(slot,progressmax,"Erasing  "+`slot`)
0433             try:
0434                 res=self.sendpbcommand(req,self.protocolclass.phonebookslotresponse, fixup=self.pblinerepair)
0435                 if len(res) > 0:
0436                     self.log("Starting capture data for : "+res[0].entry.name)
0437                     names[slot]=res[0].entry.name
0438                     birthdays[slot]=res[0].entry.birthday
0439                     wallpaper_s[slot]=res[0].entry.wallpaper
0440                     wallpaper_files[slot]=res[0].entry.wallpaper_file
0441                     wallpaper_modifiers[slot]=res[0].entry.wallpaper_modifier
0442                     self.log("Captured data for : "+res[0].entry.name)
0443                     self.log("User Slot from phone: "+str(res[0].entry.uslot))
0444                 else:
0445                     names[slot]=""
0446             except:
0447                 names[slot]=""
0448                 self.log("Slot "+`slot`+" Empty slot or read failed")
0449             reqerase=self.protocolclass.phonebooksloterase()
0450             reqerase.slot=slot
0451             self.sendpbcommand(reqerase, self.protocolclass.phonebookslotupdateresponse)
0452   # Skip this.. the group save commands don't work
0453   #      self.savegroups(data)
0454 
0455         for i in range(len(keys)):
0456             slot=keys[i]
0457             req=self.protocolclass.phonebookslotupdaterequest()
0458             req.entry=self.makeentry(pb[slot],data)
0459   # groups are not handled through the phonebook data on this phone
0460             req.entry.group=self.protocolclass.DEFAULT_GROUP 
0461 
0462   # force a single space into email and url if they are zero length
0463             if len(req.entry.email)==0:
0464                 req.entry.email=" "
0465             if len(req.entry.url)==0: 
0466                 req.entry.url=" "
0467   # restore the stuff we may not have in the database
0468             if names[slot]==req.entry.name:
0469                 req.entry.birthday=birthdays[slot] # no analogy on bitpim database, just keep with entry
0470             # test for internal sig and keep whatever wallpaper is already on the phone
0471                 if req.entry.wallpaper==self.protocolclass.DEFAULT_WALLPAPER and req.entry.wallpaper_modifier==8: # yup, keep previous stuff
0472                      req.entry.wallpaper=wallpaper_s[slot]
0473                      req.entry.wallpaper_file=wallpaper_files[slot]
0474                      req.entry.wallpaper_modifier=wallpaper_modifiers[slot]
0475   # make sure the default wallpaper has no modifier applied
0476             if req.entry.wallpaper==self.protocolclass.DEFAULT_WALLPAPER:  
0477                 req.entry.wallpaper_modifier=self.protocolclass.DEFAULT_WALLPAPER_MODIFIER
0478             self.log('Writing entry '+`slot`+" - "+req.entry.name+" uSlot : "+str(req.entry.uslot))
0479             self.log('Request: '+str(req))
0480             self.progress(i+self.protocolclass.NUMPHONEBOOKENTRIES,progressmax,"Writing "+req.entry.name)
0481             self.sendpbcommand(req, self.protocolclass.phonebookslotupdateresponse)
0482         self.progress(progressmax+1,progressmax+1, "Phone book write completed")
0483         self.setmode(self.MODEMODEM)
0484         return data
0485 #
0486 #
0487 # Get the phone Calendar
0488 #
0489 #
0490     def getcalendar(self, result):
0491         entries = {}
0492         self.log("Getting calendar entries")
0493         self.setmode(self.MODEPHONEBOOK)
0494         req=self.protocolclass.eventrequest()
0495         cal_cnt=0
0496         for slot in range(self.protocolclass.NUMCALENDAREVENTS):
0497             req.slot=slot
0498             res=self.sendpbcommand(req,self.protocolclass.eventresponse)
0499             if len(res) > 0:
0500                 self.progress(slot+1, self.protocolclass.NUMCALENDAREVENTS,
0501                               res[0].eventname)
0502                 # build a calendar entry
0503                 entry=bpcalendar.CalendarEntry()
0504                 # start time date
0505                 entry.start=res[0].start[0:5]
0506                 if res[0].end:
0507                     # valid end time
0508                     entry.end=res[0].start[0:5]
0509                 else:
0510                     entry.end=entry.start
0511                 # description
0512                 entry.description=res[0].eventname
0513                 try:
0514                     alarm=self.__cal_alarm_values[res[0].alarm]
0515                 except:
0516                     alarm=None
0517                 entry.alarm=alarm
0518                 # update calendar dict
0519                 entries[entry.id]=entry
0520                 cal_cnt += 1
0521         result['calendar']=entries
0522         self.setmode(self.MODEMODEM)
0523         return result
0524 
0525 #
0526 #
0527 # Save the phone Calendar
0528 #
0529 #
0530     def savecalendar(self, dict, merge):
0531         self.log("Sending calendar entries")
0532         cal=self.process_calendar(dict['calendar'])
0533         # testing
0534         if __debug__:
0535             print 'processed calendar: ', len(cal), ' items'
0536             for c in cal:
0537                 print c.description,':', c.start
0538         self.setmode(self.MODEPHONEBOOK)
0539         self.log("Saving calendar entries")
0540         cal_cnt=0
0541         req=self.protocolclass.eventupdaterequest()
0542         l = self.protocolclass.NUMCALENDAREVENTS
0543         for c in cal:
0544       # Save this entry to phone
0545             # self.log('Item %d' %k)
0546       # pos
0547             req.slot=cal_cnt
0548       # start date time
0549             # print "Start ",c.start
0550             req.start=list(c.start)+[0]
0551       # end date time must be the same as start time for this phone write
0552             req.end=req.start
0553       # time stamp
0554             req.timestamp=list(time.localtime(time.time())[0:6])
0555             # print "Alarm ",c.alarm
0556             req.alarm=c.alarm
0557       # Name, check for bad char & proper length
0558             # name=c.description.replace('"', '')
0559             name=c.description
0560             if len(name)>self.__cal_max_name_len:
0561                 name=name[:self.__cal_max_name_len]
0562             req.eventname=name
0563       # and save it
0564             self.progress(cal_cnt+1, l, "Updating "+name)
0565             self.sendpbcommand(req,self.protocolclass.eventupdateresponse)
0566             cal_cnt += 1
0567       # delete the rest of the calendar slots
0568         self.log('Deleting unused entries')
0569         for k in range(cal_cnt, l):
0570             self.progress(k, l, "Deleting entry %d" % k)
0571             reqerase=self.protocolclass.eventsloterase()
0572             reqerase.slot=k
0573             self.sendpbcommand(reqerase, self.protocolclass.eventupdateresponse)
0574         self.setmode(self.MODEMODEM)
0575 
0576         return dict
0577 
0578 #### Profile class 
0579  
0580 parentprofile=com_samsung_packet.Profile
0581 class Profile(parentprofile):
0582     deviceclasses=("modem",)
0583 
0584     BP_Calendar_Version=3
0585     protocolclass=Phone.protocolclass
0586     serialsname=Phone.serialsname
0587     phone_manufacturer='SAMSUNG ELECTRONICS CO.,LTD.'
0588     phone_model='SCH-A850 /180'
0589 
0590     def __init__(self):
0591         parentprofile.__init__(self)
0592         self.numbertypetab=numbertypetab
0593         
0594     _supportedsyncs=(
0595         ('phonebook', 'read', None),  # all phonebook reading
0596         ('phonebook', 'write', 'OVERWRITE'),  # only overwriting phonebook
0597         ('calendar', 'read', None),   # all calendar reading
0598         ('calendar', 'write', 'OVERWRITE')   # only overwriting calendar
0599         )
0600 
0601     # fill in the list of ringtone/sound origins on your phone
0602     ringtoneorigins=('ringers')
0603     #e.g.
0604     #ringtoneorigins=('ringers', 'sounds')
0605 
0606 class Samsung_Calendar:
0607     _cal_alarm_values={
0608         10: 2, 30: 3, 60: 4, -1: 0, 0: 1 }
0609     
0610     def __init__(self, calendar_entry, new_date=None):
0611         self._start=self._end=self._alarm=self._desc=None
0612         self._extract_cal_info(calendar_entry, new_date)
0613 
0614     def _extract_cal_info(self, cal_entry, new_date):
0615         s=cal_entry.start
0616         if new_date is not None:
0617             s=new_date[:3]+s[3:]
0618         self._start=s
0619         self._end=cal_entry.end
0620         self._desc=cal_entry.description
0621     # approximate the alarm value
0622         self._alarm=0
0623         alarm=cal_entry.alarm
0624         _keys=self._cal_alarm_values.keys()
0625         _keys.sort()
0626         _keys.reverse()
0627         for k in _keys:
0628             if alarm>=k:
0629                 self._alarm=self._cal_alarm_values[k]
0630                 break
0631 
0632     def __lt__(self, rhs):
0633         return self.start<rhs.start
0634     def __le__(self, rhs):
0635         return self.start<=rhs.start
0636     def __eq__(self, rhs):
0637         return self.start==rhs.start
0638     def __ne__(self, rhs):
0639         return self.start!=rhs.start
0640     def __gt__(self, rhs):
0641         return self.start>rhs.start
0642     def __ge__(self, rhs):
0643         return self.start>=rhs.start
0644     
0645     def _get_start(self):
0646         return self._start
0647     start=property(fget=_get_start)
0648 
0649     def _get_end(self):
0650         return self._end
0651     end=property(fget=_get_end)
0652 
0653     def _get_desc(self):
0654         return self._desc
0655     description=property(fget=_get_desc)
0656 
0657     def _get_alarm(self):
0658         return self._alarm
0659     alarm=property(fget=_get_alarm)
0660 

Generated by PyXR 0.9.4