text: import os
  import json
  import base64
  import shelve
  import urllib
  import logging
  import tempfile
  import subprocess
  
  import requests
  
  
  class Session(object):
    def __init__(self, url):
      self.session_id = None
      self.url = url.rstrip('/') + '/'
  
    def __enter__(self):
      return self
  
    def __exit__(self, *args):
      pass
  
    def __dict__(self):
      return self.response
  
    def request(self, method, data=None):
      """
      Sends a request to the BIM server.
      """
      params = {}
      url = self.url + method
  
      if type(data) is str:
        data = json.loads(data)
  
      if self.session_id:
        params['session-id'] = self.session_id
  
      if data:
        self._request = requests.post(url, params=params, json=data)
      else:
        self._request = requests.get(url, params=params)
  
      self._text = self._request.text
  
      if method.endswith('get-server-public-key'):
        logging.debug('Got public key: %s' % self._text)
        self.key = self._text
        return self
  
      try:
        self.response = self._request.json()
      except ValueError:
        raise Exception(self._text)
  
      if type(self.response) == dict:
        if self.response.get('error-code'):
          raise Exception(self.response.get('error-message'))
  
        if self.response.get('status', 0) == 400:
          raise Exception(self.response.get('message'))
  
      if method.endswith('get-server-info'):
        self.server = self.response
        self.id = self.response.get('serverId')
        self.version = self.response.get('versionString')
        self.name = self.response.get('friendlyName')
        self.license = self.response.get('license')
        self.platform = self.response.get('platform')
  
      return self
  
    def encrypt_password(self, password):
      """
      Encrypts the supplied password with the server's public key
      and returns the encrypted password
      """
      with tempfile.NamedTemporaryFile() as f:
        f.write(self.key)
        logging.debug('Wrote public key to %s' % f.name)
        f.seek(0)
        p = subprocess.Popen(['openssl', 'rsautl', '-encrypt',
                              '-inkey', f.name, '-pubin'],
                              stdin=subprocess.PIPE,
                              stdout=subprocess.PIPE)
        o, e = p.communicate(password + '00000000')
        password = base64.b64encode(o)
        return password
  
    def login(self, username, password):
      """
      Authenticates with the BIM server.
      Returns self for further queries.
      """
      db = os.path.join(tempfile.gettempdir(), 'bimclient_db')
      cache = shelve.open(db)
      session = cache.get('session')
  
      if session:
        logging.debug('Using cached session: %s' % session)
        self.response = session
      else:
        self.request('management/latest/get-server-public-key')
        password = self.encrypt_password(password)
        d = {'username': username, 'password': password}
        self.request('management/latest/create-session', data=d)
        cache['session'] = self.response
        cache.close()
  
      logging.debug(self.response)
  
      self.user_id = self.response.get('user-id')
      self.session_id = self.response.get('session-id')
      self.session_timeout = self.response.get('expire-timeout')
  
      if self.user_id:
        logging.debug('Logged in as %s' % self.user_id)
      else:
        raise Exception('Authentication failed')
  
      return self
  
    def projects(self):
      data = json.loads('{"$and":[{"$or":[{"$eq":{"id":"projectRoot"}},{"$eq":{"$parentId":"projectRoot"}}]}]}')
      self.request('management/latest/get-resources-by-criterion', data=data)
      logging.debug(self.response)
      return self.response
  
  
  def connect(url):
    with Session(url) as session:
      return session.request('get-server-info')
  