o
    l>jE                     @   s   U d Z ddlZddlZddlZddlmZmZ ddlmZ ddlm	Z	m
Z
mZmZ ddlmZ ddlmZmZmZ ddlmZ dd	lmZ d
Zeed< eeZejed< dZeed< 	dde de
dej!de"ddf
ddZ#G dd deZ$G dd dZ%dS )zFind my iPhone service.    N)datetime	timedelta)MappingProxyType)AnyCallableIteratorOptional)Response)PyiCloudAuthRequiredExceptionPyiCloudNoDevicesExceptionPyiCloudServiceUnavailable)BaseService)PyiCloudSessionz
US/Pacific_FMIP_CLIENT_CONTEXT_TIMEZONE_LOGGER   _MAX_REFRESH_RETRIESFintervalfunc
stop_eventlocatereturnc              
   C   s   t  t| d }|j| dsE|t  k r=z|| W n ty3 } ztd| W Y d}~nd}~ww t  t| d }|j| drdS dS )z:Thread function to monitor the FindMyiPhoneServiceManager.)seconds)timeoutz%FindMyiPhone monitor thread error: %sN)r   nowr   wait	Exceptionr   debug)r   r   r   r   
next_eventexc r    S/home/thesage/.local/lib/python3.10/site-packages/pyicloud/services/findmyiphone.py_monitor_thread   s   r"   c                       s6  e Zd ZdZ		d,dedededeeef dedB d	df fd
dZ	d-de
de
d	dfddZde
d	dfddZd.ddZde
d	dfddZd/de
d	dfddZdeeB d	dfddZd	efddZd	efdd Zd	ed fd!d"Zd	efd#d$Zed	e
fd%d&Zed0d(d)Zed	eeeef  fd*d+Z  ZS )1FindMyiPhoneServiceManagerzThe 'Find my iPhone' iCloud service

    This connects to iCloud and return phone data including the near-realtime
    latitude and longitude.
    FNservice_roottoken_endpointsessionparamsrefresh_intervalr   c                    s   t  ||| || _|dur|nd| _| d}| d| _| d| _| d| _| d| _| d| _| d	| _	| d
| _
i | _g | _d| _d| _d| _t | _| jdd dS )z*Initialize the FindMyiPhoneServiceManager.Ng     r@z/fmipservice/client/webz/initClientz/refreshClientz
/playSoundz/sendMessagez/lostDevicez/remoteWipeWithUserAuthz/fmipWebAuthenticateTr   )super__init___with_family_refresh_interval_fmip_init_url_fmip_refresh_url_fmip_sound_url_fmip_message_url_fmip_lost_url_fmip_erase_url_erase_token_url_devices_devices_names_server_ctx
_user_info_monitor	threadingEventr   _refresh_client_with_reauth)selfr$   r%   r&   r'   with_familyr(   fmip_endpoint	__class__r    r!   r+   .   s&   


z#FindMyiPhoneServiceManager.__init__r   retryc                 C   s   | j   z| j|d W n& ty3   |du r td d| _| jjj	dd | j
|dd Y dS w | j|d |   dS )z
        Refreshes the FindMyiPhoneService endpoint with re-authentication.
        This ensures that the location data is up-to-date.
        r)   TzRe-authenticating sessionN)force_refresh)r   rB   )r   set_refresh_clientr
   r   r   r7   r&   serviceauthenticater<   _initialize_devices_start_monitor_thread)r=   r   rB   r    r    r!   r<   P   s   

z6FindMyiPhoneServiceManager._refresh_client_with_reauthc                 C   s   d}t  }| jrT| jrT| jddrT|tk rTdd | jdi  D }|s'n-||kr2td| n"|}t	d | j
|d	 |d
7 }| jrT| jrT| jddrT|tk s| jsZt tdt| j dS )z;Initializes the devices for the FindMyiPhoneServiceManager.r   
hasMembersFc                 S   s"   h | ]\}}| d dkr|qS )deviceFetchStatusLOADING)get).0kvr    r    r!   	<setcomp>x   s
    zAFindMyiPhoneServiceManager._initialize_devices.<locals>.<setcomp>membersInfoz>No progress on LOADING family members after retry %d, stoppingg?r)      zNumber of devices found: %dN)rD   r,   r8   rM   r   itemsr   r   timesleeprE   r5   r   infolen)r=   r   retriesprev_loading_keysloading_keysr    r    r!   rH   g   sD   	
z.FindMyiPhoneServiceManager._initialize_devicesc                 C   sB   | j stjt| j| j| jddd| _| j  | j	  dS dS )z=Starts the monitor thread for the FindMyiPhoneServiceManager.)r   r   r   T)targetkwargsdaemonN)
is_aliver:   Threadr"   rE   r-   r   r9   clearstartr=   r    r    r!   rI      s   
	z0FindMyiPhoneServiceManager._start_monitor_threadc                 C   s@  ddddd| j tddi}| jr%| j|d< |r%d	|d
< |d d	dd | jj| jr.| jn| j| j|d}|	 }|
d| _| jrMd| jv rMd| jd< |
d| _d|vr^td dS tdt|d  |d D ])}|d }|| jvrt|| j| | j| j| j| j| jd| j|< ql| j| | qlt| j | _dS )zx
        Refreshes the FindMyiPhoneService endpoint, this ensures that the location data
        is up-to-date.
        clientContextziCloud Find (Web)z2.0z3.0rS   r   )appName
appVersion
apiVersiondeviceListVersionfmlytimezoneinactiveTimeserverContextTisUpdatingAllLocationsall)shouldLocateselectedDevice)urlr'   json	theftLossNuserInfocontentzFMIP returned 0 deviceszFMIP returned %d devicesid)manager	sound_urllost_urlmessage_url	erase_urlerase_token_url)r,   r   r7   updater&   postr/   r.   r'   rr   rM   r8   r   r   rX   r5   AppleDevicer0   r2   r1   r3   r4   listkeysr6   )r=   r   req_jsonreqrespdevice_info	device_idr    r    r!   rE      s`   



z*FindMyiPhoneServiceManager._refresh_clientTc                 C   s   | j |d dS )z:Public method to refresh the FindMyiPhoneService endpoint.r)   N)r<   )r=   r   r    r    r!   refresh   s   z"FindMyiPhoneServiceManager.refreshkeyr   c                 C   s0   | j s	| jdd t|tr| j| }| j| S )zGets a device by name or index.Tr)   )r_   r<   
isinstanceintr6   r5   r=   r   r    r    r!   __getitem__   s
   


z&FindMyiPhoneServiceManager.__getitem__c                 C   s   | j  S )z%String representation of the devices.)r5   rc   r    r    r!   __str__   s   z"FindMyiPhoneServiceManager.__str__c                 C   s   |  S )Representation of the device.r    rc   r    r    r!   __repr__   s   z#FindMyiPhoneServiceManager.__repr__c                 C   s    | j s	| jdd t| j S )zIterates over the devices.Tr)   )r_   r<   iterr5   valuesrc   r    r    r!   __iter__   s   z#FindMyiPhoneServiceManager.__iter__c                 C   s   | j s	| jdd t| jS )zReturns the number of devices.Tr)   )r_   r<   rX   r5   rc   r    r    r!   __len__   s   
z"FindMyiPhoneServiceManager.__len__c                 C   s   | j duo	| j  S )z"Indicates if the service is alive.N)r9   r_   rc   r    r    r!   r_         z#FindMyiPhoneServiceManager.is_alive"MappingProxyType[str, AppleDevice]c                 C   s
   t | jS )zReturns the devices.)r   r5   rc   r    r    r!   devices  s   
z"FindMyiPhoneServiceManager.devicesc                 C   s   | j rt| j S dS )zReturns the user info.N)r8   r   rc   r    r    r!   	user_info
  r   z$FindMyiPhoneServiceManager.user_info)FNFr   N)T)r   r   )__name__
__module____qualname____doc__strr   dictr   floatr+   boolr<   rH   rI   rE   r   r   r   r   r   r   r   r   propertyr_   r   r   r   r   __classcell__r    r    r@   r!   r#   '   sB    
"
(@	$r#   c                   @   s  e Zd ZdZdeeef deeef dededededed	ed
dfddZe	d
e
fddZdEddZe	d
eeeef  fddZdFdeee  d
eeef fddZdGdEddZ					dH	dEddZ		dId ed!ed"ed
dfd#d$Zd
efd%d&Z		dId!ed"ed
dfd'd(Ze	d
eeef fd)d*Zd
efd+d,Zd
efd-d.Ze	d
efd/d0Ze	d
efd1d2Ze	d
efd3d4Ze	d
efd5d6Ze	d
efd7d8Ze	d
efd9d:Ze	d
efd;d<Z e	d
efd=d>Z!e	d
efd?d@Z"d
efdAdBZ#d
efdCdDZ$dS )Jr   zApple device.ru   r'   rw   rx   ry   r{   r|   rz   r   Nc	           	      C   s4   || _ || _|| _|| _|| _|| _|| _|| _dS )zInitialize the Apple device.N)_content_manager_params
_sound_url	_lost_url
_erase_urlr4   _message_url)	r=   ru   r'   rw   rx   ry   r{   r|   rz   r    r    r!   r+     s   
zAppleDevice.__init__c                 C   s   | j jS )zGets the session.)r   r&   rc   r    r    r!   r&   )  s   zAppleDevice.sessionc                 C   s
   || _ dS )zUpdates the device data.N)r   r=   datar    r    r!   r}   .  s   
zAppleDevice.updatec                 C   s   | j du rdS | jd S )zUpdates the device location.FNlocation)location_availabler   rc   r    r    r!   r   2  s   

zAppleDevice.location
additionalc                 C   s:   g d}|dur||7 }i }|D ]
}| j |||< q|S )zkReturns status information for device.

        This returns only a subset of possible properties.
        )batteryLeveldeviceDisplayNamedeviceStatusnameN)r   rM   )r=   r   fields
propertiesfieldr    r    r!   status9  s   zAppleDevice.statusFind My iPhone Alertc                 C   sB   | j du r	td| jd |ddid}| jj| j| j|d dS )	zSend a request to the device to play a sound.

        It's possible to pass a custom message by changing the `subject`.
        Fz&Sound is not available for this devicerv   ri   T)devicesubjectrd   r'   rr   N)sound_availabler   r   r&   r~   r   r   )r=   r   r   r    r    r!   
play_soundL  s   
zAppleDevice.play_soundThis is a noteFc                 C   sF   | j du r	td| jd |d||||d}| jj| j| j|d dS )zSend a request to the device to a display a message.

        It's possible to pass a custom message by changing the `subject`.
        Fz*Messaging is not available for this devicerv   T)r   r   userTexttextsoundvibratestrober   N)messaging_availabler   r   r&   r~   r   r   )r=   r   messagesoundsr   r   r   r    r    r!   display_message[  s   

zAppleDevice.display_message*This device has been lost. Please call me. numberr   newpasscodec                 C   sF   | j du r	td|d|dd| jd |d}| jj| j| j|d dS )zSend a request to the device to trigger 'lost mode'.

        The device will show the message in `text`, and if a number has
        been passed, then the person holding the device can call
        the number without entering the passcode.
        Fz*Lost mode is not available for this deviceTrv   )r   r   ownerNbrlostModeEnabledtrackingEnabledr   passcoder   N)lost_mode_availabler   r   r&   r~   r   r   )r=   r   r   r   r   r    r    r!   lost_devicex  s   

zAppleDevice.lost_devicec                 C   sP   d| j jdi}| j j| j|d }d|vsd|d vr"td|d d S )z3Get the erase token for the Find My iPhone service.dsWebAuthTokensession_token)rq   rr   tokensmmeFMIPWebEraseDeviceTokenz(Find My iPhone erase token not available)r&   r   rM   r~   r4   rr   r   r   r    r    r!   _get_erase_token  s   zAppleDevice._get_erase_tokenc                 C   sD   | j du r	td|  || jd |d}| jj| j| j|d dS )z5Send a request to the device to start a remote erase.Fz&Erase is not available for this devicerv   )	authTokenr   r   r   r   N)erase_availabler   r   r   r&   r~   r   r   )r=   r   r   r   r    r    r!   erase_device  s   
zAppleDevice.erase_devicec                 C   s   | j js	| j   | jS )zGets the device data.r   r_   r   r   rc   r    r    r!   r     s   
zAppleDevice.datac                 C   s   | j js	| j   | j| S )%Gets an attribute of the device data.r   r   r    r    r!   r     s   

zAppleDevice.__getitem__c                 C   sB   | j js	| j   || jv r| j| S tdt| j d| d)r   'z' object has no attribute ')r   r_   r   r   AttributeErrortyper   )r=   attrr    r    r!   __getattr__  s   


zAppleDevice.__getattr__c                 C      | j ddS )zGets the device name.r   r   r   rM   rc   r    r    r!   r        zAppleDevice.namec                 C   r   )zGets the device model.deviceModelr   r   rc   r    r    r!   model  r   zAppleDevice.modelc                 C   r   )zGets the device model name.r   r   r   rc   r    r    r!   
model_name  r   zAppleDevice.model_namec                 C   r   )zGets the device type.deviceClassr   r   rc   r    r    r!   device_type  r   zAppleDevice.device_typec                 C   r   )z3Indicates if lost mode is available for the device.lostModeCapableFr   rc   r    r    r!   r     r   zAppleDevice.lost_mode_availablec                 C      | j di ddS )z3Indicates if messaging is available for the device.featuresMSGFr   rc   r    r    r!   r        zAppleDevice.messaging_availablec                 C   r   )z/Indicates if sound is available for the device.r   SNDFr   rc   r    r    r!   r     r   zAppleDevice.sound_availablec                 C   r   )z/Indicates if erase is available for the device.r   WIPFr   rc   r    r    r!   r     r   zAppleDevice.erase_availablec                 C   s.   | j di ddod| jv o| jd duS )z2Indicates if location is available for the device.r   LOCFr   N)r   rM   r   rc   r    r    r!   r     s
   zAppleDevice.location_availablec                 C   s   | j  d| j S )z$String representation of the device.z: )r   r   rc   r    r    r!   r     s   zAppleDevice.__str__c                 C   s   d|  dS )r   z<AppleDevice(z)>r    rc   r    r    r!   r     s   zAppleDevice.__repr__r   )N)r   )r   r   FFF)r   r   )%r   r   r   r   r   r   r   r#   r+   r   r   r&   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r    r    r!   r     s    

	


$
 

r   r   )&r   loggingr:   rU   r   r   typesr   typingr   r   r   r   requestsr	   pyicloud.exceptionsr
   r   r   pyicloud.services.baser   pyicloud.sessionr   r   r   __annotations__	getLoggerr   r   Loggerr   r   r   r;   r   r"   r#   r   r    r    r    r!   <module>   s:    
 j