No need to explicitly initialize CString and use Empty() for clearing CString
[TortoiseGit.git] / src / TortoiseProc / Settings / SettingGitCredential.cpp
blob1a76399231dbb02e4afb98f34b0368022bd86006
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_bUseHttpPath(FALSE)
77 m_ChangedMask = 0;
80 CSettingGitCredential::~CSettingGitCredential()
84 void CSettingGitCredential::DoDataExchange(CDataExchange* pDX)
86 CPropertyPage::DoDataExchange(pDX);
87 DDX_Control(pDX, IDC_COMBO_SIMPLECREDENTIAL, m_ctrlSimpleCredential);
88 DDX_Control(pDX, IDC_LIST_REMOTE, m_ctrlUrlList);
89 DDX_Text(pDX, IDC_EDIT_URL, m_strUrl);
90 DDX_Text(pDX, IDC_COMBO_HELPER, m_strHelper);
91 DDX_Text(pDX, IDC_EDIT_USERNAME, m_strUsername);
92 DDX_Check(pDX, IDC_CHECK_USEHTTPPATH, m_bUseHttpPath);
93 DDX_Control(pDX, IDC_COMBO_CONFIGTYPE, m_ctrlConfigType);
97 BEGIN_MESSAGE_MAP(CSettingGitCredential, CPropertyPage)
98 ON_CBN_SELCHANGE(IDC_COMBO_SIMPLECREDENTIAL, &CSettingGitCredential::OnCbnSelchangeComboSimplecredential)
99 ON_BN_CLICKED(IDC_BUTTON_ADD, &CSettingGitCredential::OnBnClickedButtonAdd)
100 ON_LBN_SELCHANGE(IDC_LIST_REMOTE, &CSettingGitCredential::OnLbnSelchangeListUrl)
101 ON_CBN_SELCHANGE(IDC_COMBO_CONFIGTYPE, &CSettingGitCredential::OnCbnSelchangeComboConfigType)
102 ON_EN_CHANGE(IDC_EDIT_URL, &CSettingGitCredential::OnEnChangeEditUrl)
103 ON_CBN_EDITCHANGE(IDC_COMBO_HELPER, &CSettingGitCredential::OnEnChangeEditHelper)
104 ON_CBN_SELCHANGE(IDC_COMBO_HELPER, &CSettingGitCredential::OnEnChangeEditHelper)
105 ON_EN_CHANGE(IDC_EDIT_USERNAME, &CSettingGitCredential::OnEnChangeEditUsername)
106 ON_BN_CLICKED(IDC_CHECK_USEHTTPPATH, &CSettingGitCredential::OnBnClickedCheckUsehttppath)
107 ON_BN_CLICKED(IDC_BUTTON_REMOVE, &CSettingGitCredential::OnBnClickedButtonRemove)
108 END_MESSAGE_MAP()
110 static bool RunUAC()
112 CString sCmd;
113 sCmd.Format(_T("/command:settings /page:gitcredential /path:\"%s\""), (LPCTSTR)g_Git.m_CurrentDir);
114 return CAppUtils::RunTortoiseGitProc(sCmd, true);
117 static CString GetWinstorePath()
119 TCHAR winstorebuf[MAX_PATH] = {0};
120 ExpandEnvironmentStrings(_T("%AppData%\\GitCredStore\\git-credential-winstore.exe"), winstorebuf, MAX_PATH);
121 CString winstore;
122 winstore.Format(_T("!'%s'"), winstorebuf);
123 return winstore;
126 static bool WincredExists()
128 CString path = CGit::ms_MsysGitRootDir;
129 path.Append(_T("libexec\\git-core\\git-credential-wincred.exe"));
130 return !!PathFileExists(path);
133 static bool WinstoreExists()
135 return !!PathFileExists(GetWinstorePath());
138 static CStringA RegexEscape(CStringA str)
140 CStringA result;
141 for (int i = 0; i < str.GetLength(); ++i)
143 char c = str[i];
144 switch (c)
146 case '\\': case '*': case '+': case '?': case '|':
147 case '{': case '[': case '(': case ')': case '^':
148 case '$': case '.': case '#': case ' ':
149 result.AppendChar('\\');
150 result.AppendChar(c);
151 break;
152 case '\t': result.Append("\\t"); break;
153 case '\n': result.Append("\\n"); break;
154 case '\r': result.Append("\\r"); break;
155 case '\f': result.Append("\\f"); break;
156 default: result.AppendChar(c); break;
160 return result;
163 BOOL CSettingGitCredential::OnInitDialog()
165 ISettingsPropPage::OnInitDialog();
167 AdjustControlSize(IDC_CHECK_USEHTTPPATH);
169 bool hasLocal = GitAdminDir::HasAdminDir(g_Git.m_CurrentDir);
171 m_ctrlUrlList.ResetContent();
173 ConfigType::Init();
174 AddConfigType(ConfigType::Local, CString(MAKEINTRESOURCE(IDS_SETTINGS_LOCAL)), hasLocal);
175 AddConfigType(ConfigType::Global, CString(MAKEINTRESOURCE(IDS_SETTINGS_GLOBAL)));
176 AddConfigType(ConfigType::System, CString(MAKEINTRESOURCE(IDS_SETTINGS_SYSTEM)));
177 m_ctrlConfigType.SetCurSel(0);
179 if (WincredExists())
180 ((CComboBox*) GetDlgItem(IDC_COMBO_HELPER))->AddString(_T("wincred"));
181 if (WinstoreExists())
182 ((CComboBox*) GetDlgItem(IDC_COMBO_HELPER))->AddString(GetWinstorePath());
184 SimpleCredentialType::Init();
185 AddSimpleCredential(SimpleCredentialType::Advanced, CString(MAKEINTRESOURCE(IDS_ADVANCED)));
186 AddSimpleCredential(SimpleCredentialType::None, CString(MAKEINTRESOURCE(IDS_NONE)));
187 AddSimpleCredential(SimpleCredentialType::LocalWincred, CString(MAKEINTRESOURCE(IDS_LOCAL_WINCRED)), hasLocal && WincredExists());
188 AddSimpleCredential(SimpleCredentialType::LocalWinstore, CString(MAKEINTRESOURCE(IDS_LOCAL_WINSTORE)), hasLocal && WinstoreExists());
189 AddSimpleCredential(SimpleCredentialType::GlobalWincred, CString(MAKEINTRESOURCE(IDS_GLOBAL_WINCRED)), WincredExists());
190 AddSimpleCredential(SimpleCredentialType::GlobalWinstore, CString(MAKEINTRESOURCE(IDS_GLOBAL_WINSTORE)), WinstoreExists());
191 AddSimpleCredential(SimpleCredentialType::SystemWincred, CString(MAKEINTRESOURCE(IDS_SYSTEM_WINCRED)), WincredExists());
193 LoadList();
195 EnableAdvancedOptions();
197 UpdateData(FALSE);
198 return TRUE;
200 // CSettingGitCredential message handlers
202 void CSettingGitCredential::OnCbnSelchangeComboSimplecredential()
204 EnableAdvancedOptions();
205 SetModified();
208 void CSettingGitCredential::OnBnClickedButtonAdd()
210 UpdateData();
212 if (m_strHelper.Trim().IsEmpty())
214 CMessageBox::Show(NULL, IDS_GITCREDENTIAL_HELPEREMPTY, IDS_APPNAME, MB_OK | MB_ICONERROR);
215 return;
218 m_ChangedMask = CREDENTIAL_URL | CREDENTIAL_HELPER | CREDENTIAL_USERNAME | CREDENTIAL_USEHTTPPATH;
219 int sel = m_ctrlConfigType.GetCurSel();
220 CString prefix = sel == ConfigType::System ? _T("S") : sel == ConfigType::Global ? _T("G") : _T("L");
221 CString text;
222 if (!m_strUrl.IsEmpty())
223 text.Format(_T("%s:%s"), (LPCTSTR)prefix, (LPCTSTR)m_strUrl);
224 else
225 text = prefix;
226 if (IsUrlExist(text))
228 CString msg;
229 msg.Format(IDS_GITCREDENTIAL_OVERWRITEHELPER, (LPCTSTR)m_strUrl);
230 if (CMessageBox::Show(NULL, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2) == IDYES)
231 m_ChangedMask &= ~CREDENTIAL_URL;
232 else
233 return;
235 else
237 if (m_strUsername.IsEmpty())
238 m_ChangedMask &= ~CREDENTIAL_USERNAME;
239 if (!m_bUseHttpPath)
240 m_ChangedMask &= ~CREDENTIAL_USEHTTPPATH;
243 OnApply();
246 void CSettingGitCredential::EnableAdvancedOptions()
248 BOOL enable = m_ctrlSimpleCredential.GetCurSel() == SimpleCredentialType::Advanced ? TRUE : FALSE;
249 GetDlgItem(IDC_LIST_REMOTE)->EnableWindow(enable);
250 GetDlgItem(IDC_EDIT_URL)->EnableWindow(enable);
251 GetDlgItem(IDC_COMBO_HELPER)->EnableWindow(enable);
252 GetDlgItem(IDC_EDIT_USERNAME)->EnableWindow(enable);
253 GetDlgItem(IDC_COMBO_CONFIGTYPE)->EnableWindow(enable);
254 GetDlgItem(IDC_CHECK_USEHTTPPATH)->EnableWindow(enable);
255 GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(enable);
256 GetDlgItem(IDC_BUTTON_REMOVE)->EnableWindow(enable);
259 BOOL CSettingGitCredential::IsUrlExist(CString &text)
261 CString str;
262 for(int i = 0; i < m_ctrlUrlList.GetCount();i++)
264 m_ctrlUrlList.GetText(i, str);
265 if (str == text)
267 return true;
270 return false;
273 void CSettingGitCredential::OnLbnSelchangeListUrl()
275 CWaitCursor wait;
277 if (m_ChangedMask)
279 if (CMessageBox::Show(NULL, IDS_GITCREDENTIAL_SAVEHELPER, IDS_APPNAME, 1, IDI_QUESTION, IDS_SAVEBUTTON, IDS_DISCARDBUTTON) == 1)
280 OnApply();
282 SetModified(FALSE);
284 CString cmd, output;
285 int index = m_ctrlUrlList.GetCurSel();
286 if (index < 0)
288 m_strHelper.Empty();
289 m_strUrl.Empty();
290 m_strHelper.Empty();
291 m_bUseHttpPath = FALSE;
292 UpdateData(FALSE);
293 return;
296 CString text;
297 m_ctrlUrlList.GetText(index, text);
298 int pos = text.Find(_T(':'));
299 CString prefix = pos >= 0 ? text.Left(pos) : text.Left(1);
300 m_ctrlConfigType.SetCurSel(prefix == _T("S") ? ConfigType::System : prefix == _T("X") ? ConfigType::Global : prefix == _T("G") ? ConfigType::Global : ConfigType::Local);
301 m_strUrl = pos >= 0 ? text.Mid(pos + 1) : _T("");
303 m_strHelper = Load(_T("helper"));
304 m_strUsername = Load(_T("username"));
305 m_bUseHttpPath = Load(_T("useHttpPath")) == _T("true") ? TRUE : FALSE;
307 m_ChangedMask = 0;
309 GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(TRUE);
310 GetDlgItem(IDC_BUTTON_REMOVE)->EnableWindow(TRUE);
311 this->UpdateData(FALSE);
314 void CSettingGitCredential::OnCbnSelchangeComboConfigType()
316 SetModified();
319 void CSettingGitCredential::OnEnChangeEditUrl()
321 m_ChangedMask |= CREDENTIAL_URL;
322 SetModified();
325 void CSettingGitCredential::OnEnChangeEditHelper()
327 m_ChangedMask |= CREDENTIAL_HELPER;
329 UpdateData();
330 if (!m_strHelper.IsEmpty())
331 SetModified();
332 else
333 SetModified(0);
336 void CSettingGitCredential::OnEnChangeEditUsername()
338 m_ChangedMask |= CREDENTIAL_USERNAME;
339 SetModified();
342 void CSettingGitCredential::OnBnClickedCheckUsehttppath()
344 m_ChangedMask |= CREDENTIAL_USEHTTPPATH;
345 SetModified();
348 static int GetCredentialDefaultUrlCallback(const git_config_entry *entry, void *payload)
350 CString display = entry->level == 1 ? _T("S") : entry->level == 2 ? _T("X") : entry->level == 3 ? _T("G") : _T("L");
351 ((STRING_VECTOR *)payload)->push_back(display);
352 return 0;
355 static int GetCredentialUrlCallback(const git_config_entry *entry, void *payload)
357 CString name = CUnicodeUtils::GetUnicode(entry->name);
358 int pos1 = name.Find(_T('.'));
359 int pos2 = name.ReverseFind(_T('.'));
360 CString url = name.Mid(pos1 + 1, pos2 - pos1 - 1);
361 CString display;
362 display.Format(_T("%s:%s"), entry->level == 1 ? _T("S") : entry->level == 2 ? _T("X") : entry->level == 3 ? _T("G") : _T("L"), url);
363 ((STRING_VECTOR *)payload)->push_back(display);
364 return 0;
367 static int GetCredentialEntryCallback(const git_config_entry *entry, void *payload)
369 CString name = CUnicodeUtils::GetUnicode(entry->name);
370 ((STRING_VECTOR *)payload)->push_back(name);
371 return 0;
374 static int GetCredentialAnyEntryCallback(const git_config_entry *entry, void *payload)
376 CString name = CUnicodeUtils::GetUnicode(entry->name);
377 CString value = CUnicodeUtils::GetUnicode(entry->value);
378 CString display = entry->level == 1 ? _T("S") : entry->level == 2 ? _T("X") : entry->level == 3 ? _T("G") : _T("L");
379 CString text;
380 text.Format(_T("%s\n%s\n%s"), (LPCTSTR)display, (LPCTSTR)name, (LPCTSTR)value);
381 ((STRING_VECTOR *)payload)->push_back(text);
382 return 0;
385 void CSettingGitCredential::AddConfigType(int &index, CString text, bool add)
387 if (add)
388 index = m_ctrlConfigType.AddString(text);
391 void CSettingGitCredential::AddSimpleCredential(int &index, CString text, bool add)
393 if (add)
394 index = m_ctrlSimpleCredential.AddString(text);
397 void CSettingGitCredential::LoadList()
399 CAutoConfig config(true);
400 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitLocalConfig()), GIT_CONFIG_LEVEL_LOCAL, FALSE);
401 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitGlobalConfig()), GIT_CONFIG_LEVEL_GLOBAL, FALSE);
402 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitGlobalXDGConfig()), GIT_CONFIG_LEVEL_XDG, FALSE);
403 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitSystemConfig()), GIT_CONFIG_LEVEL_SYSTEM, FALSE);
405 STRING_VECTOR defaultList, urlList;
406 git_config_foreach_match(config, "credential\\.helper", GetCredentialDefaultUrlCallback, &defaultList);
407 git_config_foreach_match(config, "credential\\..*\\.helper", GetCredentialUrlCallback, &urlList);
408 STRING_VECTOR anyList;
409 git_config_foreach_match(config, "credential\\..*", GetCredentialAnyEntryCallback, &anyList);
411 for (size_t i = 0; i < defaultList.size(); ++i)
412 m_ctrlUrlList.AddString(defaultList[i]);
413 for (size_t i = 0; i < urlList.size(); ++i)
414 m_ctrlUrlList.AddString(urlList[i]);
416 if (anyList.empty())
418 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::None);
419 return;
421 if (anyList.size() > 1)
423 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::Advanced);
424 return;
427 int pos = 0;
428 CString prefix = anyList[0].Tokenize(_T("\n"), pos);
429 CString key = anyList[0].Tokenize(_T("\n"), pos);
430 CString value = anyList[0].Tokenize(_T("\n"), pos);
431 if (key != _T("credential.helper"))
433 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::Advanced);
434 return;
437 CString winstore = GetWinstorePath();
438 if (prefix == _T("L"))
440 if (value == _T("wincred"))
442 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::LocalWincred);
443 return;
445 else if (value == winstore)
447 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::LocalWinstore);
448 return;
452 if (prefix == _T("G") || prefix == _T("X"))
454 if (value == _T("wincred"))
456 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::GlobalWincred);
457 return;
459 else if (value == winstore)
461 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::GlobalWinstore);
462 return;
466 if (prefix == _T("S"))
468 if (value == _T("wincred"))
470 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::SystemWincred);
471 return;
475 m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::Advanced);
478 CString CSettingGitCredential::Load(CString key)
480 CString cmd;
482 if (m_strUrl.IsEmpty())
483 cmd.Format(_T("credential.%s"), (LPCTSTR)key);
484 else
485 cmd.Format(_T("credential.%s.%s"), (LPCTSTR)m_strUrl, (LPCTSTR)key);
487 CAutoConfig config(true);
488 int sel = m_ctrlConfigType.GetCurSel();
489 if (sel == ConfigType::Local)
491 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitLocalConfig()), GIT_CONFIG_LEVEL_LOCAL, FALSE);
493 else if (sel == ConfigType::Global)
495 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitGlobalConfig()), GIT_CONFIG_LEVEL_GLOBAL, FALSE);
496 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitGlobalXDGConfig()), GIT_CONFIG_LEVEL_XDG, FALSE);
498 else if (sel == ConfigType::System)
500 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitSystemConfig()), GIT_CONFIG_LEVEL_SYSTEM, FALSE);
503 CStringA cmdA = CUnicodeUtils::GetUTF8(cmd);
504 CStringA valueA;
505 git_config_entry* entry;
506 if (!git_config_get_entry(&entry, config, cmdA))
507 valueA = CStringA(entry->value);
508 git_config_entry_free(entry);
510 return CUnicodeUtils::GetUnicode(valueA);
513 void CSettingGitCredential::Save(CString key, CString value)
515 CString cmd, out;
517 if (m_strUrl.IsEmpty())
518 cmd.Format(_T("credential.%s"), (LPCTSTR)key);
519 else
520 cmd.Format(_T("credential.%s.%s"), (LPCTSTR)m_strUrl, (LPCTSTR)key);
522 int sel = m_ctrlConfigType.GetCurSel();
523 CONFIG_TYPE configLevel = sel == ConfigType::System ? CONFIG_SYSTEM : sel == ConfigType::Global ? CONFIG_GLOBAL : CONFIG_LOCAL;
525 bool old = g_Git.m_IsUseGitDLL;
526 // workaround gitdll bug
527 // TODO: switch to libgit2
528 g_Git.m_IsUseGitDLL = false;
529 if (g_Git.SetConfigValue(cmd, value, configLevel))
531 CString msg;
532 msg.Format(IDS_PROC_SAVECONFIGFAILED, (LPCTSTR)cmd, (LPCTSTR)value);
533 CMessageBox::Show(NULL, msg, _T("TortoiseGit"), MB_OK | MB_ICONERROR);
535 if (value.IsEmpty())
537 if (g_Git.UnsetConfigValue(cmd, configLevel))
539 CString msg;
540 msg.Format(IDS_PROC_SAVECONFIGFAILED, (LPCTSTR)cmd, (LPCTSTR)value);
541 CMessageBox::Show(NULL, msg, _T("TortoiseGit"), MB_OK | MB_ICONERROR);
544 g_Git.m_IsUseGitDLL = old;
547 static int DeleteOtherKeys(int type)
549 CString match;
550 if (type == SimpleCredentialType::LocalWincred)
551 match = _T("L\ncredential.helper\nwincred");
552 else if (type == SimpleCredentialType::LocalWinstore)
553 match = _T("L\ncredential.helper\n") + GetWinstorePath();
554 else if (type == SimpleCredentialType::GlobalWincred)
555 match = _T("G\ncredential.helper\nwincred");
556 else if (type == SimpleCredentialType::GlobalWinstore)
557 match = _T("G\ncredential.helper\n") + GetWinstorePath();
558 else if (type == SimpleCredentialType::SystemWincred)
559 match = _T("S\ncredential.helper\nwincred");
561 CAutoConfig config(true);
562 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitLocalConfig()), GIT_CONFIG_LEVEL_LOCAL, FALSE);
563 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitGlobalConfig()), GIT_CONFIG_LEVEL_GLOBAL, FALSE);
564 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitGlobalXDGConfig()), GIT_CONFIG_LEVEL_XDG, FALSE);
565 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitSystemConfig()), GIT_CONFIG_LEVEL_SYSTEM, FALSE);
567 STRING_VECTOR list;
568 git_config_foreach_match(config, "credential\\..*", GetCredentialAnyEntryCallback, &list);
569 for (size_t i = 0; i < list.size(); ++i)
571 int pos = 0;
572 CString prefix = list[i].Tokenize(_T("\n"), pos);
573 if (prefix == _T("S") && !CAppUtils::IsAdminLogin())
575 RunUAC();
576 return -1;
580 int result = 0;
581 // workaround gitdll bug
582 // TODO: switch to libgit2
583 bool old = g_Git.m_IsUseGitDLL;
584 g_Git.m_IsUseGitDLL = false;
585 for (size_t i = 0; i < list.size(); ++i)
587 if (list[i] != match)
589 int pos = 0;
590 CString prefix = list[i].Tokenize(_T("\n"), pos);
591 CString key = list[i].Tokenize(_T("\n"), pos);
592 CONFIG_TYPE configLevel = prefix == _T("S") ? CONFIG_SYSTEM : prefix == _T("G") || prefix == _T("X") ? CONFIG_GLOBAL : CONFIG_LOCAL;
593 if (g_Git.UnsetConfigValue(key, configLevel))
595 CString msg;
596 msg.Format(IDS_PROC_SAVECONFIGFAILED, (LPCTSTR)key, _T(""));
597 CMessageBox::Show(NULL, msg, _T("TortoiseGit"), MB_OK | MB_ICONERROR);
598 result = 1;
599 break;
603 g_Git.m_IsUseGitDLL = old;
605 return result;
608 bool SaveSimpleCredential(int type)
610 CONFIG_TYPE configLevel;
611 CString value;
612 if (type == SimpleCredentialType::LocalWincred)
614 configLevel = CONFIG_LOCAL;
615 value = _T("wincred");
617 else if (type == SimpleCredentialType::LocalWinstore)
619 configLevel = CONFIG_LOCAL;
620 value = GetWinstorePath();
622 else if (type == SimpleCredentialType::GlobalWincred)
624 configLevel = CONFIG_GLOBAL;
625 value = _T("wincred");
627 else if (type == SimpleCredentialType::GlobalWinstore)
629 configLevel = CONFIG_GLOBAL;
630 value = GetWinstorePath();
632 else if (type == SimpleCredentialType::SystemWincred)
634 configLevel = CONFIG_SYSTEM;
635 value = _T("wincred");
637 else
639 return true;
642 // workaround gitdll bug
643 // TODO: switch to libgit2
644 bool old = g_Git.m_IsUseGitDLL;
645 g_Git.m_IsUseGitDLL = false;
646 if (g_Git.SetConfigValue(_T("credential.helper"), value, configLevel))
648 CString msg;
649 msg.Format(IDS_PROC_SAVECONFIGFAILED, _T("credential.helper"), (LPCTSTR)value);
650 CMessageBox::Show(NULL, msg, _T("TortoiseGit"), MB_OK | MB_ICONERROR);
651 return false;
653 g_Git.m_IsUseGitDLL = old;
654 return true;
657 BOOL CSettingGitCredential::OnApply()
659 CWaitCursor wait;
660 UpdateData();
662 int type = m_ctrlSimpleCredential.GetCurSel();
663 if (type == SimpleCredentialType::SystemWincred && !CAppUtils::IsAdminLogin())
665 RunUAC();
666 EndDialog(0);
667 return FALSE;
669 if (type != SimpleCredentialType::Advanced)
671 if (!SaveSimpleCredential(type))
672 return FALSE;
674 int ret = DeleteOtherKeys(type);
675 if (ret < 0)
676 EndDialog(0);
677 if (ret)
678 return FALSE;
679 SetModified(FALSE);
680 return ISettingsPropPage::OnApply();
683 int sel = m_ctrlConfigType.GetCurSel();
684 if (sel == ConfigType::System && !CAppUtils::IsAdminLogin())
686 RunUAC();
687 EndDialog(0);
688 return FALSE;
691 if (m_ChangedMask & CREDENTIAL_URL)
693 //Add Helper
694 if (m_strHelper.IsEmpty())
696 CMessageBox::Show(NULL, IDS_GITCREDENTIAL_HELPEREMPTY, IDS_APPNAME, MB_OK | MB_ICONERROR);
697 return FALSE;
699 m_strUrl.Replace(L'\\', L'/');
700 m_strHelper.Replace(L'\\', L'/');
702 Save(_T("helper"), m_strHelper);
703 m_ChangedMask &= ~CREDENTIAL_HELPER;
705 sel = m_ctrlConfigType.GetCurSel();
706 CString prefix = sel == ConfigType::System ? _T("S") : sel == ConfigType::Global ? _T("G") : _T("L");
707 CString text;
708 if (!m_strUrl.IsEmpty())
709 text.Format(_T("%s:%s"), (LPCTSTR)prefix, (LPCTSTR)m_strUrl);
710 else
711 text = prefix;
712 int urlIndex = m_ctrlUrlList.AddString(text);
713 m_ctrlUrlList.SetCurSel(urlIndex);
714 GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(TRUE);
717 if (m_ChangedMask & CREDENTIAL_HELPER)
719 m_strHelper.Replace(L'\\', L'/');
720 Save(_T("helper"), m_strHelper);
723 if (m_ChangedMask & CREDENTIAL_USERNAME)
724 Save(_T("username"), m_strUsername);
726 if (m_ChangedMask & CREDENTIAL_USEHTTPPATH)
727 Save(_T("useHttpPath"), m_bUseHttpPath ? _T("true") : _T(""));
729 SetModified(FALSE);
731 m_ChangedMask = 0;
732 return ISettingsPropPage::OnApply();
735 void CSettingGitCredential::OnBnClickedButtonRemove()
737 int index = m_ctrlUrlList.GetCurSel();
738 if (index >= 0)
740 CString str;
741 m_ctrlUrlList.GetText(index, str);
742 CString msg;
743 msg.Format(IDS_WARN_REMOVE, (LPCTSTR)str);
744 if (CMessageBox::Show(NULL, msg, _T("TortoiseGit"), MB_YESNO | MB_ICONQUESTION) == IDYES)
746 CAutoConfig config(true);
747 int pos = str.Find(_T(':'));
748 CString prefix = pos >= 0 ? str.Left(pos) : str;
749 CString url = pos >= 0 ? str.Mid(pos + 1) : _T("");
750 CONFIG_TYPE configLevel = CONFIG_LOCAL;
751 switch (prefix[0])
753 case _T('L'):
755 configLevel = CONFIG_LOCAL;
756 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitLocalConfig()), GIT_CONFIG_LEVEL_LOCAL, FALSE);
757 break;
759 case _T('G'):
760 case _T('X'):
762 configLevel = CONFIG_GLOBAL;
763 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitGlobalConfig()), GIT_CONFIG_LEVEL_GLOBAL, FALSE);
764 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitGlobalXDGConfig()), GIT_CONFIG_LEVEL_XDG, FALSE);
765 break;
767 case _T('S'):
769 if (!CAppUtils::IsAdminLogin())
771 RunUAC();
772 EndDialog(0);
773 return;
775 configLevel = CONFIG_SYSTEM;
776 git_config_add_file_ondisk(config, CGit::GetGitPathStringA(g_Git.GetGitSystemConfig()), GIT_CONFIG_LEVEL_SYSTEM, FALSE);
777 break;
781 STRING_VECTOR list;
782 CStringA urlA = CUnicodeUtils::GetUTF8(url);
783 CStringA pattern = urlA.IsEmpty() ? "^credential\\.[^.]+$" : ("credential\\." + RegexEscape(urlA) + "\\..*");
784 git_config_foreach_match(config, pattern, GetCredentialEntryCallback, &list);
785 for (size_t i = 0; i < list.size(); ++i)
786 g_Git.UnsetConfigValue(list[i], configLevel);
787 m_ctrlUrlList.DeleteString(index);
788 OnLbnSelchangeListUrl();