Do not use GitAdminDir objects
[TortoiseGit.git] / src / TortoiseProc / Settings / SettingGitCredential.cpp
blob46b9ddd0ea7e27a71adf59a4acd08d1aa3bc0500
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2013-2015 - TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 // SettingGitCredential.cpp : implementation file
22 #include "stdafx.h"
23 #include "TortoiseProc.h"
24 #include "SettingGitCredential.h"
25 #include "Settings.h"
26 #include "GitAdminDir.h"
27 #include "MessageBox.h"
28 #include "AppUtils.h"
29 #include "Git.h"
30 #include "PathUtils.h"
32 namespace SimpleCredentialType
34 static int Advanced;
35 static int None;
36 static int LocalWincred;
37 static int LocalWinstore;
38 static int GlobalWincred;
39 static int GlobalWinstore;
40 static int SystemWincred;
42 static void Init()
44 Advanced = -1;
45 None = -1;
46 LocalWincred = -1;
47 LocalWinstore = -1;
48 GlobalWincred = -1;
49 GlobalWinstore = -1;
50 SystemWincred = -1;
54 namespace ConfigType
56 static int Local;
57 static int Global;
58 static int System;
60 static void Init()
62 Local = -1;
63 Global = -1;
64 System = -1;
68 // CSettingGitCredential dialog
70 IMPLEMENT_DYNAMIC(CSettingGitCredential, ISettingsPropPage)
72 CSettingGitCredential::CSettingGitCredential()
73 : ISettingsPropPage(CSettingGitCredential::IDD)
74 , m_strUrl(_T(""))
75 , m_strHelper(_T(""))
76 , m_strUsername(_T(""))
77 , m_bUseHttpPath(FALSE)
80 m_ChangedMask = 0;
83 CSettingGitCredential::~CSettingGitCredential()
87 void CSettingGitCredential::DoDataExchange(CDataExchange* pDX)
89 CPropertyPage::DoDataExchange(pDX);
90 DDX_Control(pDX, IDC_COMBO_SIMPLECREDENTIAL, m_ctrlSimpleCredential);
91 DDX_Control(pDX, IDC_LIST_REMOTE, m_ctrlUrlList);
92 DDX_Text(pDX, IDC_EDIT_URL, m_strUrl);
93 DDX_Text(pDX, IDC_COMBO_HELPER, m_strHelper);
94 DDX_Text(pDX, IDC_EDIT_USERNAME, m_strUsername);
95 DDX_Check(pDX, IDC_CHECK_USEHTTPPATH, m_bUseHttpPath);
96 DDX_Control(pDX, IDC_COMBO_CONFIGTYPE, m_ctrlConfigType);
100 BEGIN_MESSAGE_MAP(CSettingGitCredential, CPropertyPage)
101 ON_CBN_SELCHANGE(IDC_COMBO_SIMPLECREDENTIAL, &CSettingGitCredential::OnCbnSelchangeComboSimplecredential)
102 ON_BN_CLICKED(IDC_BUTTON_ADD, &CSettingGitCredential::OnBnClickedButtonAdd)
103 ON_LBN_SELCHANGE(IDC_LIST_REMOTE, &CSettingGitCredential::OnLbnSelchangeListUrl)
104 ON_CBN_SELCHANGE(IDC_COMBO_CONFIGTYPE, &CSettingGitCredential::OnCbnSelchangeComboConfigType)
105 ON_EN_CHANGE(IDC_EDIT_URL, &CSettingGitCredential::OnEnChangeEditUrl)
106 ON_CBN_EDITCHANGE(IDC_COMBO_HELPER, &CSettingGitCredential::OnEnChangeEditHelper)
107 ON_CBN_SELCHANGE(IDC_COMBO_HELPER, &CSettingGitCredential::OnEnChangeEditHelper)
108 ON_EN_CHANGE(IDC_EDIT_USERNAME, &CSettingGitCredential::OnEnChangeEditUsername)
109 ON_BN_CLICKED(IDC_CHECK_USEHTTPPATH, &CSettingGitCredential::OnBnClickedCheckUsehttppath)
110 ON_BN_CLICKED(IDC_BUTTON_REMOVE, &CSettingGitCredential::OnBnClickedButtonRemove)
111 END_MESSAGE_MAP()
113 static bool RunUAC()
115 CString sCmd;
116 sCmd.Format(_T("/command:settings /page:gitcredential /path:\"%s\""), g_Git.m_CurrentDir);
117 return CAppUtils::RunTortoiseGitProc(sCmd, true);
120 static CString GetWinstorePath()
122 TCHAR winstorebuf[MAX_PATH] = {0};
123 ExpandEnvironmentStrings(_T("%AppData%\\GitCredStore\\git-credential-winstore.exe"), winstorebuf, MAX_PATH);
124 CString winstore;
125 winstore.Format(_T("!'%s'"), winstorebuf);
126 return winstore;
129 static bool WincredExists()
131 CString path = g_Git.ms_LastMsysGitDir;
132 if (g_Git.ms_LastMsysGitDir.Right(1) != _T("\\"))
133 path.AppendChar(_T('\\'));
134 path.Append(_T("..\\libexec\\git-core\\git-credential-wincred.exe"));
135 return !!PathFileExists(path);
138 static bool WinstoreExists()
140 return !!PathFileExists(GetWinstorePath());
143 static CStringA RegexEscape(CStringA str)
145 CStringA result;
146 for (int i = 0; i < str.GetLength(); ++i)
148 char c = str[i];
149 switch (c)
151 case '\\': case '*': case '+': case '?': case '|':
152 case '{': case '[': case '(': case ')': case '^':
153 case '$': case '.': case '#': case ' ':
154 result.AppendChar('\\');
155 result.AppendChar(c);
156 break;
157 case '\t': result.Append("\\t"); break;
158 case '\n': result.Append("\\n"); break;
159 case '\r': result.Append("\\r"); break;
160 case '\f': result.Append("\\f"); break;
161 default: result.AppendChar(c); break;
165 return result;
168 BOOL CSettingGitCredential::OnInitDialog()
170 ISettingsPropPage::OnInitDialog();
172 AdjustControlSize(IDC_CHECK_USEHTTPPATH);
174 bool hasLocal = GitAdminDir::HasAdminDir(g_Git.m_CurrentDir);
176 m_ctrlUrlList.ResetContent();
178 ConfigType::Init();
179 AddConfigType(ConfigType::Local, CString(MAKEINTRESOURCE(IDS_SETTINGS_LOCAL)), hasLocal);
180 AddConfigType(ConfigType::Global, CString(MAKEINTRESOURCE(IDS_SETTINGS_GLOBAL)));
181 AddConfigType(ConfigType::System, CString(MAKEINTRESOURCE(IDS_SETTINGS_SYSTEM)));
182 m_ctrlConfigType.SetCurSel(0);
184 if (WincredExists())
185 ((CComboBox*) GetDlgItem(IDC_COMBO_HELPER))->AddString(_T("wincred"));
186 if (WinstoreExists())
187 ((CComboBox*) GetDlgItem(IDC_COMBO_HELPER))->AddString(GetWinstorePath());
189 SimpleCredentialType::Init();
190 AddSimpleCredential(SimpleCredentialType::Advanced, CString(MAKEINTRESOURCE(IDS_ADVANCED)));
191 AddSimpleCredential(SimpleCredentialType::None, CString(MAKEINTRESOURCE(IDS_NONE)));
192 AddSimpleCredential(SimpleCredentialType::LocalWincred, CString(MAKEINTRESOURCE(IDS_LOCAL_WINCRED)), hasLocal && WincredExists());
193 AddSimpleCredential(SimpleCredentialType::LocalWinstore, CString(MAKEINTRESOURCE(IDS_LOCAL_WINSTORE)), hasLocal && WinstoreExists());
194 AddSimpleCredential(SimpleCredentialType::GlobalWincred, CString(MAKEINTRESOURCE(IDS_GLOBAL_WINCRED)), WincredExists());
195 AddSimpleCredential(SimpleCredentialType::GlobalWinstore, CString(MAKEINTRESOURCE(IDS_GLOBAL_WINSTORE)), WinstoreExists());
196 AddSimpleCredential(SimpleCredentialType::SystemWincred, CString(MAKEINTRESOURCE(IDS_SYSTEM_WINCRED)), WincredExists());
198 LoadList();
200 EnableAdvancedOptions();
202 UpdateData(FALSE);
203 return TRUE;
205 // CSettingGitCredential message handlers
207 void CSettingGitCredential::OnCbnSelchangeComboSimplecredential()
209 EnableAdvancedOptions();
210 SetModified();
213 void CSettingGitCredential::OnBnClickedButtonAdd()
215 UpdateData();
217 if (m_strHelper.Trim().IsEmpty())
219 CMessageBox::Show(NULL, IDS_GITCREDENTIAL_HELPEREMPTY, IDS_APPNAME, MB_OK | MB_ICONERROR);
220 return;
223 m_ChangedMask = CREDENTIAL_URL | CREDENTIAL_HELPER | CREDENTIAL_USERNAME | CREDENTIAL_USEHTTPPATH;
224 int sel = m_ctrlConfigType.GetCurSel();
225 CString prefix = sel == ConfigType::System ? _T("S") : sel == ConfigType::Global ? _T("G") : _T("L");
226 CString text;
227 if (!m_strUrl.IsEmpty())
228 text.Format(_T("%s:%s"), prefix, m_strUrl);
229 else
230 text = prefix;
231 if (IsUrlExist(text))
233 CString msg;
234 msg.Format(IDS_GITCREDENTIAL_OVERWRITEHELPER, m_strUrl);
235 if (CMessageBox::Show(NULL, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2) == IDYES)
236 m_ChangedMask &= ~CREDENTIAL_URL;
237 else
238 return;
240 else
242 if (m_strUsername.IsEmpty())
243 m_ChangedMask &= ~CREDENTIAL_USERNAME;
244 if (!m_bUseHttpPath)
245 m_ChangedMask &= ~CREDENTIAL_USEHTTPPATH;
248 OnApply();
251 void CSettingGitCredential::EnableAdvancedOptions()
253 BOOL enable = m_ctrlSimpleCredential.GetCurSel() == SimpleCredentialType::Advanced ? TRUE : FALSE;
254 GetDlgItem(IDC_LIST_REMOTE)->EnableWindow(enable);
255 GetDlgItem(IDC_EDIT_URL)->EnableWindow(enable);
256 GetDlgItem(IDC_COMBO_HELPER)->EnableWindow(enable);
257 GetDlgItem(IDC_EDIT_USERNAME)->EnableWindow(enable);
258 GetDlgItem(IDC_COMBO_CONFIGTYPE)->EnableWindow(enable);
259 GetDlgItem(IDC_CHECK_USEHTTPPATH)->EnableWindow(enable);
260 GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(enable);
261 GetDlgItem(IDC_BUTTON_REMOVE)->EnableWindow(enable);
264 BOOL CSettingGitCredential::IsUrlExist(CString &text)
266 CString str;
267 for(int i = 0; i < m_ctrlUrlList.GetCount();i++)
269 m_ctrlUrlList.GetText(i, str);
270 if (str == text)
272 return true;
275 return false;
278 void CSettingGitCredential::OnLbnSelchangeListUrl()
280 CWaitCursor wait;
282 if (m_ChangedMask)
284 if (CMessageBox::Show(NULL, IDS_GITCREDENTIAL_SAVEHELPER, IDS_APPNAME, 1, IDI_QUESTION, IDS_SAVEBUTTON, IDS_DISCARDBUTTON) == 1)
285 OnApply();
287 SetModified(FALSE);
289 CString cmd, output;
290 int index = m_ctrlUrlList.GetCurSel();
291 if (index < 0)
293 m_strHelper.Empty();
294 m_strUrl.Empty();
295 m_strHelper.Empty();
296 m_bUseHttpPath = FALSE;
297 UpdateData(FALSE);
298 return;
301 CString text;
302 m_ctrlUrlList.GetText(index, text);
303 int pos = text.Find(_T(':'));
304 CString prefix = pos >= 0 ? text.Left(pos) : text.Left(1);
305 m_ctrlConfigType.SetCurSel(prefix == _T("S") ? ConfigType::System : prefix == _T("X") ? ConfigType::Global : prefix == _T("G") ? ConfigType::Global : ConfigType::Local);
306 m_strUrl = pos >= 0 ? text.Mid(pos + 1) : _T("");
308 m_strHelper = Load(_T("helper"));
309 m_strUsername = Load(_T("username"));
310 m_bUseHttpPath = Load(_T("useHttpPath")) == _T("true") ? TRUE : FALSE;
312 m_ChangedMask = 0;
314 GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(TRUE);
315 GetDlgItem(IDC_BUTTON_REMOVE)->EnableWindow(TRUE);
316 this->UpdateData(FALSE);
319 void CSettingGitCredential::OnCbnSelchangeComboConfigType()
321 SetModified();
324 void CSettingGitCredential::OnEnChangeEditUrl()
326 m_ChangedMask |= CREDENTIAL_URL;
327 SetModified();
330 void CSettingGitCredential::OnEnChangeEditHelper()
332 m_ChangedMask |= CREDENTIAL_HELPER;
334 UpdateData();
335 if (!m_strHelper.IsEmpty())
336 SetModified();
337 else
338 SetModified(0);
341 void CSettingGitCredential::OnEnChangeEditUsername()
343 m_ChangedMask |= CREDENTIAL_USERNAME;
344 SetModified();
347 void CSettingGitCredential::OnBnClickedCheckUsehttppath()
349 m_ChangedMask |= CREDENTIAL_USEHTTPPATH;
350 SetModified();
353 static int GetCredentialDefaultUrlCallback(const git_config_entry *entry, void *payload)
355 CString display = entry->level == 1 ? _T("S") : entry->level == 2 ? _T("X") : entry->level == 3 ? _T("G") : _T("L");
356 ((STRING_VECTOR *)payload)->push_back(display);
357 return 0;
360 static int GetCredentialUrlCallback(const git_config_entry *entry, void *payload)
362 CString name = CUnicodeUtils::GetUnicode(entry->name);
363 int pos1 = name.Find(_T('.'));
364 int pos2 = name.ReverseFind(_T('.'));
365 CString url = name.Mid(pos1 + 1, pos2 - pos1 - 1);
366 CString display;
367 display.Format(_T("%s:%s"), entry->level == 1 ? _T("S") : entry->level == 2 ? _T("X") : entry->level == 3 ? _T("G") : _T("L"), url);
368 ((STRING_VECTOR *)payload)->push_back(display);
369 return 0;
372 static int GetCredentialEntryCallback(const git_config_entry *entry, void *payload)
374 CString name = CUnicodeUtils::GetUnicode(entry->name);
375 ((STRING_VECTOR *)payload)->push_back(name);
376 return 0;
379 static int GetCredentialAnyEntryCallback(const git_config_entry *entry, void *payload)
381 CString name = CUnicodeUtils::GetUnicode(entry->name);
382 CString value = CUnicodeUtils::GetUnicode(entry->value);
383 CString display = entry->level == 1 ? _T("S") : entry->level == 2 ? _T("X") : entry->level == 3 ? _T("G") : _T("L");
384 CString text;
385 text.Format(_T("%s\n%s\n%s"), display, name, value);
386 ((STRING_VECTOR *)payload)->push_back(text);
387 return 0;
390 void CSettingGitCredential::AddConfigType(int &index, CString text, bool add)
392 if (add)
393 index = m_ctrlConfigType.AddString(text);
396 void CSettingGitCredential::AddSimpleCredential(int &index, CString text, bool add)
398 if (add)
399 index = m_ctrlSimpleCredential.AddString(text);
402 void CSettingGitCredential::LoadList()
404 CAutoConfig config(true);
405 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitLocalConfig()), GIT_CONFIG_LEVEL_LOCAL, FALSE);
406 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitGlobalConfig()), GIT_CONFIG_LEVEL_GLOBAL, FALSE);
407 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitGlobalXDGConfig()), GIT_CONFIG_LEVEL_XDG, FALSE);
408 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitSystemConfig()), GIT_CONFIG_LEVEL_SYSTEM, FALSE);
410 STRING_VECTOR defaultList, urlList;
411 git_config_foreach_match(config, "credential\\.helper", GetCredentialDefaultUrlCallback, &defaultList);
412 git_config_foreach_match(config, "credential\\..*\\.helper", GetCredentialUrlCallback, &urlList);
413 STRING_VECTOR anyList;
414 git_config_foreach_match(config, "credential\\..*", GetCredentialAnyEntryCallback, &anyList);
416 for (size_t i = 0; i < defaultList.size(); ++i)
417 m_ctrlUrlList.AddString(defaultList[i]);
418 for (size_t i = 0; i < urlList.size(); ++i)
419 m_ctrlUrlList.AddString(urlList[i]);
421 if (anyList.empty())
423 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::None);
424 return;
426 if (anyList.size() > 1)
428 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::Advanced);
429 return;
432 int pos = 0;
433 CString prefix = anyList[0].Tokenize(_T("\n"), pos);
434 CString key = anyList[0].Tokenize(_T("\n"), pos);
435 CString value = anyList[0].Tokenize(_T("\n"), pos);
436 if (key != _T("credential.helper"))
438 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::Advanced);
439 return;
442 CString winstore = GetWinstorePath();
443 if (prefix == _T("L"))
445 if (value == _T("wincred"))
447 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::LocalWincred);
448 return;
450 else if (value == winstore)
452 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::LocalWinstore);
453 return;
457 if (prefix == _T("G") || prefix == _T("X"))
459 if (value == _T("wincred"))
461 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::GlobalWincred);
462 return;
464 else if (value == winstore)
466 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::GlobalWinstore);
467 return;
471 if (prefix == _T("S"))
473 if (value == _T("wincred"))
475 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::SystemWincred);
476 return;
480 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::Advanced);
483 CString CSettingGitCredential::Load(CString key)
485 CString cmd;
487 if (m_strUrl.IsEmpty())
488 cmd.Format(_T("credential.%s"), key);
489 else
490 cmd.Format(_T("credential.%s.%s"), m_strUrl, key);
492 CAutoConfig config(true);
493 int sel = m_ctrlConfigType.GetCurSel();
494 if (sel == ConfigType::Local)
496 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitLocalConfig()), GIT_CONFIG_LEVEL_LOCAL, FALSE);
498 else if (sel == ConfigType::Global)
500 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitGlobalConfig()), GIT_CONFIG_LEVEL_GLOBAL, FALSE);
501 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitGlobalXDGConfig()), GIT_CONFIG_LEVEL_XDG, FALSE);
503 else if (sel == ConfigType::System)
505 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitSystemConfig()), GIT_CONFIG_LEVEL_SYSTEM, FALSE);
508 CStringA cmdA = CUnicodeUtils::GetUTF8(cmd);
509 CStringA valueA;
510 const git_config_entry *entry;
511 if (!git_config_get_entry(&entry, config, cmdA))
512 valueA = CStringA(entry->value);
514 return CUnicodeUtils::GetUnicode(valueA);
517 void CSettingGitCredential::Save(CString key, CString value)
519 CString cmd, out;
521 if (m_strUrl.IsEmpty())
522 cmd.Format(_T("credential.%s"), key);
523 else
524 cmd.Format(_T("credential.%s.%s"), m_strUrl, key);
526 int sel = m_ctrlConfigType.GetCurSel();
527 CONFIG_TYPE configLevel = sel == ConfigType::System ? CONFIG_SYSTEM : sel == ConfigType::Global ? CONFIG_GLOBAL : CONFIG_LOCAL;
529 bool old = g_Git.m_IsUseGitDLL;
530 // workaround gitdll bug
531 // TODO: switch to libgit2
532 g_Git.m_IsUseGitDLL = false;
533 if (g_Git.SetConfigValue(cmd, value, configLevel))
535 CString msg;
536 msg.Format(IDS_PROC_SAVECONFIGFAILED, cmd, value);
537 CMessageBox::Show(NULL, msg, _T("TortoiseGit"), MB_OK | MB_ICONERROR);
539 if (value.IsEmpty())
541 if (g_Git.UnsetConfigValue(cmd, configLevel))
543 CString msg;
544 msg.Format(IDS_PROC_SAVECONFIGFAILED, cmd, value);
545 CMessageBox::Show(NULL, msg, _T("TortoiseGit"), MB_OK | MB_ICONERROR);
548 g_Git.m_IsUseGitDLL = old;
551 static int DeleteOtherKeys(int type)
553 CString match;
554 if (type == SimpleCredentialType::LocalWincred)
555 match = _T("L\ncredential.helper\nwincred");
556 else if (type == SimpleCredentialType::LocalWinstore)
557 match = _T("L\ncredential.helper\n") + GetWinstorePath();
558 else if (type == SimpleCredentialType::GlobalWincred)
559 match = _T("G\ncredential.helper\nwincred");
560 else if (type == SimpleCredentialType::GlobalWinstore)
561 match = _T("G\ncredential.helper\n") + GetWinstorePath();
562 else if (type == SimpleCredentialType::SystemWincred)
563 match = _T("S\ncredential.helper\nwincred");
565 CAutoConfig config(true);
566 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitLocalConfig()), GIT_CONFIG_LEVEL_LOCAL, FALSE);
567 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitGlobalConfig()), GIT_CONFIG_LEVEL_GLOBAL, FALSE);
568 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitGlobalXDGConfig()), GIT_CONFIG_LEVEL_XDG, FALSE);
569 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitSystemConfig()), GIT_CONFIG_LEVEL_SYSTEM, FALSE);
571 STRING_VECTOR list;
572 git_config_foreach_match(config, "credential\\..*", GetCredentialAnyEntryCallback, &list);
573 for (size_t i = 0; i < list.size(); ++i)
575 int pos = 0;
576 CString prefix = list[i].Tokenize(_T("\n"), pos);
577 if (prefix == _T("S") && !CAppUtils::IsAdminLogin())
579 RunUAC();
580 return -1;
584 int result = 0;
585 // workaround gitdll bug
586 // TODO: switch to libgit2
587 bool old = g_Git.m_IsUseGitDLL;
588 g_Git.m_IsUseGitDLL = false;
589 for (size_t i = 0; i < list.size(); ++i)
591 if (list[i] != match)
593 int pos = 0;
594 CString prefix = list[i].Tokenize(_T("\n"), pos);
595 CString key = list[i].Tokenize(_T("\n"), pos);
596 CONFIG_TYPE configLevel = prefix == _T("S") ? CONFIG_SYSTEM : prefix == _T("G") || prefix == _T("X") ? CONFIG_GLOBAL : CONFIG_LOCAL;
597 if (g_Git.UnsetConfigValue(key, configLevel))
599 CString msg;
600 msg.Format(IDS_PROC_SAVECONFIGFAILED, key, _T(""));
601 CMessageBox::Show(NULL, msg, _T("TortoiseGit"), MB_OK | MB_ICONERROR);
602 result = 1;
603 break;
607 g_Git.m_IsUseGitDLL = old;
609 return result;
612 bool SaveSimpleCredential(int type)
614 CONFIG_TYPE configLevel;
615 CString value;
616 if (type == SimpleCredentialType::LocalWincred)
618 configLevel = CONFIG_LOCAL;
619 value = _T("wincred");
621 else if (type == SimpleCredentialType::LocalWinstore)
623 configLevel = CONFIG_LOCAL;
624 value = GetWinstorePath();
626 else if (type == SimpleCredentialType::GlobalWincred)
628 configLevel = CONFIG_GLOBAL;
629 value = _T("wincred");
631 else if (type == SimpleCredentialType::GlobalWinstore)
633 configLevel = CONFIG_GLOBAL;
634 value = GetWinstorePath();
636 else if (type == SimpleCredentialType::SystemWincred)
638 configLevel = CONFIG_SYSTEM;
639 value = _T("wincred");
641 else
643 return true;
646 // workaround gitdll bug
647 // TODO: switch to libgit2
648 bool old = g_Git.m_IsUseGitDLL;
649 g_Git.m_IsUseGitDLL = false;
650 if (g_Git.SetConfigValue(_T("credential.helper"), value, configLevel))
652 CString msg;
653 msg.Format(IDS_PROC_SAVECONFIGFAILED, _T("credential.helper"), value);
654 CMessageBox::Show(NULL, msg, _T("TortoiseGit"), MB_OK | MB_ICONERROR);
655 return false;
657 g_Git.m_IsUseGitDLL = old;
658 return true;
661 BOOL CSettingGitCredential::OnApply()
663 CWaitCursor wait;
664 UpdateData();
666 int type = m_ctrlSimpleCredential.GetCurSel();
667 if (type == SimpleCredentialType::SystemWincred && !CAppUtils::IsAdminLogin())
669 RunUAC();
670 EndDialog(0);
671 return FALSE;
673 if (type != SimpleCredentialType::Advanced)
675 if (!SaveSimpleCredential(type))
676 return FALSE;
678 int ret = DeleteOtherKeys(type);
679 if (ret < 0)
680 EndDialog(0);
681 if (ret)
682 return FALSE;
683 SetModified(FALSE);
684 return ISettingsPropPage::OnApply();
687 int sel = m_ctrlConfigType.GetCurSel();
688 if (sel == ConfigType::System && !CAppUtils::IsAdminLogin())
690 RunUAC();
691 EndDialog(0);
692 return FALSE;
695 if (m_ChangedMask & CREDENTIAL_URL)
697 //Add Helper
698 if (m_strHelper.IsEmpty())
700 CMessageBox::Show(NULL, IDS_GITCREDENTIAL_HELPEREMPTY, IDS_APPNAME, MB_OK | MB_ICONERROR);
701 return FALSE;
703 m_strUrl.Replace(L'\\', L'/');
704 m_strHelper.Replace(L'\\', L'/');
706 Save(_T("helper"), m_strHelper);
707 m_ChangedMask &= ~CREDENTIAL_HELPER;
709 int sel = m_ctrlConfigType.GetCurSel();
710 CString prefix = sel == ConfigType::System ? _T("S") : sel == ConfigType::Global ? _T("G") : _T("L");
711 CString text;
712 if (!m_strUrl.IsEmpty())
713 text.Format(_T("%s:%s"), prefix, m_strUrl);
714 else
715 text = prefix;
716 int urlIndex = m_ctrlUrlList.AddString(text);
717 m_ctrlUrlList.SetCurSel(urlIndex);
718 GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(TRUE);
721 if (m_ChangedMask & CREDENTIAL_HELPER)
723 m_strHelper.Replace(L'\\', L'/');
724 Save(_T("helper"), m_strHelper);
727 if (m_ChangedMask & CREDENTIAL_USERNAME)
728 Save(_T("username"), m_strUsername);
730 if (m_ChangedMask & CREDENTIAL_USEHTTPPATH)
731 Save(_T("useHttpPath"), m_bUseHttpPath ? _T("true") : _T(""));
733 SetModified(FALSE);
735 m_ChangedMask = 0;
736 return ISettingsPropPage::OnApply();
739 void CSettingGitCredential::OnBnClickedButtonRemove()
741 int index = m_ctrlUrlList.GetCurSel();
742 if (index >= 0)
744 CString str;
745 m_ctrlUrlList.GetText(index, str);
746 CString msg;
747 msg.Format(IDS_GITCREDENTIAL_DELETEHELPER, str);
748 if (CMessageBox::Show(NULL, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION) == IDYES)
750 CAutoConfig config(true);
751 int pos = str.Find(_T(':'));
752 CString prefix = pos >= 0 ? str.Left(pos) : str;
753 CString url = pos >= 0 ? str.Mid(pos + 1) : _T("");
754 CONFIG_TYPE configLevel = CONFIG_LOCAL;
755 switch (prefix[0])
757 case _T('L'):
759 configLevel = CONFIG_LOCAL;
760 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitLocalConfig()), GIT_CONFIG_LEVEL_LOCAL, FALSE);
761 break;
763 case _T('G'):
764 case _T('X'):
766 configLevel = CONFIG_GLOBAL;
767 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitGlobalConfig()), GIT_CONFIG_LEVEL_GLOBAL, FALSE);
768 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitGlobalXDGConfig()), GIT_CONFIG_LEVEL_XDG, FALSE);
769 break;
771 case _T('S'):
773 if (!CAppUtils::IsAdminLogin())
775 RunUAC();
776 EndDialog(0);
777 return;
779 configLevel = CONFIG_SYSTEM;
780 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitSystemConfig()), GIT_CONFIG_LEVEL_SYSTEM, FALSE);
781 break;
785 STRING_VECTOR list;
786 CStringA urlA = CUnicodeUtils::GetUTF8(url);
787 CStringA pattern = urlA.IsEmpty() ? "^credential\\.[^.]+$" : ("credential\\." + RegexEscape(urlA) + "\\..*");
788 git_config_foreach_match(config, pattern, GetCredentialEntryCallback, &list);
789 for (size_t i = 0; i < list.size(); ++i)
790 g_Git.UnsetConfigValue(list[i], configLevel);
791 m_ctrlUrlList.DeleteString(index);
792 OnLbnSelchangeListUrl();