glade: Fix make file some files were not installed
[anjuta.git] / plugins / subversion / svn-command.c
blob13d5991efa7c4c808a39b071098b5a47ca7e1dbb
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 GCond *dialog_finished_condition;
33 GMutex *dialog_finished_lock;
34 gboolean dialog_finished;
35 gboolean cancelled;
38 G_DEFINE_TYPE (SvnCommand, svn_command, ANJUTA_TYPE_ASYNC_COMMAND);
41 /* Auth functions */
42 /* In order to prevent deadlocking when Subversion prompts for something, we
43 * have to make sure that no GTK calls are made from the command threads by way
44 * of the authentication baton. To do this, the dialog code will be called from
45 * idle sources. */
47 /* svn_auth_simple_prompt_func_cb argumements */
48 typedef struct
50 svn_auth_cred_simple_t **cred;
51 void *baton;
52 gchar *realm;
53 gchar *username;
54 svn_boolean_t may_save;
55 apr_pool_t *pool;
56 svn_error_t *error;
57 } SimplePromptArgs;
59 /* svn_auth_ssl_server_trust_prompt_func_cb arguements */
60 typedef struct
62 svn_auth_cred_ssl_server_trust_t **cred;
63 void *baton;
64 gchar *realm;
65 apr_uint32_t failures;
66 svn_auth_ssl_server_cert_info_t *cert_info;
67 svn_boolean_t may_save;
68 apr_pool_t *pool;
69 svn_error_t *error;
70 } SSLServerTrustArgs;
73 /* Idle destroy functions. The command threads should wait for the dialogs to
74 * finish before continuing. These functions signals the condition structure,
75 * allowing them to continue. These functions are executed on the main thread */
77 static void
78 on_simple_prompt_finished (SimplePromptArgs *args)
80 SvnCommand *self;
82 self = SVN_COMMAND (args->baton);
84 g_mutex_lock (self->priv->dialog_finished_lock);
86 self->priv->dialog_finished = TRUE;
87 g_cond_signal (self->priv->dialog_finished_condition);
89 g_mutex_unlock (self->priv->dialog_finished_lock);
92 static void
93 on_ssl_server_trust_prompt_finished (SSLServerTrustArgs *args)
95 SvnCommand *self;
97 self = SVN_COMMAND (args->baton);
99 g_mutex_lock (self->priv->dialog_finished_lock);
101 self->priv->dialog_finished = TRUE;
102 g_cond_signal (self->priv->dialog_finished_condition);
104 g_mutex_unlock (self->priv->dialog_finished_lock);
107 static gboolean
108 simple_prompt (SimplePromptArgs *args)
110 GtkBuilder* bxml = gtk_builder_new ();
111 GtkWidget* svn_user_auth;
112 GtkWidget* auth_realm;
113 GtkWidget* username_entry;
114 GtkWidget* password_entry;
115 GtkWidget* remember_pwd;
116 svn_error_t *err = NULL;
117 SvnCommand *svn_command;
118 GError* error = NULL;
120 if (!gtk_builder_add_from_file (bxml, GLADE_FILE, &error))
122 g_warning ("Couldn't load builder file: %s", error->message);
123 g_error_free (error);
126 svn_user_auth = GTK_WIDGET (gtk_builder_get_object (bxml, "svn_user_auth"));
127 auth_realm = GTK_WIDGET (gtk_builder_get_object (bxml, "auth_realm"));
128 username_entry = GTK_WIDGET (gtk_builder_get_object (bxml, "username_entry"));
129 password_entry = GTK_WIDGET (gtk_builder_get_object (bxml, "password_entry"));
130 remember_pwd = GTK_WIDGET (gtk_builder_get_object (bxml, "remember_pwd"));
132 gtk_dialog_set_default_response (GTK_DIALOG (svn_user_auth), GTK_RESPONSE_OK);
134 if (args->realm)
135 gtk_label_set_text (GTK_LABEL (auth_realm), args->realm);
136 if (args->username)
138 gtk_entry_set_text (GTK_ENTRY (username_entry), args->username);
139 gtk_widget_grab_focus (password_entry);
141 if (!args->may_save)
142 gtk_widget_set_sensitive(remember_pwd, FALSE);
144 /* Then the dialog is prompted to user and when user clicks ok, the
145 * values entered, i.e username, password and remember password (true
146 * by default) should be used to initialized the memebers below. If the
147 * user cancels the dialog, I think we return an error struct
148 * appropriately initialized. -- naba
151 switch (gtk_dialog_run(GTK_DIALOG(svn_user_auth)))
153 case GTK_RESPONSE_OK:
155 *args->cred = apr_pcalloc (args->pool, sizeof(svn_auth_cred_simple_t));
156 (*(args->cred))->may_save = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
157 (remember_pwd));
158 (*(args->cred))->username = apr_pstrdup (args->pool,
159 gtk_entry_get_text(GTK_ENTRY(username_entry)));
160 (*(args->cred))->password = apr_pstrdup (args->pool,
161 gtk_entry_get_text(GTK_ENTRY(password_entry)));
163 err = SVN_NO_ERROR;
164 break;
166 default:
167 err = svn_error_create (SVN_ERR_AUTHN_CREDS_UNAVAILABLE, NULL,
168 _("Authentication canceled"));
170 break;
172 gtk_widget_destroy (svn_user_auth);
173 args->error = err;
175 return FALSE;
178 static gboolean
179 ssl_server_trust_prompt (SSLServerTrustArgs *args)
181 GtkBuilder* bxml = gtk_builder_new ();
182 GtkWidget* svn_server_trust;
183 GtkWidget* auth_realm;
184 GtkWidget* server_info;
185 GtkWidget* remember_check;
186 svn_error_t *err = NULL;
187 gchar* info;
188 SvnCommand *svn_command;
189 GError* error = NULL;
191 if (!gtk_builder_add_from_file (bxml, GLADE_FILE, &error))
193 g_warning ("Couldn't load builder file: %s", error->message);
194 g_error_free (error);
196 svn_server_trust = GTK_WIDGET (gtk_builder_get_object (bxml, "svn_server_trust"));
197 auth_realm = GTK_WIDGET (gtk_builder_get_object (bxml, "realm_label"));
198 server_info = GTK_WIDGET (gtk_builder_get_object (bxml, "server_info_label"));
199 remember_check = GTK_WIDGET (gtk_builder_get_object (bxml, "remember_check"));
201 if (args->realm)
202 gtk_label_set_text (GTK_LABEL (auth_realm), args->realm);
204 info = g_strconcat(_("Hostname:"), args->cert_info->hostname, "\n",
205 _("Fingerprint:"), args->cert_info->fingerprint, "\n",
206 _("Valid from:"), args->cert_info->valid_from, "\n",
207 _("Valid until:"), args->cert_info->valid_until, "\n",
208 _("Issuer DN:"), args->cert_info->issuer_dname, "\n",
209 _("DER certificate:"), args->cert_info->ascii_cert, "\n",
210 NULL);
211 gtk_label_set_text (GTK_LABEL (server_info), info);
213 if (!args->may_save)
214 gtk_widget_set_sensitive(remember_check, FALSE);
216 gtk_dialog_set_default_response (GTK_DIALOG (svn_server_trust), GTK_RESPONSE_YES);
219 switch (gtk_dialog_run(GTK_DIALOG(svn_server_trust)))
221 case GTK_RESPONSE_YES:
222 *args->cred = apr_pcalloc (args->pool,
223 sizeof(*(args->cred)));
224 (*(args->cred))->may_save = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
225 (remember_check));
226 err = SVN_NO_ERROR;
227 /* TODO: Set bitmask for accepted_failures */
228 break;
229 default:
230 err = svn_error_create (SVN_ERR_AUTHN_CREDS_UNAVAILABLE, NULL,
231 _("Authentication canceled"));
232 break;
234 gtk_widget_destroy (svn_server_trust);
235 args->error = err;
237 return FALSE;
240 /* User authentication prompts handlers */
241 static svn_error_t*
242 svn_auth_simple_prompt_func_cb (svn_auth_cred_simple_t **cred, void *baton,
243 const char *realm, const char *username,
244 svn_boolean_t may_save, apr_pool_t *pool)
246 SimplePromptArgs *args;
247 SvnCommand *svn_command;
248 svn_error_t *error;
250 args = g_new0 (SimplePromptArgs, 1);
251 args->cred = cred;
252 args->baton = baton;
253 args->realm = g_strdup (realm);
254 args->username = g_strdup (username);
255 args->may_save = may_save;
256 args->pool = pool;
258 svn_command = SVN_COMMAND (baton);
260 /* Wait for the dialog to finish */
261 g_mutex_lock (svn_command->priv->dialog_finished_lock);
263 svn_command->priv->dialog_finished = FALSE;
265 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
266 (GSourceFunc) simple_prompt, args,
267 (GDestroyNotify) on_simple_prompt_finished);
269 while (!svn_command->priv->dialog_finished)
271 g_cond_wait (svn_command->priv->dialog_finished_condition,
272 svn_command->priv->dialog_finished_lock);
275 error = args->error;
276 g_free (args->realm);
277 g_free (args->username);
278 g_free (args);
280 g_mutex_unlock (svn_command->priv->dialog_finished_lock);
282 return error;
286 static svn_error_t*
287 svn_auth_ssl_server_trust_prompt_func_cb (svn_auth_cred_ssl_server_trust_t **cred,
288 void *baton, const char *realm,
289 apr_uint32_t failures,
290 const svn_auth_ssl_server_cert_info_t *cert_info,
291 svn_boolean_t may_save,
292 apr_pool_t *pool)
294 SSLServerTrustArgs *args;
295 SvnCommand *svn_command;
296 svn_error_t *error;
298 args = g_new0 (SSLServerTrustArgs, 1);
299 args->cred = cred;
300 args->baton = baton;
301 args->realm = g_strdup (realm);
302 args->failures = failures;
303 args->cert_info = g_memdup (cert_info,
304 sizeof (svn_auth_ssl_server_cert_info_t));
305 args->may_save = may_save;
306 args->pool = pool;
308 svn_command = SVN_COMMAND (baton);
310 /* Wait for the dialog to finish */
311 g_mutex_lock (svn_command->priv->dialog_finished_lock);
313 svn_command->priv->dialog_finished = FALSE;
315 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
316 (GSourceFunc) ssl_server_trust_prompt, args,
317 (GDestroyNotify) on_ssl_server_trust_prompt_finished);
319 while (!svn_command->priv->dialog_finished)
321 g_cond_wait (svn_command->priv->dialog_finished_condition,
322 svn_command->priv->dialog_finished_lock);
325 error = args->error;
326 g_free (args->realm);
327 g_free (args->cert_info);
328 g_free (args);
330 g_mutex_unlock (svn_command->priv->dialog_finished_lock);
332 return error;
335 static svn_error_t*
336 svn_auth_ssl_client_cert_prompt_func_cb (svn_auth_cred_ssl_client_cert_t **cred,
337 void *baton, const char *realm,
338 svn_boolean_t may_save,
339 apr_pool_t *pool)
342 /* Ask for the file where client certificate of authenticity is.
343 * I think it is some sort of private key. */
344 return SVN_NO_ERROR;
347 static svn_error_t*
348 svn_auth_ssl_client_cert_pw_prompt_func_cb (svn_auth_cred_ssl_client_cert_pw_t **cred,
349 void *baton, const char *realm,
350 svn_boolean_t may_save,
351 apr_pool_t *pool)
354 /* Prompt for password only. I think it is pass-phrase of the above key. */
355 return SVN_NO_ERROR;;
358 /* Notification callback to handle notifications from Subversion itself */
359 static void
360 on_svn_notify (gpointer baton,
361 const svn_wc_notify_t *notify,
362 apr_pool_t *pool)
364 SvnCommand *self;
365 gchar *action_message;
366 gchar *state_message;
368 self = SVN_COMMAND (baton);
369 action_message = NULL;
370 state_message = NULL;
372 switch (notify->action)
374 case svn_wc_notify_delete:
375 action_message = g_strdup_printf (_("Deleted: %s"), notify->path);
376 break;
377 case svn_wc_notify_add:
378 action_message = g_strdup_printf (_("Added: %s"), notify->path);
379 break;
380 case svn_wc_notify_revert:
381 action_message = g_strdup_printf ("Reverted: %s", notify->path);
382 break;
383 case svn_wc_notify_failed_revert:
384 action_message = g_strdup_printf ("Revert failed: %s",
385 notify->path);
386 break;
387 case svn_wc_notify_resolved:
388 action_message = g_strdup_printf (_("Resolved: %s"), notify->path);
389 break;
390 case svn_wc_notify_update_delete:
391 action_message = g_strdup_printf (_("Deleted: %s"), notify->path);
392 break;
393 case svn_wc_notify_update_update:
394 action_message = g_strdup_printf (_("Updated: %s"), notify->path);
395 break;
396 case svn_wc_notify_update_add:
397 action_message = g_strdup_printf (_("Added: %s"), notify->path);
398 break;
399 case svn_wc_notify_update_external:
400 action_message = g_strdup_printf (_("Externally Updated: %s"),
401 notify->path);
402 break;
403 case svn_wc_notify_commit_modified:
404 action_message = g_strdup_printf ("Commit Modified: %s",
405 notify->path);
406 break;
407 case svn_wc_notify_commit_added:
408 action_message = g_strdup_printf ("Commit Added: %s", notify->path);
409 break;
410 case svn_wc_notify_commit_deleted:
411 action_message = g_strdup_printf ("Commit Deleted: %s",
412 notify->path);
413 break;
414 case svn_wc_notify_commit_replaced:
415 action_message = g_strdup_printf ("Commit Replaced: %s",
416 notify->path);
417 break;
418 case svn_wc_notify_copy:
419 action_message = g_strdup_printf ("Created File: %s", notify->path);
420 break;
421 default:
422 break;
425 if (action_message)
427 svn_command_push_info (self, action_message);
428 g_free (action_message);
431 switch (notify->content_state)
433 case svn_wc_notify_state_changed:
434 state_message = g_strdup_printf (_("Modified: %s"), notify->path);
435 break;
436 case svn_wc_notify_state_merged:
437 state_message = g_strdup_printf (_("Merged: %s"), notify->path);
438 break;
439 case svn_wc_notify_state_conflicted:
440 state_message = g_strdup_printf (_("Conflicted: %s"),
441 notify->path);
442 break;
443 case svn_wc_notify_state_missing:
444 state_message = g_strdup_printf (_("Missing: %s"), notify->path);
445 break;
446 case svn_wc_notify_state_obstructed:
447 state_message = g_strdup_printf (_("Obstructed: %s"), notify->path);
448 break;
449 default:
450 break;
453 if (state_message)
455 svn_command_push_info (self, state_message);
456 g_free (state_message);
460 /* Operation cancelling callback */
461 static svn_error_t *
462 on_svn_cancel (gpointer cancel_baton)
464 SvnCommand *self;
466 self = SVN_COMMAND (cancel_baton);
468 if (self->priv->cancelled)
469 return svn_error_create (SVN_ERR_CANCELLED, NULL, NULL);
470 else
471 return SVN_NO_ERROR;
474 static void
475 svn_command_init (SvnCommand *self)
477 svn_auth_baton_t *auth_baton;
478 apr_array_header_t *providers;
479 svn_auth_provider_object_t *provider;
481 self->priv = g_new0 (SvnCommandPriv, 1);
483 self->priv->pool = svn_pool_create (NULL);
484 svn_client_create_context (&self->priv->client_context, self->priv->pool);
485 self->priv->client_context->notify_func2 = on_svn_notify;
486 self->priv->client_context->notify_baton2 = self;
487 self->priv->client_context->cancel_func = on_svn_cancel;
488 self->priv->client_context->cancel_baton = self;
490 svn_config_get_config (&(self->priv->client_context)->config,
491 NULL, /* default dir */
492 self->priv->pool);
494 self->priv->info_messages = g_queue_new ();
495 self->priv->dialog_finished_lock = g_mutex_new ();
496 self->priv->dialog_finished_condition = g_cond_new ();
498 /* Fill in the auth baton callbacks */
499 providers = apr_array_make (self->priv->pool, 1,
500 sizeof (svn_auth_provider_object_t *));
502 /* Provider that authenticates username/password from ~/.subversion */
503 provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
504 svn_client_get_simple_provider (&provider, self->priv->pool);
505 *(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
507 /* Provider that authenticates server trust from ~/.subversion */
508 provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
509 svn_client_get_ssl_server_trust_file_provider (&provider, self->priv->pool);
510 *(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
512 /* Provider that authenticates client cert from ~/.subversion */
513 provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
514 svn_client_get_ssl_client_cert_file_provider (&provider, self->priv->pool);
515 *(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
517 /* Provider that authenticates client cert password from ~/.subversion */
518 provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
519 svn_client_get_ssl_client_cert_pw_file_provider (&provider,
520 self->priv->pool);
521 *(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
523 /* Provider that prompts for username/password */
524 provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
525 svn_client_get_simple_prompt_provider(&provider,
526 svn_auth_simple_prompt_func_cb,
527 self, 3, self->priv->pool);
528 *(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
530 /* Provider that prompts for server trust */
531 provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
532 svn_client_get_ssl_server_trust_prompt_provider (&provider,
533 svn_auth_ssl_server_trust_prompt_func_cb,
534 self,
535 self->priv->pool);
536 *(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
538 /* Provider that prompts for client certificate file */
539 provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
540 svn_client_get_ssl_client_cert_prompt_provider (&provider,
541 svn_auth_ssl_client_cert_prompt_func_cb,
542 NULL, 3, self->priv->pool);
543 *(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
545 /* Provider that prompts for client certificate file password */
546 provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
547 svn_client_get_ssl_client_cert_pw_prompt_provider (&provider,
548 svn_auth_ssl_client_cert_pw_prompt_func_cb,
549 NULL, 3,
550 self->priv->pool);
551 *(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
553 svn_auth_open (&auth_baton, providers, self->priv->pool);
554 self->priv->client_context->auth_baton = auth_baton;
558 static void
559 svn_command_finalize (GObject *object)
561 SvnCommand *self;
562 GList *current_message_line;
564 self = SVN_COMMAND (object);
566 svn_pool_clear (self->priv->pool);
567 svn_pool_destroy (self->priv->pool);
569 current_message_line = self->priv->info_messages->head;
571 while (current_message_line)
573 g_free (current_message_line->data);
574 current_message_line = g_list_next (current_message_line);
577 g_mutex_free (self->priv->dialog_finished_lock);
578 g_cond_free (self->priv->dialog_finished_condition);
580 g_queue_free (self->priv->info_messages);
581 g_free (self->priv);
583 G_OBJECT_CLASS (svn_command_parent_class)->finalize (object);
586 static void
587 svn_command_cancel (AnjutaCommand *command)
589 SvnCommand *self;
591 self = SVN_COMMAND (command);
593 self->priv->cancelled = TRUE;
596 static void
597 svn_command_class_init (SvnCommandClass *klass)
599 GObjectClass* object_class = G_OBJECT_CLASS (klass);
600 AnjutaCommandClass *command_class = ANJUTA_COMMAND_CLASS (klass);
602 object_class->finalize = svn_command_finalize;
603 command_class->cancel = svn_command_cancel;
607 void
608 svn_command_push_info (SvnCommand *self, const gchar *message)
610 anjuta_async_command_lock (ANJUTA_ASYNC_COMMAND (self));
611 g_queue_push_tail (self->priv->info_messages, g_strdup (message));
612 anjuta_async_command_unlock (ANJUTA_ASYNC_COMMAND (self));
614 anjuta_command_notify_data_arrived (ANJUTA_COMMAND (self));
617 GQueue *
618 svn_command_get_info_queue (SvnCommand *self)
620 return self->priv->info_messages;
623 void
624 svn_command_set_error (SvnCommand *self, svn_error_t *error)
626 GString *error_string;
627 svn_error_t *current_error;
628 gchar *error_c_string;
630 error_string = g_string_new ("");
631 current_error = error;
633 while (current_error)
635 g_string_append (error_string, current_error->message);
637 if (current_error->child)
638 g_string_append_c (error_string, '\n');
640 current_error = current_error->child;
643 error_c_string = g_string_free (error_string, FALSE);
644 anjuta_async_command_set_error_message (ANJUTA_COMMAND (self),
645 error_c_string);
647 g_free (error_c_string);
650 svn_client_ctx_t *
651 svn_command_get_client_context (SvnCommand *self)
653 return self->priv->client_context;
656 apr_pool_t *
657 svn_command_get_pool (SvnCommand *self)
659 return self->priv->pool;
662 gchar *
663 svn_command_make_canonical_path (SvnCommand *self, const gchar *path)
665 const gchar *canonical_path;
667 canonical_path = NULL;
669 if (path)
670 canonical_path = svn_path_canonicalize (path, self->priv->pool);
672 return g_strdup (canonical_path);
675 svn_opt_revision_t *
676 svn_command_get_revision (const gchar *revision)
678 svn_opt_revision_t* svn_revision;
680 svn_revision = g_new0 (svn_opt_revision_t, 1);
682 /* FIXME: Parse the revision string */
683 svn_revision->kind = svn_opt_revision_head;
685 return svn_revision;
688 GList *
689 svn_command_copy_path_list (GList *list)
691 GList *current_path;
692 GList *new_list;
694 new_list = NULL;
695 current_path = list;
697 while (current_path)
699 new_list = g_list_append (new_list, g_strdup (current_path->data));
700 current_path = g_list_next (current_path);
703 return new_list;
706 void
707 svn_command_free_path_list (GList *list)
709 GList *current_path;
711 current_path = list;
713 while (current_path)
715 g_free (current_path->data);
716 current_path = g_list_next (current_path);
719 g_list_free (list);