2013-06-23 01:32:23 +00:00
|
|
|
# Created By: Virgil Dupras
|
|
|
|
# Created On: 2009-05-16
|
|
|
|
# Copyright 2013 Hardcoded Software (http://www.hardcoded.net)
|
|
|
|
|
|
|
|
# This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
|
|
|
# which should be included with this package. The terms are also available at
|
|
|
|
# http://www.hardcoded.net/licenses/bsd_license
|
|
|
|
|
|
|
|
import re
|
|
|
|
from hashlib import md5
|
|
|
|
|
2013-10-12 17:54:13 +00:00
|
|
|
from . import desktop
|
2013-06-23 01:32:23 +00:00
|
|
|
from .trans import trget
|
|
|
|
|
|
|
|
tr = trget('hscommon')
|
|
|
|
|
|
|
|
ALL_APPS = [
|
|
|
|
(1, 'dupeGuru'),
|
|
|
|
(2, 'moneyGuru'),
|
|
|
|
(3, 'musicGuru'),
|
|
|
|
(6, 'PdfMasher'),
|
|
|
|
]
|
|
|
|
|
|
|
|
OLDAPPIDS = {
|
|
|
|
1: {1, 4, 5},
|
|
|
|
2: {6, },
|
|
|
|
3: {2, },
|
|
|
|
}
|
|
|
|
|
|
|
|
class InvalidCodeError(Exception):
|
|
|
|
"""The supplied code is invalid."""
|
|
|
|
|
|
|
|
DEMO_PROMPT = tr("{name} is fairware, which means \"open source software developed with expectation "
|
|
|
|
"of fair contributions from users\". It's a very interesting concept, but one year of fairware has "
|
|
|
|
"shown that most people just want to know how much it costs and not be bothered with theories "
|
|
|
|
"about intellectual property."
|
|
|
|
"\n\n"
|
|
|
|
"So I won't bother you and will be very straightforward: You can try {name} for free but you have "
|
|
|
|
"to buy it in order to use it without limitations. In demo mode, {name} {limitation}."
|
|
|
|
"\n\n"
|
|
|
|
"So it's as simple as this. If you're curious about fairware, however, I encourage you to read "
|
|
|
|
"more about it by clicking on the \"Fairware?\" button.")
|
|
|
|
|
|
|
|
class RegistrableApplication:
|
|
|
|
#--- View interface
|
|
|
|
# get_default(key_name)
|
|
|
|
# set_default(key_name, value)
|
|
|
|
# setup_as_registered()
|
|
|
|
# show_message(msg)
|
|
|
|
# show_demo_nag(prompt)
|
|
|
|
|
|
|
|
PROMPT_NAME = "<undefined>"
|
|
|
|
DEMO_LIMITATION = "<undefined>"
|
|
|
|
|
|
|
|
def __init__(self, view, appid):
|
|
|
|
self.view = view
|
|
|
|
self.appid = appid
|
|
|
|
self.registered = False
|
|
|
|
self.fairware_mode = False
|
|
|
|
self.registration_code = ''
|
|
|
|
self.registration_email = ''
|
|
|
|
self._unpaid_hours = None
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _is_code_valid(appid, code, email):
|
|
|
|
if len(code) != 32:
|
|
|
|
return False
|
|
|
|
appid = str(appid)
|
|
|
|
for i in range(100):
|
|
|
|
blob = appid + email + str(i) + 'aybabtu'
|
|
|
|
digest = md5(blob.encode('utf-8')).hexdigest()
|
|
|
|
if digest == code:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def _set_registration(self, code, email):
|
|
|
|
self.validate_code(code, email)
|
|
|
|
self.registration_code = code
|
|
|
|
self.registration_email = email
|
|
|
|
self.registered = True
|
|
|
|
self.view.setup_as_registered()
|
|
|
|
|
|
|
|
def initial_registration_setup(self):
|
|
|
|
# Should be called only after the app is finished launching
|
|
|
|
if self.registered:
|
|
|
|
# We've already set registration in a hardcoded way (for example, for the Ubuntu Store)
|
|
|
|
# Just ignore registration, but not before having set as registered.
|
|
|
|
self.view.setup_as_registered()
|
|
|
|
return
|
|
|
|
code = self.view.get_default('RegistrationCode')
|
|
|
|
email = self.view.get_default('RegistrationEmail')
|
|
|
|
if code and email:
|
|
|
|
try:
|
|
|
|
self._set_registration(code, email)
|
|
|
|
except InvalidCodeError:
|
|
|
|
pass
|
|
|
|
if not self.registered:
|
|
|
|
if self.view.get_default('FairwareMode'):
|
|
|
|
self.fairware_mode = True
|
|
|
|
if not self.fairware_mode:
|
|
|
|
prompt = DEMO_PROMPT.format(name=self.PROMPT_NAME, limitation=self.DEMO_LIMITATION)
|
|
|
|
self.view.show_demo_nag(prompt)
|
|
|
|
|
|
|
|
def validate_code(self, code, email):
|
|
|
|
code = code.strip().lower()
|
|
|
|
email = email.strip().lower()
|
|
|
|
if self._is_code_valid(self.appid, code, email):
|
|
|
|
return
|
|
|
|
# Check if it's not an old reg code
|
|
|
|
for oldappid in OLDAPPIDS.get(self.appid, []):
|
|
|
|
if self._is_code_valid(oldappid, code, email):
|
|
|
|
return
|
|
|
|
# let's see if the user didn't mix the fields up
|
|
|
|
if self._is_code_valid(self.appid, email, code):
|
|
|
|
msg = "Invalid Code. It seems like you inverted the 'Registration Code' and"\
|
|
|
|
"'Registration E-mail' field."
|
|
|
|
raise InvalidCodeError(msg)
|
|
|
|
# Is the code a paypal transaction id?
|
|
|
|
if re.match(r'^[a-z\d]{17}$', code) is not None:
|
|
|
|
msg = "The code you submitted looks like a Paypal transaction ID. Registration codes are "\
|
|
|
|
"32 digits codes which you should have received in a separate e-mail. If you haven't "\
|
|
|
|
"received it yet, please visit http://www.hardcoded.net/support/"
|
|
|
|
raise InvalidCodeError(msg)
|
|
|
|
# Invalid, let's see if it's a code for another app.
|
|
|
|
for appid, appname in ALL_APPS:
|
|
|
|
if self._is_code_valid(appid, code, email):
|
|
|
|
msg = "This code is a {0} code. You're running the wrong application. You can "\
|
|
|
|
"download the correct application at http://www.hardcoded.net".format(appname)
|
|
|
|
raise InvalidCodeError(msg)
|
|
|
|
DEFAULT_MSG = "Your code is invalid. Make sure that you wrote the good code. Also make sure "\
|
|
|
|
"that the e-mail you gave is the same as the e-mail you used for your purchase."
|
|
|
|
raise InvalidCodeError(DEFAULT_MSG)
|
|
|
|
|
|
|
|
def set_registration(self, code, email, register_os):
|
|
|
|
if not self.fairware_mode and 'fairware' in {code.strip().lower(), email.strip().lower()}:
|
|
|
|
self.fairware_mode = True
|
|
|
|
self.view.set_default('FairwareMode', True)
|
|
|
|
self.view.show_message("Fairware mode enabled.")
|
|
|
|
return True
|
|
|
|
try:
|
|
|
|
self._set_registration(code, email)
|
|
|
|
self.view.show_message("Your code is valid. Thanks!")
|
|
|
|
if register_os:
|
|
|
|
self.register_os()
|
|
|
|
self.view.set_default('RegistrationCode', self.registration_code)
|
|
|
|
self.view.set_default('RegistrationEmail', self.registration_email)
|
|
|
|
return True
|
|
|
|
except InvalidCodeError as e:
|
|
|
|
self.view.show_message(str(e))
|
|
|
|
return False
|
|
|
|
|
|
|
|
def register_os(self):
|
|
|
|
# We don't do that anymore.
|
|
|
|
pass
|
|
|
|
|
|
|
|
def contribute(self):
|
2013-10-12 17:54:13 +00:00
|
|
|
desktop.open_url("http://open.hardcoded.net/contribute/")
|
2013-06-23 01:32:23 +00:00
|
|
|
|
|
|
|
def buy(self):
|
2013-10-12 17:54:13 +00:00
|
|
|
desktop.open_url("http://www.hardcoded.net/purchase.htm")
|
2013-06-23 01:32:23 +00:00
|
|
|
|
|
|
|
def about_fairware(self):
|
2013-10-12 17:54:13 +00:00
|
|
|
desktop.open_url("http://open.hardcoded.net/about/")
|
2013-06-23 01:32:23 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def should_show_fairware_reminder(self):
|
|
|
|
return (not self.registered) and (self.fairware_mode) and (self.unpaid_hours >= 1)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def should_apply_demo_limitation(self):
|
|
|
|
return (not self.registered) and (not self.fairware_mode)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def unpaid_hours(self):
|
|
|
|
# We don't bother verifying unpaid hours anymore, the only app that still has fairware
|
|
|
|
# dialogs is dupeGuru and it has a huge surplus. Now, "fairware mode" really means
|
|
|
|
# "free mode".
|
|
|
|
return 0
|
|
|
|
|