144
141
"""Get the users pop up editor."""
145
142
raise NotImplementedError
147
def get_mail_client(self):
148
"""Get a mail client to use"""
149
selected_client = self.get_user_option('mail_client')
151
mail_client_class = {
152
None: mail_client.DefaultMail,
154
'evolution': mail_client.Evolution,
155
'kmail': mail_client.KMail,
156
'mutt': mail_client.Mutt,
157
'thunderbird': mail_client.Thunderbird,
159
'default': mail_client.DefaultMail,
160
'editor': mail_client.Editor,
161
'mapi': mail_client.MAPIClient,
162
'xdg-email': mail_client.XDGEmail,
165
raise errors.UnknownMailClient(selected_client)
166
return mail_client_class(self)
168
144
def _get_signature_checking(self):
169
145
"""Template method to override signature checking policy."""
457
428
def __init__(self, location):
458
429
name_generator = locations_config_filename
459
if (not os.path.exists(name_generator()) and
430
if (not os.path.exists(name_generator()) and
460
431
os.path.exists(branches_config_filename())):
461
432
if sys.platform == 'win32':
462
trace.warning('Please rename %s to %s'
463
% (branches_config_filename(),
464
locations_config_filename()))
433
warning('Please rename %s to %s'
434
% (branches_config_filename(),
435
locations_config_filename()))
466
trace.warning('Please rename ~/.bazaar/branches.conf'
467
' to ~/.bazaar/locations.conf')
437
warning('Please rename ~/.bazaar/branches.conf'
438
' to ~/.bazaar/locations.conf')
468
439
name_generator = branches_config_filename
469
440
super(LocationConfig, self).__init__(name_generator)
470
441
# local file locations are looked up by local path, rather than
670
def set_user_option(self, name, value, store=STORE_BRANCH,
641
def set_user_option(self, name, value, store=STORE_BRANCH):
672
642
if store == STORE_BRANCH:
673
643
self._get_branch_data_config().set_option(value, name)
674
644
elif store == STORE_GLOBAL:
675
645
self._get_global_config().set_user_option(name, value)
677
647
self._get_location_config().set_user_option(name, value, store)
680
if store in (STORE_GLOBAL, STORE_BRANCH):
681
mask_value = self._get_location_config().get_user_option(name)
682
if mask_value is not None:
683
trace.warning('Value "%s" is masked by "%s" from'
684
' locations.conf', value, mask_value)
686
if store == STORE_GLOBAL:
687
branch_config = self._get_branch_data_config()
688
mask_value = branch_config.get_user_option(name)
689
if mask_value is not None:
690
trace.warning('Value "%s" is masked by "%s" from'
691
' branch.conf', value, mask_value)
694
649
def _gpg_signing_command(self):
695
650
"""See Config.gpg_signing_command."""
862
811
return realname, (username + '@' + socket.gethostname())
865
def parse_username(username):
866
"""Parse e-mail username and return a (name, address) tuple."""
867
match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
869
return (username, '')
871
return (match.group(1), match.group(2))
874
814
def extract_email_address(e):
875
815
"""Return just the address part of an email string.
877
817
That is just the user@domain part, nothing else.
878
818
This part is required to contain only ascii characters.
879
819
If it can't be extracted, raises an error.
881
821
>>> extract_email_address('Jane Tester <jane@test.com>')
884
name, email = parse_username(e)
824
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
886
826
raise errors.NoEmailInUsername(e)
890
830
class TreeConfig(IniBasedConfig):
891
831
"""Branch configuration data associated with its contents, not location"""
893
832
def __init__(self, branch):
894
833
self.branch = branch
940
879
self.branch.control_files.put('branch.conf', out_file)
942
881
self.branch.unlock()
945
class AuthenticationConfig(object):
946
"""The authentication configuration file based on a ini file.
948
Implements the authentication.conf file described in
949
doc/developers/authentication-ring.txt.
952
def __init__(self, _file=None):
953
self._config = None # The ConfigObj
955
self._filename = authentication_config_filename()
956
self._input = self._filename = authentication_config_filename()
958
# Tests can provide a string as _file
959
self._filename = None
962
def _get_config(self):
963
if self._config is not None:
966
# FIXME: Should we validate something here ? Includes: empty
967
# sections are useless, at least one of
968
# user/password/password_encoding should be defined, etc.
970
# Note: the encoding below declares that the file itself is utf-8
971
# encoded, but the values in the ConfigObj are always Unicode.
972
self._config = ConfigObj(self._input, encoding='utf-8')
973
except configobj.ConfigObjError, e:
974
raise errors.ParseConfigError(e.errors, e.config.filename)
978
"""Save the config file, only tests should use it for now."""
979
conf_dir = os.path.dirname(self._filename)
980
ensure_config_dir_exists(conf_dir)
981
self._get_config().write(file(self._filename, 'wb'))
983
def _set_option(self, section_name, option_name, value):
984
"""Set an authentication configuration option"""
985
conf = self._get_config()
986
section = conf.get(section_name)
989
section = conf[section]
990
section[option_name] = value
993
def get_credentials(self, scheme, host, port=None, user=None, path=None):
994
"""Returns the matching credentials from authentication.conf file.
996
:param scheme: protocol
998
:param host: the server address
1000
:param port: the associated port (optional)
1002
:param user: login (optional)
1004
:param path: the absolute path on the server (optional)
1006
:return: A dict containing the matching credentials or None.
1008
- name: the section name of the credentials in the
1009
authentication.conf file,
1010
- user: can't de different from the provided user if any,
1011
- password: the decoded password, could be None if the credential
1012
defines only the user
1013
- verify_certificates: https specific, True if the server
1014
certificate should be verified, False otherwise.
1017
for auth_def_name, auth_def in self._get_config().items():
1018
a_scheme, a_host, a_user, a_path = map(
1019
auth_def.get, ['scheme', 'host', 'user', 'path'])
1022
a_port = auth_def.as_int('port')
1026
raise ValueError("'port' not numeric in %s" % auth_def_name)
1028
a_verify_certificates = auth_def.as_bool('verify_certificates')
1030
a_verify_certificates = True
1033
"'verify_certificates' not boolean in %s" % auth_def_name)
1036
if a_scheme is not None and scheme != a_scheme:
1038
if a_host is not None:
1039
if not (host == a_host
1040
or (a_host.startswith('.') and host.endswith(a_host))):
1042
if a_port is not None and port != a_port:
1044
if (a_path is not None and path is not None
1045
and not path.startswith(a_path)):
1047
if (a_user is not None and user is not None
1048
and a_user != user):
1049
# Never contradict the caller about the user to be used
1054
credentials = dict(name=auth_def_name,
1055
user=a_user, password=auth_def['password'],
1056
verify_certificates=a_verify_certificates)
1057
self.decode_password(credentials,
1058
auth_def.get('password_encoding', None))
1059
if 'auth' in debug.debug_flags:
1060
trace.mutter("Using authentication section: %r", auth_def_name)
1065
def get_user(self, scheme, host, port=None,
1066
realm=None, path=None, prompt=None):
1067
"""Get a user from authentication file.
1069
:param scheme: protocol
1071
:param host: the server address
1073
:param port: the associated port (optional)
1075
:param realm: the realm sent by the server (optional)
1077
:param path: the absolute path on the server (optional)
1079
:return: The found user.
1081
credentials = self.get_credentials(scheme, host, port, user=None,
1083
if credentials is not None:
1084
user = credentials['user']
1089
def get_password(self, scheme, host, user, port=None,
1090
realm=None, path=None, prompt=None):
1091
"""Get a password from authentication file or prompt the user for one.
1093
:param scheme: protocol
1095
:param host: the server address
1097
:param port: the associated port (optional)
1101
:param realm: the realm sent by the server (optional)
1103
:param path: the absolute path on the server (optional)
1105
:return: The found password or the one entered by the user.
1107
credentials = self.get_credentials(scheme, host, port, user, path)
1108
if credentials is not None:
1109
password = credentials['password']
1112
# Prompt user only if we could't find a password
1113
if password is None:
1115
# Create a default prompt suitable for most of the cases
1116
prompt = '%s' % scheme.upper() + ' %(user)s@%(host)s password'
1117
# Special handling for optional fields in the prompt
1118
if port is not None:
1119
prompt_host = '%s:%d' % (host, port)
1122
password = ui.ui_factory.get_password(prompt,
1123
host=prompt_host, user=user)
1126
def decode_password(self, credentials, encoding):