1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /* Copyright (C) 2003, 2004 Novell, Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU Lesser General Public
7 * License as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
20 /* e2k-autoconfig: Automatic account configuration backend code */
22 /* Note on gtk-doc: Several functions in this file have intentionally-
23 * broken gtk-doc comments (that have only a single "*" after the
24 * opening "/") so that they can be overridden by versions in
25 * docs/reference/tmpl/e2k-autoconfig.sgml that use better markup.
26 * If you change the docs here, be sure to change them there as well.
41 #include <glib/gstdio.h>
44 #include <netinet/in.h>
45 #include <arpa/nameser.h>
52 #define DNS_TYPE_SRV 33
56 #include "e2k-autoconfig.h"
57 #include "e2k-encoding-utils.h"
58 #include "e2k-context.h"
59 #include "e2k-global-catalog.h"
60 #include "e2k-propnames.h"
62 #include "e2k-utils.h"
63 #include "e2k-xml-utils.h"
66 #include <libedataserver/e-data-server-util.h>
67 #include <libedataserver/e-url.h>
68 #include <libedataserverui/e-passwords.h>
69 #include <gconf/gconf-client.h>
70 #include <libxml/tree.h>
71 #include <libxml/HTMLparser.h>
76 #undef CONNECTOR_PREFIX
77 #define CONNECTOR_PREFIX e_util_get_prefix ()
80 static char *find_olson_timezone (const char *windows_timezone);
81 static void set_account_uri_string (E2kAutoconfig *ac);
85 * @owa_uri: the OWA URI, or %NULL to (try to) use a default
86 * @username: the username (or DOMAIN\username), or %NULL to use a default
87 * @password: the password, or %NULL if not yet known
88 * @auth_pref: information about what auth type to use
90 * Creates an autoconfig context, based on information stored in the
91 * config file or provided as arguments.
93 * Return value: an autoconfig context
96 e2k_autoconfig_new (const char *owa_uri, const char *username,
97 const char *password, E2kAutoconfigAuthPref auth_pref)
101 ac = g_new0 (E2kAutoconfig, 1);
103 if (e2k_autoconfig_lookup_option ("Disable-Plaintext")) {
104 ac->auth_pref = E2K_AUTOCONFIG_USE_NTLM;
105 ac->require_ntlm = TRUE;
107 ac->auth_pref = auth_pref;
109 e2k_autoconfig_set_owa_uri (ac, owa_uri);
110 e2k_autoconfig_set_gc_server (ac, NULL, -1);
111 e2k_autoconfig_set_username (ac, username);
112 e2k_autoconfig_set_password (ac, password);
118 * e2k_autoconfig_free:
119 * @ac: an autoconfig context
124 e2k_autoconfig_free (E2kAutoconfig *ac)
126 g_free (ac->owa_uri);
127 g_free (ac->gc_server);
128 g_free (ac->username);
129 g_free (ac->password);
130 g_free (ac->display_name);
132 g_free (ac->account_uri);
133 g_free (ac->exchange_server);
134 g_free (ac->timezone);
135 g_free (ac->nt_domain);
136 g_free (ac->w2k_domain);
137 g_free (ac->home_uri);
138 g_free (ac->exchange_dn);
139 g_free (ac->pf_server);
145 reset_gc_derived (E2kAutoconfig *ac)
147 if (ac->display_name) {
148 g_free (ac->display_name);
149 ac->display_name = NULL;
155 if (ac->account_uri) {
156 g_free (ac->account_uri);
157 ac->account_uri = NULL;
162 reset_owa_derived (E2kAutoconfig *ac)
164 /* Clear the information we explicitly get from OWA */
166 g_free (ac->timezone);
169 if (ac->exchange_dn) {
170 g_free (ac->exchange_dn);
171 ac->exchange_dn = NULL;
174 g_free (ac->pf_server);
175 ac->pf_server = NULL;
178 g_free (ac->home_uri);
182 /* Reset domain info we may have implicitly got */
183 ac->use_ntlm = (ac->auth_pref != E2K_AUTOCONFIG_USE_BASIC);
184 if (ac->nt_domain_defaulted) {
185 g_free (ac->nt_domain);
186 ac->nt_domain = g_strdup (e2k_autoconfig_lookup_option ("NT-Domain"));
187 ac->nt_domain_defaulted = FALSE;
190 g_free (ac->w2k_domain);
191 ac->w2k_domain = g_strdup (e2k_autoconfig_lookup_option ("Domain"));
193 /* Reset GC-derived information since it depends on the
194 * OWA-derived information too.
196 reset_gc_derived (ac);
200 * e2k_autoconfig_set_owa_uri:
201 * @ac: an autoconfig context
202 * @owa_uri: the new OWA URI, or %NULL
204 * Sets @ac's #owa_uri field to @owa_uri (or the default if @owa_uri is
205 * %NULL), and resets any fields whose values had been set based on
206 * the old value of #owa_uri.
209 e2k_autoconfig_set_owa_uri (E2kAutoconfig *ac, const char *owa_uri)
211 reset_owa_derived (ac);
212 if (ac->gc_server_autodetected)
213 e2k_autoconfig_set_gc_server (ac, NULL, -1);
214 g_free (ac->owa_uri);
217 if (!strncmp (owa_uri, "http", 4))
218 ac->owa_uri = g_strdup (owa_uri);
220 ac->owa_uri = g_strdup_printf ("http://%s", owa_uri);
222 ac->owa_uri = g_strdup (e2k_autoconfig_lookup_option ("OWA-URL"));
226 * e2k_autoconfig_set_gc_server:
227 * @ac: an autoconfig context
228 * @gc_server: the new GC server, or %NULL
229 * @gal_limit: GAL search size limit, or -1 for no limit
231 * Sets @ac's #gc_server field to @gc_server (or the default if
232 * @gc_server is %NULL) and the #gal_limit field to @gal_limit, and
233 * resets any fields whose values had been set based on the old value
237 e2k_autoconfig_set_gc_server (E2kAutoconfig *ac, const char *gc_server,
240 const char *default_gal_limit;
242 reset_gc_derived (ac);
243 g_free (ac->gc_server);
246 ac->gc_server = g_strdup (gc_server);
248 ac->gc_server = g_strdup (e2k_autoconfig_lookup_option ("Global-Catalog"));
249 ac->gc_server_autodetected = FALSE;
251 if (gal_limit == -1) {
252 default_gal_limit = e2k_autoconfig_lookup_option ("GAL-Limit");
253 if (default_gal_limit)
254 gal_limit = atoi (default_gal_limit);
256 ac->gal_limit = gal_limit;
260 * e2k_autoconfig_set_username:
261 * @ac: an autoconfig context
262 * @username: the new username (or DOMAIN\username), or %NULL
264 * Sets @ac's #username field to @username (or the default if
265 * @username is %NULL), and resets any fields whose values had been
266 * set based on the old value of #username.
269 e2k_autoconfig_set_username (E2kAutoconfig *ac, const char *username)
273 reset_owa_derived (ac);
274 g_free (ac->username);
277 /* If the username includes a domain name, split it out */
278 dlen = strcspn (username, "/\\");
279 if (username[dlen]) {
280 g_free (ac->nt_domain);
281 ac->nt_domain = g_strndup (username, dlen);
282 ac->username = g_strdup (username + dlen + 1);
283 ac->nt_domain_defaulted = FALSE;
285 ac->username = g_strdup (username);
287 ac->username = g_strdup (g_get_user_name ());
291 * e2k_autoconfig_set_password:
292 * @ac: an autoconfig context
293 * @password: the new password, or %NULL to clear
295 * Sets or clears @ac's #password field.
298 e2k_autoconfig_set_password (E2kAutoconfig *ac, const char *password)
300 g_free (ac->password);
301 ac->password = g_strdup (password);
305 get_ctx_auth_handler (SoupMessage *msg, gpointer user_data)
307 E2kAutoconfig *ac = user_data;
308 const GSList *headers;
309 const char *challenge_hdr;
310 GByteArray *challenge;
312 ac->saw_ntlm = ac->saw_basic = FALSE;
313 headers = soup_message_get_header_list (msg->response_headers,
316 challenge_hdr = headers->data;
318 if (!strcmp (challenge_hdr, "NTLM"))
320 else if (!strncmp (challenge_hdr, "Basic ", 6))
321 ac->saw_basic = TRUE;
323 if (!strncmp (challenge_hdr, "NTLM ", 5) &&
324 (!ac->w2k_domain || !ac->nt_domain)) {
325 challenge = e2k_base64_decode (challenge_hdr + 5);
327 ac->nt_domain_defaulted = TRUE;
328 xntlm_parse_challenge (challenge->data, challenge->len,
330 ac->nt_domain ? NULL : &ac->nt_domain,
331 ac->w2k_domain ? NULL : &ac->w2k_domain);
332 g_byte_array_free (challenge, TRUE);
337 headers = headers->next;
342 * e2k_autoconfig_get_context:
343 * @ac: an autoconfig context
344 * @op: an #E2kOperation, for cancellation
345 * @result: on output, a result code
347 * Checks if @ac's URI and authentication parameters work, and if so
348 * returns an #E2kContext using them. On return, *@result (which
349 * may not be %NULL) will contain a result code as follows:
351 * %E2K_AUTOCONFIG_OK: success
352 * %E2K_AUTOCONFIG_REDIRECT: The server issued a valid-looking
353 * redirect. @ac->owa_uri has been updated and the caller
355 * %E2K_AUTOCONFIG_TRY_SSL: The server requires SSL.
356 * @ac->owa_uri has been updated and the caller should try
358 * %E2K_AUTOCONFIG_AUTH_ERROR: Generic authentication failure.
359 * Probably password incorrect
360 * %E2K_AUTOCONFIG_AUTH_ERROR_TRY_DOMAIN: Authentication failed.
361 * Including an NT domain with the username (or using NTLM)
362 * may fix the problem.
363 * %E2K_AUTOCONFIG_AUTH_ERROR_TRY_BASIC: Caller requested NTLM
364 * auth, but only Basic was available.
365 * %E2K_AUTOCONFIG_AUTH_ERROR_TRY_NTLM: Caller requested Basic
366 * auth, but only NTLM was available.
367 * %E2K_AUTOCONFIG_EXCHANGE_5_5: Server appears to be Exchange 5.5.
368 * %E2K_AUTOCONFIG_NOT_EXCHANGE: Server does not appear to be
369 * any version of Exchange
370 * %E2K_AUTOCONFIG_NO_OWA: Server may be Exchange 2000, but OWA
371 * is not present at the given URL.
372 * %E2K_AUTOCONFIG_NO_MAILBOX: OWA claims the user has no mailbox.
373 * %E2K_AUTOCONFIG_CANT_RESOLVE: Could not resolve hostname.
374 * %E2K_AUTOCONFIG_CANT_CONNECT: Could not connect to server.
375 * %E2K_AUTOCONFIG_CANCELLED: User cancelled
376 * %E2K_AUTOCONFIG_FAILED: Other error.
378 * Return value: the new context, or %NULL
380 * (If you change this comment, see the note at the top of this file.)
383 e2k_autoconfig_get_context (E2kAutoconfig *ac, E2kOperation *op,
384 E2kAutoconfigResult *result)
388 E2kHTTPStatus status;
389 const char *ms_webstorage;
392 xmlChar *equiv, *content, *href;
394 ctx = e2k_context_new (ac->owa_uri);
396 *result = E2K_AUTOCONFIG_FAILED;
399 e2k_context_set_auth (ctx, ac->username, ac->nt_domain,
400 ac->use_ntlm ? "NTLM" : "Basic", ac->password);
402 msg = e2k_soup_message_new (ctx, ac->owa_uri, SOUP_METHOD_GET);
403 soup_message_add_header (msg->request_headers, "Accept-Language",
404 e2k_http_accept_language ());
405 soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
407 soup_message_add_status_code_handler (msg, E2K_HTTP_UNAUTHORIZED,
408 SOUP_HANDLER_PRE_BODY,
409 get_ctx_auth_handler, ac);
412 e2k_context_send_message (ctx, op, msg);
413 status = msg->status_code;
415 /* Check for cancellation or other transport error. */
416 if (E2K_HTTP_STATUS_IS_TRANSPORT_ERROR (status)) {
417 if (status == E2K_HTTP_CANCELLED)
418 *result = E2K_AUTOCONFIG_CANCELLED;
419 else if (status == E2K_HTTP_CANT_RESOLVE)
420 *result = E2K_AUTOCONFIG_CANT_RESOLVE;
422 *result = E2K_AUTOCONFIG_CANT_CONNECT;
426 /* Check for an authentication failure. This could be because
427 * the password is incorrect, or because we used Basic auth
428 * without specifying a domain and the server doesn't have a
429 * default domain, or because we tried to use an auth type the
430 * server doesn't allow.
432 if (status == E2K_HTTP_UNAUTHORIZED) {
433 if (!ac->use_ntlm && !ac->nt_domain)
434 *result = E2K_AUTOCONFIG_AUTH_ERROR_TRY_DOMAIN;
435 else if (ac->use_ntlm && !ac->saw_ntlm)
436 *result = E2K_AUTOCONFIG_AUTH_ERROR_TRY_BASIC;
437 else if (!ac->use_ntlm && !ac->saw_basic)
438 *result = E2K_AUTOCONFIG_AUTH_ERROR_TRY_NTLM;
440 *result = E2K_AUTOCONFIG_AUTH_ERROR;
444 /* A redirection to "logon.asp" means this is Exchange 5.5
445 * OWA. A redirection to "owalogon.asp" means this is Exchange
446 * 2003 forms-based authentication. A redirection to
447 * "CookieAuth.dll" means that it's an Exchange 2003 server
448 * behind an ISA Server 2004 proxy. Other redirections most
449 * likely indicate that the user's mailbox has been moved to a
452 if (E2K_HTTP_STATUS_IS_REDIRECTION (status)) {
453 const char *location;
456 location = soup_message_get_header (msg->response_headers,
459 *result = E2K_AUTOCONFIG_FAILED;
463 if (strstr (location, "/logon.asp")) {
464 *result = E2K_AUTOCONFIG_EXCHANGE_5_5;
466 } else if (strstr (location, "/owalogon.asp") ||
467 strstr (location, "/CookieAuth.dll")) {
468 if (e2k_context_fba (ctx, msg))
470 *result = E2K_AUTOCONFIG_AUTH_ERROR;
474 new_uri = e2k_strdup_with_trailing_slash (location);
475 e2k_autoconfig_set_owa_uri (ac, new_uri);
477 *result = E2K_AUTOCONFIG_REDIRECT;
481 /* If the server requires SSL, it will send back 403 Forbidden
482 * with a body explaining that.
484 if (status == E2K_HTTP_FORBIDDEN &&
485 !strncmp (ac->owa_uri, "http:", 5) &&
486 msg->response.length > 0) {
487 msg->response.body[msg->response.length - 1] = '\0';
488 if (strstr (msg->response.body, "SSL")) {
490 g_strconcat ("https:", ac->owa_uri + 5, NULL);
491 e2k_autoconfig_set_owa_uri (ac, new_uri);
493 *result = E2K_AUTOCONFIG_TRY_SSL;
498 /* Figure out some stuff about the server */
499 ms_webstorage = soup_message_get_header (msg->response_headers,
502 if (!strncmp (ms_webstorage, "6.0.", 4))
503 ac->version = E2K_EXCHANGE_2000;
504 else if (!strncmp (ms_webstorage, "6.5.", 4))
505 ac->version = E2K_EXCHANGE_2003;
507 ac->version = E2K_EXCHANGE_FUTURE;
509 const char *server = soup_message_get_header (msg->response_headers, "Server");
511 /* If the server explicitly claims to be something
512 * other than IIS, then return the "not windows"
515 if (server && !strstr (server, "IIS")) {
516 *result = E2K_AUTOCONFIG_NOT_EXCHANGE;
520 /* It's probably Exchange 2000... older versions
521 * didn't include the MS-WebStorage header here. But
522 * we don't know for sure.
524 ac->version = E2K_EXCHANGE_UNKNOWN;
527 /* If we're talking to OWA, then 404 Not Found means you don't
528 * have a mailbox. Otherwise, it means you're not talking to
529 * Exchange (even 5.5).
531 if (status == E2K_HTTP_NOT_FOUND) {
533 *result = E2K_AUTOCONFIG_NO_MAILBOX;
535 *result = E2K_AUTOCONFIG_NOT_EXCHANGE;
539 /* Any other error else gets generic failure */
540 if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
541 *result = E2K_AUTOCONFIG_FAILED;
545 /* Parse the returned HTML. */
546 doc = e2k_parse_html (msg->response.body, msg->response.length);
549 *result = ac->version == E2K_EXCHANGE_UNKNOWN ?
550 E2K_AUTOCONFIG_NO_OWA :
551 E2K_AUTOCONFIG_FAILED;
555 /* Make sure it's not Exchange 5.5 */
556 if (ac->version == E2K_EXCHANGE_UNKNOWN &&
557 strstr (ac->owa_uri, "/logon.asp")) {
558 *result = E2K_AUTOCONFIG_EXCHANGE_5_5;
562 /* Make sure it's not trying to redirect us to Exchange 5.5 */
563 for (node = doc->children; node; node = e2k_xml_find (node, "meta")) {
564 gboolean ex55 = FALSE;
566 equiv = xmlGetProp (node, "http-equiv");
567 content = xmlGetProp (node, "content");
568 if (equiv && content &&
569 !g_ascii_strcasecmp (equiv, "REFRESH") &&
570 strstr (content, "/logon.asp"))
578 *result = E2K_AUTOCONFIG_EXCHANGE_5_5;
583 /* Try to find the base URI */
584 node = e2k_xml_find (doc->children, "base");
587 *result = E2K_AUTOCONFIG_OK;
588 href = xmlGetProp (node, "href");
589 g_free (ac->home_uri);
590 ac->home_uri = g_strdup (href);
593 *result = E2K_AUTOCONFIG_FAILED;
597 g_object_unref (msg);
599 if (*result != E2K_AUTOCONFIG_OK) {
600 g_object_unref (ctx);
606 static const char *home_properties[] = {
608 E2K_PR_EXCHANGE_TIMEZONE
610 static const int n_home_properties = sizeof (home_properties) / sizeof (home_properties[0]);
613 * e2k_autoconfig_check_exchange:
614 * @ac: an autoconfiguration context
615 * @op: an #E2kOperation, for cancellation
617 * Tries to connect to the the Exchange server using the OWA URL,
618 * username, and password in @ac. Attempts to determine the domain
619 * name and home_uri, and then given the home_uri, looks up the
620 * user's mailbox entryid (used to find his Exchange 5.5 DN) and
623 * The returned codes are the same as for e2k_autoconfig_get_context()
624 * with the following changes/additions/removals:
626 * %E2K_AUTOCONFIG_REDIRECT: URL returned in first redirect returned
627 * another redirect, which was not followed.
628 * %E2K_AUTOCONFIG_CANT_BPROPFIND: The server does not allow
629 * BPROPFIND due to IIS Lockdown configuration
630 * %E2K_AUTOCONFIG_TRY_SSL: Not used; always handled internally by
631 * e2k_autoconfig_check_exchange()
633 * Return value: an #E2kAutoconfigResult
635 * (If you change this comment, see the note at the top of this file.)
638 e2k_autoconfig_check_exchange (E2kAutoconfig *ac, E2kOperation *op)
642 E2kHTTPStatus status;
643 E2kAutoconfigResult result;
644 char *new_uri, *pf_uri;
646 gboolean redirected = FALSE;
650 const char *exchange_dn, *timezone, *hrefs[] = { "" };
656 g_return_val_if_fail (ac->owa_uri != NULL, E2K_AUTOCONFIG_FAILED);
657 g_return_val_if_fail (ac->username != NULL, E2K_AUTOCONFIG_FAILED);
658 g_return_val_if_fail (ac->password != NULL, E2K_AUTOCONFIG_FAILED);
661 ctx = e2k_autoconfig_get_context (ac, op, &result);
664 case E2K_AUTOCONFIG_OK:
667 case E2K_AUTOCONFIG_AUTH_ERROR_TRY_BASIC:
668 if (ac->use_ntlm && !ac->require_ntlm) {
669 ac->use_ntlm = FALSE;
672 return E2K_AUTOCONFIG_AUTH_ERROR;
674 case E2K_AUTOCONFIG_AUTH_ERROR_TRY_NTLM:
675 return E2K_AUTOCONFIG_AUTH_ERROR;
677 case E2K_AUTOCONFIG_REDIRECT:
684 case E2K_AUTOCONFIG_TRY_SSL:
687 case E2K_AUTOCONFIG_NO_OWA:
689 /* If the provided OWA URI had no path, try appending
692 euri = e2k_uri_new (ac->owa_uri);
693 g_return_val_if_fail (euri != NULL, result);
694 if (!euri->path || !strcmp (euri->path, "/")) {
696 new_uri = e2k_uri_concat (ac->owa_uri, "exchange/");
697 e2k_autoconfig_set_owa_uri (ac, new_uri);
705 /* Find the link to the public folders */
706 if (ac->version < E2K_EXCHANGE_2003)
707 pf_uri = g_strdup_printf ("%s/?Cmd=contents", ac->owa_uri);
709 pf_uri = g_strdup_printf ("%s/?Cmd=navbar", ac->owa_uri);
711 status = e2k_context_get_owa (ctx, NULL, pf_uri, FALSE, &body, &len);
713 if (E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
714 doc = e2k_parse_html (body, len);
720 for (node = e2k_xml_find (doc->children, "img"); node; node = e2k_xml_find (node, "img")) {
721 prop = xmlGetProp (node, "src");
722 if (prop && strstr (prop, "public") && node->parent) {
725 prop = xmlGetProp (node, "href");
727 euri = e2k_uri_new (prop);
728 ac->pf_server = g_strdup (euri->host);
737 g_warning ("Could not parse pf page");
739 /* Now find the store entryid and default timezone. We
740 * gratuitously use BPROPFIND in order to test if they
741 * have the IIS Lockdown problem.
743 iter = e2k_context_bpropfind_start (ctx, op,
744 ac->home_uri, hrefs, 1,
747 results = e2k_result_iter_next (iter);
749 timezone = e2k_properties_get_prop (results->props,
750 E2K_PR_EXCHANGE_TIMEZONE);
752 ac->timezone = find_olson_timezone (timezone);
754 entryid = e2k_properties_get_prop (results->props,
757 exchange_dn = e2k_entryid_to_dn (entryid);
759 ac->exchange_dn = g_strdup (exchange_dn);
762 status = e2k_result_iter_free (iter);
763 g_object_unref (ctx);
765 if (status == E2K_HTTP_UNAUTHORIZED) {
766 if (ac->use_ntlm && !ac->require_ntlm) {
767 ac->use_ntlm = FALSE;
770 return E2K_AUTOCONFIG_AUTH_ERROR;
771 } else if (status == E2K_HTTP_NOT_FOUND)
772 return E2K_AUTOCONFIG_CANT_BPROPFIND;
773 else if (status == E2K_HTTP_CANCELLED)
774 return E2K_AUTOCONFIG_CANCELLED;
775 else if (status == E2K_HTTP_CANT_RESOLVE)
776 return E2K_AUTOCONFIG_CANT_RESOLVE;
777 else if (E2K_HTTP_STATUS_IS_TRANSPORT_ERROR (status))
778 return E2K_AUTOCONFIG_CANT_CONNECT;
779 else if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status))
780 return E2K_AUTOCONFIG_FAILED;
782 return ac->exchange_dn ? E2K_AUTOCONFIG_OK : E2K_AUTOCONFIG_FAILED;
786 /* FIXME: make this cancellable */
788 find_global_catalog (E2kAutoconfig *ac)
792 unsigned char answer[1024], namebuf[1024], *end, *p;
793 guint16 type, qclass, rdlength, priority, weight, port;
800 len = res_querydomain ("_gc._tcp", ac->w2k_domain, C_IN, T_SRV,
801 answer, sizeof (answer));
805 header = (HEADER *)answer;
806 p = answer + sizeof (HEADER);
809 /* See RFCs 1035 and 2782 for details of the parsing */
812 count = ntohs (header->qdcount);
813 while (count-- && p < end) {
814 p += dn_expand (answer, end, p, namebuf, sizeof (namebuf));
819 while (count-- && p < end) {
820 p += dn_expand (answer, end, p, namebuf, sizeof (namebuf));
822 GETSHORT (qclass, p);
824 GETSHORT (rdlength, p);
826 if (type != T_SRV || qclass != C_IN) {
831 GETSHORT (priority, p);
832 GETSHORT (weight, p);
834 p += dn_expand (answer, end, p, namebuf, sizeof (namebuf));
836 /* FIXME: obey priority and weight */
837 ac->gc_server = g_strdup (namebuf);
838 ac->gc_server_autodetected = TRUE;
844 gchar *name, *casefolded_name;
845 PDNS_RECORD dnsrecp, rover;
847 name = g_strconcat ("_gc._tcp.", ac->w2k_domain, NULL);
848 casefolded_name = g_utf8_strdown (name, -1);
851 if (DnsQuery_UTF8 (casefolded_name, DNS_TYPE_SRV, DNS_QUERY_STANDARD,
852 NULL, &dnsrecp, NULL) != ERROR_SUCCESS) {
853 g_free (casefolded_name);
857 for (rover = dnsrecp; rover != NULL; rover = rover->pNext) {
858 if (rover->wType != DNS_TYPE_SRV ||
859 strcmp (rover->pName, casefolded_name) != 0)
861 ac->gc_server = g_strdup (rover->Data.SRV.pNameTarget);
862 ac->gc_server_autodetected = TRUE;
863 g_free (casefolded_name);
864 DnsRecordListFree (dnsrecp, DnsFreeRecordList);
868 g_free (casefolded_name);
869 DnsRecordListFree (dnsrecp, DnsFreeRecordList);
875 * e2k_autoconfig_get_global_catalog
876 * @ac: an autoconfig context
877 * @op: an #E2kOperation, for cancellation
879 * Tries to connect to the global catalog associated with @ac
880 * (trying to figure it out from the domain name if the server
881 * name is not yet known).
883 * Return value: the global catalog, or %NULL if the GC server name
884 * wasn't provided and couldn't be autodetected.
887 e2k_autoconfig_get_global_catalog (E2kAutoconfig *ac, E2kOperation *op)
889 if (!ac->gc_server) {
890 find_global_catalog (ac);
895 return e2k_global_catalog_new (ac->gc_server, ac->gal_limit,
896 ac->username, ac->nt_domain,
901 * e2k_autoconfig_check_global_catalog
902 * @ac: an autoconfig context
903 * @op: an #E2kOperation, for cancellation
905 * Tries to connect to the global catalog associated with @ac
906 * (trying to figure it out from the domain name if the server
907 * name is not yet known). On success it will look up the user's
908 * full name and email address (based on his Exchange DN).
910 * Possible return values are:
912 * %E2K_AUTOCONFIG_OK: Success
913 * %E2K_AUTOCONFIG_CANT_RESOLVE: Could not determine GC server
914 * %E2K_AUTOCONFIG_NO_MAILBOX: Could not find information for
916 * %E2K_AUTOCONFIG_AUTH_ERROR_TRY_DOMAIN: Plaintext password auth
917 * failed: need to specify NT domain
918 * %E2K_AUTOCONFIG_CANCELLED: Operation was cancelled
919 * %E2K_AUTOCONFIG_FAILED: Other error.
921 * Return value: an #E2kAutoconfigResult.
923 * (If you change this comment, see the note at the top of this file.)
926 e2k_autoconfig_check_global_catalog (E2kAutoconfig *ac, E2kOperation *op)
928 E2kGlobalCatalog *gc;
929 E2kGlobalCatalogEntry *entry;
930 E2kGlobalCatalogStatus status;
931 E2kAutoconfigResult result;
933 g_return_val_if_fail (ac->exchange_dn != NULL, E2K_AUTOCONFIG_FAILED);
935 gc = e2k_autoconfig_get_global_catalog (ac, op);
937 return E2K_AUTOCONFIG_CANT_RESOLVE;
939 set_account_uri_string (ac);
941 status = e2k_global_catalog_lookup (
942 gc, op, E2K_GLOBAL_CATALOG_LOOKUP_BY_LEGACY_EXCHANGE_DN,
943 ac->exchange_dn, E2K_GLOBAL_CATALOG_LOOKUP_EMAIL |
944 E2K_GLOBAL_CATALOG_LOOKUP_MAILBOX, &entry);
946 if (status == E2K_GLOBAL_CATALOG_OK) {
947 ac->display_name = g_strdup (entry->display_name);
948 ac->email = g_strdup (entry->email);
949 result = E2K_AUTOCONFIG_OK;
950 } else if (status == E2K_GLOBAL_CATALOG_CANCELLED)
951 result = E2K_AUTOCONFIG_CANCELLED;
952 #ifndef HAVE_LDAP_NTLM_BIND
953 else if (status == E2K_GLOBAL_CATALOG_AUTH_FAILED &&
955 result = E2K_AUTOCONFIG_AUTH_ERROR_TRY_DOMAIN;
957 else if (status == E2K_GLOBAL_CATALOG_ERROR)
958 result = E2K_AUTOCONFIG_FAILED;
960 result = E2K_AUTOCONFIG_NO_MAILBOX;
967 set_account_uri_string (E2kAutoconfig *ac)
969 E2kUri *owa_uri, *home_uri;
970 char *path, *mailbox;
973 owa_uri = e2k_uri_new (ac->owa_uri);
974 home_uri = e2k_uri_new (ac->home_uri);
976 uri = g_string_new ("exchange://");
977 if (ac->nt_domain && (!ac->use_ntlm || !ac->nt_domain_defaulted)) {
978 e2k_uri_append_encoded (uri, ac->nt_domain, FALSE, "\\;:@/");
979 g_string_append_c (uri, '\\');
981 e2k_uri_append_encoded (uri, ac->username, FALSE, ";:@/");
984 g_string_append (uri, ";auth=Basic");
986 g_string_append_c (uri, '@');
987 e2k_uri_append_encoded (uri, owa_uri->host, FALSE, ":/");
989 g_string_append_printf (uri, ":%d", owa_uri->port);
990 g_string_append_c (uri, '/');
992 if (!strcmp (owa_uri->protocol, "https"))
993 g_string_append (uri, ";use_ssl=always");
994 g_string_append (uri, ";ad_server=");
995 e2k_uri_append_encoded (uri, ac->gc_server, FALSE, ";?");
996 if (ac->gal_limit != -1)
997 g_string_append_printf (uri, ";ad_limit=%d", ac->gal_limit);
999 path = g_strdup (home_uri->path + 1);
1000 mailbox = strrchr (path, '/');
1001 if (mailbox && !mailbox[1]) {
1003 mailbox = strrchr (path, '/');
1007 g_string_append (uri, ";mailbox=");
1008 e2k_uri_append_encoded (uri, mailbox, FALSE, ";?");
1010 g_string_append (uri, ";owa_path=/");
1011 e2k_uri_append_encoded (uri, path, FALSE, ";?");
1014 g_string_append (uri, ";pf_server=");
1015 e2k_uri_append_encoded (uri, ac->pf_server ? ac->pf_server : home_uri->host, FALSE, ";?");
1017 ac->account_uri = uri->str;
1018 ac->exchange_server = g_strdup (home_uri->host);
1019 g_string_free (uri, FALSE);
1020 e2k_uri_free (home_uri);
1021 e2k_uri_free (owa_uri);
1025 /* Approximate mapping from Exchange timezones to Olson ones. Exchange
1026 * is less specific, so we factor in the language/country info from
1027 * the locale in our guess.
1029 * We strip " Standard Time" / " Daylight Time" from the Windows
1030 * timezone names. (Actually, we just strip the last two words.)
1033 const char *windows_name, *lang, *country, *olson_name;
1035 /* (GMT-12:00) Eniwetok, Kwajalein */
1036 { "Dateline", NULL, NULL, "Pacific/Kwajalein" },
1038 /* (GMT-11:00) Midway Island, Samoa */
1039 { "Samoa", NULL, NULL, "Pacific/Midway" },
1041 /* (GMT-10:00) Hawaii */
1042 { "Hawaiian", NULL, NULL, "Pacific/Honolulu" },
1044 /* (GMT-09:00) Alaska */
1045 { "Alaskan", NULL, NULL, "America/Juneau" },
1047 /* (GMT-08:00) Pacific Time (US & Canada); Tijuana */
1048 { "Pacific", NULL, "CA", "America/Vancouver" },
1049 { "Pacific", "es", "MX", "America/Tijuana" },
1050 { "Pacific", NULL, NULL, "America/Los_Angeles" },
1052 /* (GMT-07:00) Arizona */
1053 { "US Mountain", NULL, NULL, "America/Phoenix" },
1055 /* (GMT-07:00) Mountain Time (US & Canada) */
1056 { "Mountain", NULL, "CA", "America/Edmonton" },
1057 { "Mountain", NULL, NULL, "America/Denver" },
1059 /* (GMT-06:00) Central America */
1060 { "Central America", NULL, "BZ", "America/Belize" },
1061 { "Central America", NULL, "CR", "America/Costa_Rica" },
1062 { "Central America", NULL, "GT", "America/Guatemala" },
1063 { "Central America", NULL, "HN", "America/Tegucigalpa" },
1064 { "Central America", NULL, "NI", "America/Managua" },
1065 { "Central America", NULL, "SV", "America/El_Salvador" },
1067 /* (GMT-06:00) Central Time (US & Canada) */
1068 { "Central", NULL, NULL, "America/Chicago" },
1070 /* (GMT-06:00) Mexico City */
1071 { "Mexico", NULL, NULL, "America/Mexico_City" },
1073 /* (GMT-06:00) Saskatchewan */
1074 { "Canada Central", NULL, NULL, "America/Regina" },
1076 /* (GMT-05:00) Bogota, Lima, Quito */
1077 { "SA Pacific", NULL, "BO", "America/Bogota" },
1078 { "SA Pacific", NULL, "EC", "America/Guayaquil" },
1079 { "SA Pacific", NULL, "PA", "America/Panama" },
1080 { "SA Pacific", NULL, "PE", "America/Lima" },
1082 /* (GMT-05:00) Eastern Time (US & Canada) */
1083 { "Eastern", "fr", "CA", "America/Montreal" },
1084 { "Eastern", NULL, NULL, "America/New_York" },
1086 /* (GMT-05:00) Indiana (East) */
1087 { "US Eastern", NULL, NULL, "America/Indiana/Indianapolis" },
1089 /* (GMT-04:00) Atlantic Time (Canada) */
1090 { "Atlantic", "es", "US", "America/Puerto_Rico" },
1091 { "Atlantic", NULL, "VI", "America/St_Thomas" },
1092 { "Atlantic", NULL, "CA", "America/Halifax" },
1094 /* (GMT-04:00) Caracas, La Paz */
1095 { "SA Western", NULL, "BO", "America/La_Paz" },
1096 { "SA Western", NULL, "VE", "America/Caracas" },
1098 /* (GMT-04:00) Santiago */
1099 { "Pacific SA", NULL, NULL, "America/Santiago" },
1101 /* (GMT-03:30) Newfoundland */
1102 { "Newfoundland", NULL, NULL, "America/St_Johns" },
1104 /* (GMT-03:00) Brasilia */
1105 { "E. South America", NULL, NULL, "America/Sao_Paulo" },
1107 /* (GMT-03:00) Greenland */
1108 { "Greenland", NULL, NULL, "America/Godthab" },
1110 /* (GMT-03:00) Buenos Aires, Georgetown */
1111 { "SA Eastern", NULL, NULL, "America/Buenos_Aires" },
1113 /* (GMT-02:00) Mid-Atlantic */
1114 { "Mid-Atlantic", NULL, NULL, "America/Noronha" },
1116 /* (GMT-01:00) Azores */
1117 { "Azores", NULL, NULL, "Atlantic/Azores" },
1119 /* (GMT-01:00) Cape Verde Is. */
1120 { "Cape Verde", NULL, NULL, "Atlantic/Cape_Verde" },
1122 /* (GMT) Casablanca, Monrovia */
1123 { "Greenwich", NULL, "LR", "Africa/Monrovia" },
1124 { "Greenwich", NULL, "MA", "Africa/Casablanca" },
1126 /* (GMT) Greenwich Mean Time : Dublin, Edinburgh, Lisbon, London */
1127 { "GMT", "ga", "IE", "Europe/Dublin" },
1128 { "GMT", "pt", "PT", "Europe/Lisbon" },
1129 { "GMT", NULL, NULL, "Europe/London" },
1131 /* (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna */
1132 { "W. Europe", "nl", "NL", "Europe/Amsterdam" },
1133 { "W. Europe", "it", "IT", "Europe/Rome" },
1134 { "W. Europe", "sv", "SE", "Europe/Stockholm" },
1135 { "W. Europe", NULL, "CH", "Europe/Zurich" },
1136 { "W. Europe", NULL, "AT", "Europe/Vienna" },
1137 { "W. Europe", "de", "DE", "Europe/Berlin" },
1139 /* (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague */
1140 { "Central Europe", "sr", "YU", "Europe/Belgrade" },
1141 { "Central Europe", "sk", "SK", "Europe/Bratislava" },
1142 { "Central Europe", "hu", "HU", "Europe/Budapest" },
1143 { "Central Europe", "sl", "SI", "Europe/Ljubljana" },
1144 { "Central Europe", "cz", "CZ", "Europe/Prague" },
1146 /* (GMT+01:00) Brussels, Copenhagen, Madrid, Paris */
1147 { "Romance", NULL, "BE", "Europe/Brussels" },
1148 { "Romance", "da", "DK", "Europe/Copenhagen" },
1149 { "Romance", "es", "ES", "Europe/Madrid" },
1150 { "Romance", "fr", "FR", "Europe/Paris" },
1152 /* (GMT+01:00) Sarajevo, Skopje, Sofija, Vilnius, Warsaw, Zagreb */
1153 { "Central European", "bs", "BA", "Europe/Sarajevo" },
1154 { "Central European", "mk", "MK", "Europe/Skopje" },
1155 { "Central European", "bg", "BG", "Europe/Sofia" },
1156 { "Central European", "lt", "LT", "Europe/Vilnius" },
1157 { "Central European", "pl", "PL", "Europe/Warsaw" },
1158 { "Central European", "hr", "HR", "Europe/Zagreb" },
1160 /* (GMT+01:00) West Central Africa */
1161 { "W. Central Africa", NULL, NULL, "Africa/Kinshasa" },
1163 /* (GMT+02:00) Athens, Istanbul, Minsk */
1164 { "GTB", "el", "GR", "Europe/Athens" },
1165 { "GTB", "tr", "TR", "Europe/Istanbul" },
1166 { "GTB", "be", "BY", "Europe/Minsk" },
1168 /* (GMT+02:00) Bucharest */
1169 { "E. Europe", NULL, NULL, "Europe/Bucharest" },
1171 /* (GMT+02:00) Cairo */
1172 { "Egypt", NULL, NULL, "Africa/Cairo" },
1174 /* (GMT+02:00) Harare, Pretoria */
1175 { "South Africa", NULL, NULL, "Africa/Johannesburg" },
1177 /* (GMT+02:00) Helsinki, Riga, Tallinn */
1178 { "FLE", "lv", "LV", "Europe/Riga" },
1179 { "FLE", "et", "EE", "Europe/Tallinn" },
1180 { "FLE", "fi", "FI", "Europe/Helsinki" },
1182 /* (GMT+02:00) Jerusalem */
1183 { "Israel", NULL, NULL, "Asia/Jerusalem" },
1185 /* (GMT+03:00) Baghdad */
1186 { "Arabic", NULL, NULL, "Asia/Baghdad" },
1188 /* (GMT+03:00) Kuwait, Riyadh */
1189 { "Arab", NULL, "KW", "Asia/Kuwait" },
1190 { "Arab", NULL, "SA", "Asia/Riyadh" },
1192 /* (GMT+03:00) Moscow, St. Petersburg, Volgograd */
1193 { "Russian", NULL, NULL, "Europe/Moscow" },
1195 /* (GMT+03:00) Nairobi */
1196 { "E. Africa", NULL, NULL, "Africa/Nairobi" },
1198 /* (GMT+03:30) Tehran */
1199 { "Iran", NULL, NULL, "Asia/Tehran" },
1201 /* (GMT+04:00) Abu Dhabi, Muscat */
1202 { "Arabian", NULL, NULL, "Asia/Muscat" },
1204 /* (GMT+04:00) Baku, Tbilisi, Yerevan */
1205 { "Caucasus", NULL, NULL, "Asia/Baku" },
1207 /* (GMT+04:30) Kabul */
1208 { "Afghanistan", NULL, NULL, "Asia/Kabul" },
1210 /* (GMT+05:00) Ekaterinburg */
1211 { "Ekaterinburg", NULL, NULL, "Asia/Yekaterinburg" },
1213 /* (GMT+05:00) Islamabad, Karachi, Tashkent */
1214 { "West Asia", NULL, NULL, "Asia/Karachi" },
1216 /* (GMT+05:30) Kolkata, Chennai, Mumbai, New Delhi */
1217 { "India", NULL, NULL, "Asia/Calcutta" },
1219 /* (GMT+05:45) Kathmandu */
1220 { "Nepal", NULL, NULL, "Asia/Katmandu" },
1222 /* (GMT+06:00) Almaty, Novosibirsk */
1223 { "N. Central Asia", NULL, NULL, "Asia/Almaty" },
1225 /* (GMT+06:00) Astana, Dhaka */
1226 { "Central Asia", NULL, NULL, "Asia/Dhaka" },
1228 /* (GMT+06:00) Sri Jayawardenepura */
1229 { "Sri Lanka", NULL, NULL, "Asia/Colombo" },
1231 /* (GMT+06:30) Rangoon */
1232 { "Myanmar", NULL, NULL, "Asia/Rangoon" },
1234 /* (GMT+07:00) Bangkok, Hanoi, Jakarta */
1235 { "SE Asia", "th", "TH", "Asia/Bangkok" },
1236 { "SE Asia", "vi", "VN", "Asia/Saigon" },
1237 { "SE Asia", "id", "ID", "Asia/Jakarta" },
1239 /* (GMT+07:00) Krasnoyarsk */
1240 { "North Asia", NULL, NULL, "Asia/Krasnoyarsk" },
1242 /* (GMT+08:00) Beijing, Chongqing, Hong Kong, Urumqi */
1243 { "China", NULL, "HK", "Asia/Hong_Kong" },
1244 { "China", NULL, NULL, "Asia/Shanghai" },
1246 /* (GMT+08:00) Irkutsk, Ulaan Bataar */
1247 { "North Asia East", NULL, NULL, "Asia/Irkutsk" },
1249 /* (GMT+08:00) Perth */
1250 { "W. Australia", NULL, NULL, "Australia/Perth" },
1252 /* (GMT+08:00) Kuala Lumpur, Singapore */
1253 { "Singapore", NULL, NULL, "Asia/Kuala_Lumpur" },
1255 /* (GMT+08:00) Taipei */
1256 { "Taipei", NULL, NULL, "Asia/Taipei" },
1258 /* (GMT+09:00) Osaka, Sapporo, Tokyo */
1259 { "Tokyo", NULL, NULL, "Asia/Tokyo" },
1261 /* (GMT+09:00) Seoul */
1262 { "Korea", NULL, "KP", "Asia/Pyongyang" },
1263 { "Korea", NULL, "KR", "Asia/Seoul" },
1265 /* (GMT+09:00) Yakutsk */
1266 { "Yakutsk", NULL, NULL, "Asia/Yakutsk" },
1268 /* (GMT+09:30) Adelaide */
1269 { "Cen. Australia", NULL, NULL, "Australia/Adelaide" },
1271 /* (GMT+09:30) Darwin */
1272 { "AUS Central", NULL, NULL, "Australia/Darwin" },
1274 /* (GMT+10:00) Brisbane */
1275 { "E. Australia", NULL, NULL, "Australia/Brisbane" },
1277 /* (GMT+10:00) Canberra, Melbourne, Sydney */
1278 { "AUS Eastern", NULL, NULL, "Australia/Sydney" },
1280 /* (GMT+10:00) Guam, Port Moresby */
1281 { "West Pacific", NULL, NULL, "Pacific/Guam" },
1283 /* (GMT+10:00) Hobart */
1284 { "Tasmania", NULL, NULL, "Australia/Hobart" },
1286 /* (GMT+10:00) Vladivostok */
1287 { "Vladivostok", NULL, NULL, "Asia/Vladivostok" },
1289 /* (GMT+11:00) Magadan, Solomon Is., New Caledonia */
1290 { "Central Pacific", NULL, NULL, "Pacific/Midway" },
1292 /* (GMT+12:00) Auckland, Wellington */
1293 { "New Zealand", NULL, NULL, "Pacific/Auckland" },
1295 /* (GMT+12:00) Fiji, Kamchatka, Marshall Is. */
1296 { "Fiji", "ru", "RU", "Asia/Kamchatka" },
1297 { "Fiji", NULL, NULL, "Pacific/Fiji" },
1299 /* (GMT+13:00) Nuku'alofa */
1300 { "Tonga", NULL, NULL, "Pacific/Tongatapu" }
1302 static const int n_zone_mappings = sizeof (zonemap) / sizeof (zonemap[0]);
1305 find_olson_timezone (const char *windows_timezone)
1308 const char *locale, *p;
1309 char lang[3] = { 0 }, country[3] = { 0 };
1311 /* Strip " Standard Time" / " Daylight Time" from name */
1312 p = windows_timezone + strlen (windows_timezone) - 1;
1313 while (p > windows_timezone && *p-- != ' ')
1315 while (p > windows_timezone && *p-- != ' ')
1317 tzlen = p - windows_timezone + 1;
1319 /* Find the first entry in zonemap with a matching name */
1320 for (i = 0; i < n_zone_mappings; i++) {
1321 if (!g_ascii_strncasecmp (windows_timezone,
1322 zonemap[i].windows_name,
1326 if (i == n_zone_mappings)
1327 return NULL; /* Shouldn't happen... */
1329 /* If there's only one choice, go with it */
1330 if (!zonemap[i].lang && !zonemap[i].country)
1331 return g_strdup (zonemap[i].olson_name);
1333 /* Find our language/country (hopefully). */
1335 locale = getenv ("LANG");
1337 locale = g_win32_getlocale ();
1340 strncpy (lang, locale, 2);
1341 locale = strchr (locale, '_');
1343 strncpy (country, locale, 2);
1346 g_free ((char *) locale);
1349 /* Look for an entry where either the country or the
1353 if ((zonemap[i].lang && !strcmp (zonemap[i].lang, lang)) ||
1354 (zonemap[i].country && !strcmp (zonemap[i].country, country)))
1355 return g_strdup (zonemap[i].olson_name);
1356 } while (++i < n_zone_mappings &&
1357 !g_ascii_strncasecmp (windows_timezone,
1358 zonemap[i].windows_name,
1361 /* None of the hints matched, so (semi-arbitrarily) return the
1362 * last of the entries with the right Windows timezone name.
1364 return g_strdup (zonemap[i - 1].olson_name);
1368 /* Config file handling */
1370 static GHashTable *config_options;
1376 char *p, *name, *value;
1380 config_options = g_hash_table_new (e2k_ascii_strcase_hash,
1381 e2k_ascii_strcase_equal);
1384 fd = g_open ("/etc/ximian/connector.conf", O_RDONLY, 0);
1387 gchar *filename = g_build_filename (CONNECTOR_PREFIX,
1388 "etc/connector.conf",
1391 fd = g_open (filename, O_RDONLY, 0);
1396 if (fstat (fd, &st) == -1) {
1397 g_warning ("Could not stat connector.conf: %s",
1398 g_strerror (errno));
1403 config_data = g_malloc (st.st_size + 1);
1404 if (read (fd, config_data, st.st_size) != st.st_size) {
1405 g_warning ("Could not read connector.conf: %s",
1406 g_strerror (errno));
1408 g_free (config_data);
1412 config_data[st.st_size] = '\0';
1414 /* Read config data */
1418 for (name = p; isspace ((unsigned char)*name); name++)
1421 p = strchr (name, ':');
1426 p = strchr (value, '\n');
1429 if (*(p - 1) == '\r')
1434 if (g_ascii_strcasecmp (value, "false") &&
1435 g_ascii_strcasecmp (value, "no"))
1436 g_hash_table_insert (config_options, name, value);
1439 g_free (config_data);
1443 * e2k_autoconfig_lookup_option:
1444 * @option: option name to look up
1446 * Looks up an autoconfiguration hint in the config file (if present)
1448 * Return value: the string value of the option, or %NULL if it is unset.
1451 e2k_autoconfig_lookup_option (const char *option)
1453 if (!config_options)
1455 return g_hash_table_lookup (config_options, option);
1459 validate (const char *owa_url, char *user, char *password, ExchangeParams *exchange_params, E2kAutoconfigResult *result)
1462 E2kOperation op; /* FIXME */
1464 gboolean valid = FALSE;
1465 const char *old, *new;
1466 char *path, *mailbox;
1468 ac = e2k_autoconfig_new (owa_url, user, password,
1469 E2K_AUTOCONFIG_USE_EITHER);
1471 e2k_operation_init (&op);
1472 // e2k_autoconfig_set_gc_server (ac, ad_server, gal_limit) FIXME
1473 // e2k_autoconfig_set_gc_server (ac, NULL, -1);
1474 *result = e2k_autoconfig_check_exchange (ac, &op);
1476 if (*result == E2K_AUTOCONFIG_OK) {
1478 * On error code 403 and SSL seen in server response
1479 * e2k_autoconfig_get_context() tries to
1480 * connect using https if owa url has http and vice versa.
1481 * And also re-sets the owa_uri in E2kAutoconfig.
1482 * So even if the uri is incorrect,
1483 * e2k_autoconfig_check_exchange() will return success.
1484 * In this case of account set up, owa_url paramter will still
1485 * have wrong url entered, and we throw the error, instead of
1486 * going ahead with account setup and failing later.
1488 if (g_str_has_prefix (ac->owa_uri, "http:")) {
1489 if (!g_str_has_prefix (owa_url, "http:"))
1490 *result = E2K_AUTOCONFIG_CANT_CONNECT;
1492 else if (!g_str_has_prefix (owa_url, "https:"))
1493 *result = E2K_AUTOCONFIG_CANT_CONNECT;
1496 if (*result == E2K_AUTOCONFIG_OK) {
1497 *result = e2k_autoconfig_check_global_catalog (ac, &op);
1498 e2k_operation_free (&op);
1500 /* find mailbox and owa_path values */
1501 euri = e2k_uri_new (ac->home_uri);
1502 path = g_strdup (euri->path + 1);
1503 e2k_uri_free (euri);
1504 mailbox = strrchr (path, '/');
1505 if (mailbox && !mailbox[1]) {
1507 mailbox = strrchr (path, '/');
1512 exchange_params->mailbox = g_strdup (mailbox);
1513 exchange_params->owa_path = g_strdup_printf ("%s%s", "/", path);
1515 exchange_params->host = g_strdup (ac->pf_server);
1517 exchange_params->ad_server = g_strdup (ac->gc_server);
1518 exchange_params->is_ntlm = ac->saw_ntlm;
1525 case E2K_AUTOCONFIG_CANT_CONNECT:
1526 if (!strncmp (ac->owa_uri, "http:", 5)) {
1534 /* SURF : e_notice (NULL, GTK_MESSAGE_ERROR,
1535 _("Could not connect to the Exchange "
1536 "server.\nMake sure the URL is correct "
1537 "(try \"%s\" instead of \"%s\"?) "
1538 "and try again."), new, old);
1543 case E2K_AUTOCONFIG_CANT_RESOLVE:
1544 /* SURF : e_notice (NULL, GTK_MESSAGE_ERROR,
1545 _("Could not locate Exchange server.\n"
1546 "Make sure the server name is spelled correctly "
1552 case E2K_AUTOCONFIG_AUTH_ERROR:
1553 case E2K_AUTOCONFIG_AUTH_ERROR_TRY_NTLM:
1554 case E2K_AUTOCONFIG_AUTH_ERROR_TRY_BASIC:
1555 /* SURF : e_notice (NULL, GTK_MESSAGE_ERROR,
1556 _("Could not authenticate to the Exchange "
1557 "server.\nMake sure the username and "
1558 "password are correct and try again."));
1563 case E2K_AUTOCONFIG_AUTH_ERROR_TRY_DOMAIN:
1564 /* SURF : e_notice (NULL, GTK_MESSAGE_ERROR,
1565 _("Could not authenticate to the Exchange "
1566 "server.\nMake sure the username and "
1567 "password are correct and try again.\n\n"
1568 "You may need to specify the Windows "
1569 "domain name as part of your username "
1570 "(eg, \"MY-DOMAIN\\%s\")."),
1576 case E2K_AUTOCONFIG_NO_OWA:
1577 case E2K_AUTOCONFIG_NOT_EXCHANGE:
1578 /* SURF : e_notice (NULL, GTK_MESSAGE_ERROR,
1579 _("Could not find OWA data at the indicated URL.\n"
1580 "Make sure the URL is correct and try again."));
1585 case E2K_AUTOCONFIG_CANT_BPROPFIND:
1586 /* SURF : e_notice (
1587 NULL, GTK_MESSAGE_ERROR,
1588 _("Ximian Connector requires access to certain "
1589 "functionality on the Exchange Server that appears "
1590 "to be disabled or blocked. (This is usually "
1591 "unintentional.) Your Exchange Administrator will "
1592 "need to enable this functionality in order for "
1593 "you to be able to use Ximian Connector.\n\n"
1594 "For information to provide to your Exchange "
1595 "administrator, please follow the link below:\n"
1596 "http://support.novell.com/cgi-bin/search/searchtid.cgi?/ximian/ximian328.html "));
1601 case E2K_AUTOCONFIG_EXCHANGE_5_5:
1602 /* SURF : e_notice (
1603 NULL, GTK_MESSAGE_ERROR,
1604 _("The Exchange server URL you provided is for an "
1605 "Exchange 5.5 Server. Ximian Connector supports "
1606 "Microsoft Exchange 2000 and 2003 only."));
1612 /* SURF : e_notice (NULL, GTK_MESSAGE_ERROR,
1613 _("Could not configure Exchange account because "
1614 "an unknown error occurred. Check the URL, "
1615 "username, and password, and try again."));
1617 valid = FALSE; /* FIXME return valid */
1622 e2k_autoconfig_free (ac);
1627 e2k_validate_user (const char *owa_url, char *pkey, char **user,
1628 ExchangeParams *exchange_params, gboolean *remember_password,
1629 E2kAutoconfigResult *result, GtkWindow *parent)
1631 gboolean valid = FALSE, remember=FALSE;
1632 char *key, *password, *prompt;
1638 uri = e_uri_new (owa_url);
1639 key = g_strdup_printf ("%s%s/", pkey, uri->host); /* FIXME */
1643 username = g_strdup (*user);
1646 password = e_passwords_get_password ("Exchange", key);
1648 /* This can be the case, where user presses authenticate button and
1649 * later cancels the account setup or removal of account fails for
1650 * some reason. We need to prompt for the password always when
1651 * authenticate button is pressed */
1652 e_passwords_forget_password ("Exchange", key);
1655 prompt = g_strdup_printf (_("Enter password for %s"), username);
1656 password = e_passwords_ask_password (_("Enter password"),
1657 "Exchange", key, prompt,
1658 E_PASSWORDS_REMEMBER_FOREVER|E_PASSWORDS_SECRET,
1664 *result = E2K_AUTOCONFIG_CANCELLED;
1668 valid = validate (owa_url, username, password, exchange_params, result);
1670 /* generate the proper key once the host name
1671 * is read and remember password temporarily,
1672 * so that at the end of * account creation,
1673 * user will not be prompted, for password will
1674 * not be asked again.
1676 *remember_password = remember;
1678 if (exchange_params->is_ntlm)
1679 key = g_strdup_printf ("exchange://%s;auth=NTLM@%s/",
1680 username, exchange_params->host);
1682 key = g_strdup_printf ("exchange://%s@%s/", username, exchange_params->host);
1683 e_passwords_add_password (key, password);
1684 e_passwords_remember_password ("Exchange", key);
1688 /* Check for name as e-mail id and try once again
1689 * extracing username from e-mail id.
1691 usernames = g_strsplit (*user, "@", 2);
1692 if (usernames && usernames[0] && usernames[1]) {
1693 username = g_strdup (usernames[0]);
1694 g_strfreev (usernames);
1696 memset(*user, 0, strlen(*user));
1698 *user = g_strdup (username);
1700 goto try_auth_again;
1703 /* if validation failed*/
1704 e_passwords_forget_password ("Exchange", key);