+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+"""
+Dboxswitch dropbox profile switcher
+
+license: Modified BSD License
+
+Copyright (c) 2012, <stack@inventati.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""
+import platform
+import re
+import shutil
+import os
+import errno
+
+from apperror import AppError
+from settings import appconf
+
+class ProfHandler():
+
+ def __init__(self):
+
+ #create profile directory if not exists
+ try:
+ os.makedirs(self.getProfileFolder())
+ except OSError, e:
+ if e.errno != errno.EEXIST:
+ raise
+
+ #compile regular expression for validating profile names
+ self.reg = re.compile("[a-zA-Z0-9_-]+")
+
+ #patch symlink on windows
+ if platform.system() is 'Windows':
+ os.symlink = winsymlink
+
+ def getProfilesList(self):
+ """ Generate and returns the profiles
+ it assumes that self.pdir is defined """
+ #this is generated every time to handle the case of the user renaming the directories by hand
+ return [os.path.join(self.pdir, f) for f in os.listdir(pdir)]
+
+ def getProfileFolder(self):
+ """ Generates, in a os dependant way, the local folder where all profiles are stored """
+ try:
+ #directory path is cached
+ return self.pdir
+ except AttributeError:
+ pl = platform.system()
+ if pl == "Linux":
+ try:
+ from xdg.BaseDirectory import xdf_data_home
+ self.pdir = os.path.join(xdg_data_home, appconf.appname)
+ except:
+ self.pdir = os.path.join(os.path.expanduser('~'),".local/share",appconf.appname)
+ elif pl == 'Windows':
+ self.pdir = os.path.join(os.getenv("APPDATA"), appconf.appname)
+ elif pl == 'Darwin':
+ self.pdir = os.path.join(os.path.expanduser('~'),"."+appconf.appname)
+ elif pl == None:
+ raise AppError('Operative system NOT supported.')
+
+ return self.pdir
+
+ def newProfile(self, profileName):
+ """ Create a profile """
+
+ print("Creating a new profile")
+ if self.isValidProfileName(profileName):
+ os.makedirs(os.path.join(self.getProfileFolder(), profileName))
+ else:
+ raise AppError('Profile Name not valid')
+ print("Profile "+profileName+" created.")
+
+ def delProfile(self, profileName):
+ """ Delete a profile """
+
+ print("Deleting profile")
+ if self.isValidProfileName(profileName):
+ try:
+ #recursively delete the profile directory
+ shutil.rmtree(os.path.join(self.pdir, profileName))
+ except:
+ raise AppError('Profile Name does not exists')
+ else:
+ raise AppError('Profile Name not valid')
+ print("Profile "+profileName+" created.")
+
+ def isValidProfileName(self, pname):
+ if self.reg.match(pname) is not None:
+ return True
+ else:
+ return False
+
+ def activateProfile(self, pname):
+ if pname in self.getProfilesList():
+ self.stopDropbox()
+ try:
+ with open(os.path.join(self.getProfileFolder(), pname)) as pdir:
+ os.unlink(self.getDropboxDirectory())
+ os.symlink(os.path.join(self.getProfileFolder(), pname), self.getDropboxDirectory())
+ except IOError as e:
+ raise AppError('Error on activating Profile: '+pname)
+ self.startDropbox()
+ else:
+ raise AppError("Trying to acrivate non existant profile")
+
+ def getDropboxDirectory(self):
+ pl = platform.system()
+ if pl == 'Linux':
+ return os.path.join(os.path.expanduser('~'),".dropbox")
+ elif pl == 'Windows':
+ raise NotImplementedError, "Not implemented yet."
+ elif pl == 'Darwin':
+ raise NotImplementedError, "Not implemented yet."
+
+
+__CSL = None
+def winsymlink(source, link_name):
+ '''symlink(source, link_name)
+ Creates a symbolic link pointing to source named link_name.
+ Used to patch the nonexistant version on windows for python 2.6'''
+ global __CSL
+ if __CSL is None:
+ import ctypes
+ csl = ctypes.windll.kernel32.CreateSymbolicLinkW
+ csl.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32)
+ csl.restype = ctypes.c_ubyte
+ __CSL = csl
+ flags = 0
+ if source is not None and os.path.isdir(source):
+ flags = 1
+ if __CSL(link_name, source, flags) == 0:
+ raise ctypes.WinError()
+