Updated Spanish translation
[anjuta-git-plugin.git] / plugins / subversion / svn-command.c
blobc6039a2a0b7106ad3c209a2d93f1df7cba025aea
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta
4 * Copyright (C) James Liggett 2007 <jrliggett@cox.net>
5 *
6 * anjuta is free software.
7 *
8 * You may redistribute it and/or modify it under the terms of the
9 * GNU General Public License, as published by the Free Software
10 * Foundation; either version 2 of the License, or (at your option)
11 * any later version.
13 * anjuta is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 * See the GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with anjuta. If not, write to:
20 * The Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02110-1301, USA.
25 #include "svn-command.h"
27 struct _SvnCommandPriv
29 svn_client_ctx_t *client_context;
30 apr_pool_t *pool;
31 GQueue *info_messages;
32 GMutex *ui_lock;
33 gboolean main_thread_has_ui_lock;
36 G_DEFINE_TYPE (SvnCommand, svn_command, ANJUTA_TYPE_ASYNC_COMMAND);
38 static gboolean
39 svn_command_acquire_ui_lock (SvnCommand *self)
41 gboolean got_lock;
43 if (!self->priv->main_thread_has_ui_lock)
45 got_lock = g_mutex_trylock (self->priv->ui_lock);
47 if (got_lock)
48 self->priv->main_thread_has_ui_lock = TRUE;
50 return !got_lock;
52 else
53 return FALSE;
56 static gboolean
57 svn_command_release_ui_lock (GMutex *ui_lock)
59 g_mutex_unlock (ui_lock);
60 g_mutex_free (ui_lock);
62 return FALSE;
65 /* Auth functions */
66 /* In order to prevent deadlocking when Subversion prompts for something, we
67 * have to make sure that no GTK calls are made from the command threads by way
68 * of the authentication baton. To do this, the dialog code will be called from
69 * idle sources. */
71 /* svn_auth_simple_prompt_func_cb argumements */
72 typedef struct
74 svn_auth_cred_simple_t **cred;
75 void *baton;
76 gchar *realm;
77 gchar *username;
78 svn_boolean_t may_save;
79 apr_pool_t *pool;
80 svn_error_t *error;
81 } SimplePromptArgs;
83 /* svn_auth_ssl_server_trust_prompt_func_cb arguements */
84 typedef struct
86 svn_auth_cred_ssl_server_trust_t **cred;
87 void *baton;
88 gchar *realm;
89 apr_uint32_t failures;
90 svn_auth_ssl_server_cert_info_t *cert_info;
91 svn_boolean_t may_save;
92 apr_pool_t *pool;
93 svn_error_t *error;
94 } SSLServerTrustArgs;
96 static gboolean
97 simple_prompt (SimplePromptArgs *args)
99 GladeXML* gxml = glade_xml_new(GLADE_FILE, "svn_user_auth", NULL);
100 GtkWidget* svn_user_auth = glade_xml_get_widget(gxml, "svn_user_auth");
101 GtkWidget* auth_realm = glade_xml_get_widget(gxml, "auth_realm");
102 GtkWidget* username_entry = glade_xml_get_widget(gxml, "username_entry");
103 GtkWidget* password_entry = glade_xml_get_widget(gxml, "password_entry");
104 GtkWidget* remember_pwd = glade_xml_get_widget(gxml, "remember_pwd");
105 svn_error_t *err = NULL;
106 SvnCommand *svn_command;
108 gtk_dialog_set_default_response (GTK_DIALOG (svn_user_auth), GTK_RESPONSE_OK);
110 if (args->realm)
111 gtk_label_set_text (GTK_LABEL (auth_realm), args->realm);
112 if (args->username)
114 gtk_entry_set_text (GTK_ENTRY (username_entry), args->username);
115 gtk_widget_grab_focus (password_entry);
117 if (!args->may_save)
118 gtk_widget_set_sensitive(remember_pwd, FALSE);
120 /* Then the dialog is prompted to user and when user clicks ok, the
121 * values entered, i.e username, password and remember password (true
122 * by default) should be used to initialized the memebers below. If the
123 * user cancels the dialog, I think we return an error struct
124 * appropriately initialized. -- naba
127 switch (gtk_dialog_run(GTK_DIALOG(svn_user_auth)))
129 case GTK_RESPONSE_OK:
131 *args->cred = apr_pcalloc (args->pool, sizeof(*(args->cred)));
132 (*(args->cred))->may_save = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
133 (remember_pwd));
134 (*(args->cred))->username = apr_pstrdup (args->pool,
135 gtk_entry_get_text(GTK_ENTRY(username_entry)));
136 (*(args->cred))->password = apr_pstrdup (args->pool,
137 gtk_entry_get_text(GTK_ENTRY(password_entry)));
139 err = SVN_NO_ERROR;
140 break;
142 default:
143 err = svn_error_create (SVN_ERR_AUTHN_CREDS_UNAVAILABLE, NULL,
144 _("Authentication canceled"));
146 break;
148 gtk_widget_destroy (svn_user_auth);
149 args->error = err;
151 /* Release because main thread should already have the lock */
152 svn_command = SVN_COMMAND (args->baton);
153 svn_command_unlock_ui (svn_command);
155 return FALSE;
158 static gboolean
159 ssl_server_trust_prompt (SSLServerTrustArgs *args)
161 GladeXML* gxml = glade_xml_new(GLADE_FILE, "svn_server_trust", NULL);
162 GtkWidget* svn_server_trust = glade_xml_get_widget(gxml, "svn_server_trust");
163 GtkWidget* auth_realm = glade_xml_get_widget(gxml, "realm_label");
164 GtkWidget* server_info = glade_xml_get_widget(gxml, "server_info_label");
165 GtkWidget* remember_check = glade_xml_get_widget(gxml, "remember_check");
166 svn_error_t *err = NULL;
167 gchar* info;
168 SvnCommand *svn_command;
170 if (args->realm)
171 gtk_label_set_text (GTK_LABEL (auth_realm), args->realm);
173 info = g_strconcat(_("Hostname: "), args->cert_info->hostname, "\n",
174 _("Fingerprint: "), args->cert_info->fingerprint, "\n",
175 _("Valid from: "), args->cert_info->valid_from, "\n",
176 _("Valid until: "), args->cert_info->valid_until, "\n",
177 _("Issuer DN: "), args->cert_info->issuer_dname, "\n",
178 _("DER certificate: "), args->cert_info->ascii_cert, "\n",
179 NULL);
180 gtk_label_set_text (GTK_LABEL (server_info), info);
182 if (!args->may_save)
183 gtk_widget_set_sensitive(remember_check, FALSE);
185 gtk_dialog_set_default_response (GTK_DIALOG (svn_server_trust), GTK_RESPONSE_YES);
188 switch (gtk_dialog_run(GTK_DIALOG(svn_server_trust)))
190 case GTK_RESPONSE_YES:
191 *args->cred = apr_pcalloc (args->pool,
192 sizeof(*(args->cred)));
193 (*(args->cred))->may_save = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
194 (remember_check));
195 err = SVN_NO_ERROR;
196 /* TODO: Set bitmask for accepted_failures */
197 break;
198 default:
199 err = svn_error_create (SVN_ERR_AUTHN_CREDS_UNAVAILABLE, NULL,
200 _("Authentication canceled"));
201 break;
203 gtk_widget_destroy (svn_server_trust);
204 args->error = err;
206 /* Release because main thread should already have the lock */
207 svn_command = SVN_COMMAND (args->baton);
208 svn_command_unlock_ui (svn_command);
210 return FALSE;
213 /* User authentication prompts handlers */
214 static svn_error_t*
215 svn_auth_simple_prompt_func_cb (svn_auth_cred_simple_t **cred, void *baton,
216 const char *realm, const char *username,
217 svn_boolean_t may_save, apr_pool_t *pool)
219 SimplePromptArgs *args;
220 SvnCommand *svn_command;
221 svn_error_t *error;
223 args = g_new0 (SimplePromptArgs, 1);
224 args->cred = cred;
225 args->baton = baton;
226 args->realm = g_strdup (realm);
227 args->username = g_strdup (username);
228 args->may_save = may_save;
229 args->pool = pool;
231 svn_command = SVN_COMMAND (baton);
233 g_idle_add ((GSourceFunc) simple_prompt, args);
235 svn_command_lock_ui (svn_command);
236 svn_command_unlock_ui (svn_command);
238 error = args->error;
239 g_free (args->realm);
240 g_free (args->username);
241 g_free (args);
243 return error;
247 static svn_error_t*
248 svn_auth_ssl_server_trust_prompt_func_cb (svn_auth_cred_ssl_server_trust_t **cred,
249 void *baton, const char *realm,
250 apr_uint32_t failures,
251 const svn_auth_ssl_server_cert_info_t *cert_info,
252 svn_boolean_t may_save,
253 apr_pool_t *pool)
255 SSLServerTrustArgs *args;
256 SvnCommand *svn_command;
257 svn_error_t *error;
259 args = g_new0 (SSLServerTrustArgs, 1);
260 args->cred = cred;
261 args->baton = baton;
262 args->realm = g_strdup (realm);
263 args->failures = failures;
264 args->cert_info = g_memdup (cert_info,
265 sizeof (svn_auth_ssl_server_cert_info_t));
266 args->may_save = may_save;
267 args->pool = pool;
269 svn_command = SVN_COMMAND (baton);
271 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
272 (GSourceFunc) ssl_server_trust_prompt, args, NULL);
274 svn_command_lock_ui (svn_command);
275 svn_command_unlock_ui (svn_command);
277 error = args->error;
278 g_free (args->realm);
279 g_free (args->cert_info);
280 g_free (args);
282 return error;
285 static svn_error_t*
286 svn_auth_ssl_client_cert_prompt_func_cb (svn_auth_cred_ssl_client_cert_t **cred,
287 void *baton, const char *realm,
288 svn_boolean_t may_save,
289 apr_pool_t *pool)
292 /* Ask for the file where client certificate of authenticity is.
293 * I think it is some sort of private key. */
294 return SVN_NO_ERROR;
297 static svn_error_t*
298 svn_auth_ssl_client_cert_pw_prompt_func_cb (svn_auth_cred_ssl_client_cert_pw_t **cred,
299 void *baton, const char *realm,
300 svn_boolean_t may_save,
301 apr_pool_t *pool)
304 /* Prompt for password only. I think it is pass-phrase of the above key. */
305 return SVN_NO_ERROR;;
308 /* Notification callback to handle notifications from Subversion itself */
309 static void
310 on_svn_notify (gpointer baton,
311 const svn_wc_notify_t *notify,
312 apr_pool_t *pool)
314 SvnCommand *self;
315 gchar *action_message;
316 gchar *state_message;
318 self = SVN_COMMAND (baton);
319 action_message = NULL;
320 state_message = NULL;
322 switch (notify->action)
324 case svn_wc_notify_delete:
325 action_message = g_strdup_printf (_("Deleted: %s"), notify->path);
326 break;
327 case svn_wc_notify_add:
328 action_message = g_strdup_printf (_("Added: %s"), notify->path);
329 break;
330 case svn_wc_notify_revert:
331 action_message = g_strdup_printf ("Reverted: %s", notify->path);
332 break;
333 case svn_wc_notify_failed_revert:
334 action_message = g_strdup_printf ("Revert failed: %s",
335 notify->path);
336 break;
337 case svn_wc_notify_resolved:
338 action_message = g_strdup_printf (_("Resolved: %s"), notify->path);
339 case svn_wc_notify_update_delete:
340 action_message = g_strdup_printf (_("Deleted: %s"), notify->path);
341 break;
342 case svn_wc_notify_update_update:
343 action_message = g_strdup_printf (_("Updated: %s"), notify->path);
344 break;
345 case svn_wc_notify_update_add:
346 action_message = g_strdup_printf (_("Added: %s"), notify->path);
347 break;
348 case svn_wc_notify_update_external:
349 action_message = g_strdup_printf (_("Externally Updated: %s"),
350 notify->path);
351 break;
352 case svn_wc_notify_commit_modified:
353 action_message = g_strdup_printf ("Commit Modified: %s",
354 notify->path);
355 break;
356 case svn_wc_notify_commit_added:
357 action_message = g_strdup_printf ("Commit Added: %s", notify->path);
358 break;
359 case svn_wc_notify_commit_deleted:
360 action_message = g_strdup_printf ("Commit Deleted: %s",
361 notify->path);
362 break;
363 case svn_wc_notify_commit_replaced:
364 action_message = g_strdup_printf ("Commit Replaced: %s",
365 notify->path);
366 break;
367 case svn_wc_notify_copy:
368 action_message = g_strdup_printf ("Created File: %s", notify->path);
369 break;
370 default:
371 break;
374 if (action_message)
376 svn_command_push_info (self, action_message);
377 g_free (action_message);
380 switch (notify->content_state)
382 case svn_wc_notify_state_changed:
383 state_message = g_strdup_printf (_("Modified: %s"), notify->path);
384 break;
385 case svn_wc_notify_state_merged:
386 state_message = g_strdup_printf (_("Merged: %s"), notify->path);
387 break;
388 case svn_wc_notify_state_conflicted:
389 state_message = g_strdup_printf (_("Conflicted: %s"),
390 notify->path);
391 break;
392 case svn_wc_notify_state_missing:
393 state_message = g_strdup_printf (_("Missing: %s"), notify->path);
394 break;
395 case svn_wc_notify_state_obstructed:
396 state_message = g_strdup_printf (_("Obstructed: %s"), notify->path);
397 break;
398 default:
399 break;
402 if (state_message)
404 svn_command_push_info (self, state_message);
405 g_free (state_message);
409 static void
410 svn_command_init (SvnCommand *self)
412 svn_auth_baton_t *auth_baton;
413 apr_array_header_t *providers;
414 svn_auth_provider_object_t *provider;
416 self->priv = g_new0 (SvnCommandPriv, 1);
418 self->priv->pool = svn_pool_create (NULL);
419 svn_client_create_context (&self->priv->client_context, self->priv->pool);
420 self->priv->client_context->notify_func2 = on_svn_notify;
421 self->priv->client_context->notify_baton2 = self;
423 svn_config_get_config (&(self->priv->client_context)->config,
424 NULL, /* default dir */
425 self->priv->pool);
427 self->priv->info_messages = g_queue_new ();
428 self->priv->ui_lock = g_mutex_new ();
430 /* Make sure that the main thread holds the lock */
431 g_idle_add ((GSourceFunc) svn_command_acquire_ui_lock, self);
433 /* Fill in the auth baton callbacks */
434 providers = apr_array_make (self->priv->pool, 1,
435 sizeof (svn_auth_provider_object_t *));
437 /* Provider that authenticates username/password from ~/.subversion */
438 provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
439 svn_client_get_simple_provider (&provider, self->priv->pool);
440 *(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
442 /* Provider that authenticates server trust from ~/.subversion */
443 provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
444 svn_client_get_ssl_server_trust_file_provider (&provider, self->priv->pool);
445 *(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
447 /* Provider that authenticates client cert from ~/.subversion */
448 provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
449 svn_client_get_ssl_client_cert_file_provider (&provider, self->priv->pool);
450 *(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
452 /* Provider that authenticates client cert password from ~/.subversion */
453 provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
454 svn_client_get_ssl_client_cert_pw_file_provider (&provider,
455 self->priv->pool);
456 *(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
458 /* Provider that prompts for username/password */
459 provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
460 svn_client_get_simple_prompt_provider(&provider,
461 svn_auth_simple_prompt_func_cb,
462 self, 3, self->priv->pool);
463 *(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
465 /* Provider that prompts for server trust */
466 provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
467 svn_client_get_ssl_server_trust_prompt_provider (&provider,
468 svn_auth_ssl_server_trust_prompt_func_cb,
469 self,
470 self->priv->pool);
471 *(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
473 /* Provider that prompts for client certificate file */
474 provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
475 svn_client_get_ssl_client_cert_prompt_provider (&provider,
476 svn_auth_ssl_client_cert_prompt_func_cb,
477 NULL, 3, self->priv->pool);
478 *(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
480 /* Provider that prompts for client certificate file password */
481 provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
482 svn_client_get_ssl_client_cert_pw_prompt_provider (&provider,
483 svn_auth_ssl_client_cert_pw_prompt_func_cb,
484 NULL, 3,
485 self->priv->pool);
486 *(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
488 svn_auth_open (&auth_baton, providers, self->priv->pool);
489 self->priv->client_context->auth_baton = auth_baton;
493 static void
494 svn_command_finalize (GObject *object)
496 SvnCommand *self;
497 GList *current_message_line;
499 self = SVN_COMMAND (object);
501 svn_pool_clear (self->priv->pool);
503 current_message_line = self->priv->info_messages->head;
505 while (current_message_line)
507 g_free (current_message_line->data);
508 current_message_line = g_list_next (current_message_line);
511 g_idle_add ((GSourceFunc) svn_command_release_ui_lock, self->priv->ui_lock);
513 g_queue_free (self->priv->info_messages);
514 g_free (self->priv);
516 G_OBJECT_CLASS (svn_command_parent_class)->finalize (object);
519 static void
520 svn_command_class_init (SvnCommandClass *klass)
522 GObjectClass* object_class = G_OBJECT_CLASS (klass);
524 object_class->finalize = svn_command_finalize;
528 void
529 svn_command_push_info (SvnCommand *self, gchar *message)
531 anjuta_async_command_lock (ANJUTA_ASYNC_COMMAND (self));
532 g_queue_push_tail (self->priv->info_messages, g_strdup (message));
533 anjuta_async_command_unlock (ANJUTA_ASYNC_COMMAND (self));
535 anjuta_command_notify_data_arrived (ANJUTA_COMMAND (self));
538 GQueue *
539 svn_command_get_info_queue (SvnCommand *self)
541 return self->priv->info_messages;
544 void
545 svn_command_set_error (SvnCommand *self, svn_error_t *error)
547 GString *error_string;
548 svn_error_t *current_error;
549 gchar *error_c_string;
551 error_string = g_string_new ("");
552 current_error = error;
554 while (current_error)
556 g_string_append (error_string, current_error->message);
558 if (current_error->child)
559 g_string_append_c (error_string, '\n');
561 current_error = current_error->child;
564 error_c_string = g_string_free (error_string, FALSE);
565 anjuta_async_command_set_error_message (ANJUTA_COMMAND (self),
566 error_c_string);
568 g_free (error_c_string);
571 svn_client_ctx_t *
572 svn_command_get_client_context (SvnCommand *self)
574 return self->priv->client_context;
577 apr_pool_t *
578 svn_command_get_pool (SvnCommand *self)
580 return self->priv->pool;
583 void
584 svn_command_lock_ui (SvnCommand *self)
586 g_mutex_lock (self->priv->ui_lock);
588 /* Have the main thread acquire the lock as soon as the other thread is done
589 * with it. The main thread should *not* acqure the lock, only release
590 * it. */
591 self->priv->main_thread_has_ui_lock = FALSE;
592 g_idle_add ((GSourceFunc) svn_command_acquire_ui_lock, self);
595 void
596 svn_command_unlock_ui (SvnCommand *self)
598 g_mutex_unlock (self->priv->ui_lock);
601 svn_opt_revision_t *
602 svn_command_get_revision (gchar *revision)
604 svn_opt_revision_t* svn_revision;
606 svn_revision = g_new0 (svn_opt_revision_t, 1);
608 /* FIXME: Parse the revision string */
609 svn_revision->kind = svn_opt_revision_head;
611 return svn_revision;
614 GList *
615 svn_command_copy_path_list (GList *list)
617 GList *current_path;
618 GList *new_list;
620 new_list = NULL;
621 current_path = list;
623 while (current_path)
625 new_list = g_list_append (new_list, g_strdup (current_path->data));
626 current_path = g_list_next (current_path);
629 return new_list;
632 void
633 svn_command_free_path_list (GList *list)
635 GList *current_path;
637 current_path = list;
639 while (current_path)
641 g_free (current_path->data);
642 current_path = g_list_next (current_path);
645 g_list_free (list);