1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2013 - 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
23 #include "TortoiseProc.h"
24 #include "SettingGitCredential.h"
26 #include "GitAdminDir.h"
27 #include "MessageBox.h"
30 #include "PathUtils.h"
32 namespace SimpleCredentialType
36 static int LocalWincred
;
37 static int LocalWinstore
;
38 static int GlobalWincred
;
39 static int GlobalWinstore
;
40 static int SystemWincred
;
68 // CSettingGitCredential dialog
70 IMPLEMENT_DYNAMIC(CSettingGitCredential
, ISettingsPropPage
)
72 CSettingGitCredential::CSettingGitCredential(CString cmdPath
)
73 : ISettingsPropPage(CSettingGitCredential::IDD
)
76 , m_strUsername(_T(""))
77 , m_bUseHttpPath(FALSE
)
84 CSettingGitCredential::~CSettingGitCredential()
88 void CSettingGitCredential::DoDataExchange(CDataExchange
* pDX
)
90 CPropertyPage::DoDataExchange(pDX
);
91 DDX_Control(pDX
, IDC_COMBO_SIMPLECREDENTIAL
, m_ctrlSimpleCredential
);
92 DDX_Control(pDX
, IDC_LIST_REMOTE
, m_ctrlUrlList
);
93 DDX_Text(pDX
, IDC_EDIT_URL
, m_strUrl
);
94 DDX_Text(pDX
, IDC_COMBO_HELPER
, m_strHelper
);
95 DDX_Text(pDX
, IDC_EDIT_USERNAME
, m_strUsername
);
96 DDX_Check(pDX
, IDC_CHECK_USEHTTPPATH
, m_bUseHttpPath
);
97 DDX_Control(pDX
, IDC_COMBO_CONFIGTYPE
, m_ctrlConfigType
);
101 BEGIN_MESSAGE_MAP(CSettingGitCredential
, CPropertyPage
)
102 ON_CBN_SELCHANGE(IDC_COMBO_SIMPLECREDENTIAL
, &CSettingGitCredential::OnCbnSelchangeComboSimplecredential
)
103 ON_BN_CLICKED(IDC_BUTTON_ADD
, &CSettingGitCredential::OnBnClickedButtonAdd
)
104 ON_LBN_SELCHANGE(IDC_LIST_REMOTE
, &CSettingGitCredential::OnLbnSelchangeListUrl
)
105 ON_CBN_SELCHANGE(IDC_COMBO_CONFIGTYPE
, &CSettingGitCredential::OnCbnSelchangeComboConfigType
)
106 ON_EN_CHANGE(IDC_EDIT_URL
, &CSettingGitCredential::OnEnChangeEditUrl
)
107 ON_CBN_EDITCHANGE(IDC_COMBO_HELPER
, &CSettingGitCredential::OnEnChangeEditHelper
)
108 ON_CBN_SELCHANGE(IDC_COMBO_HELPER
, &CSettingGitCredential::OnEnChangeEditHelper
)
109 ON_EN_CHANGE(IDC_EDIT_USERNAME
, &CSettingGitCredential::OnEnChangeEditUsername
)
110 ON_BN_CLICKED(IDC_CHECK_USEHTTPPATH
, &CSettingGitCredential::OnBnClickedCheckUsehttppath
)
111 ON_BN_CLICKED(IDC_BUTTON_REMOVE
, &CSettingGitCredential::OnBnClickedButtonRemove
)
117 sCmd
.Format(_T("/command:settings /page:gitcredential /path:\"%s\""), g_Git
.m_CurrentDir
);
118 return CAppUtils::RunTortoiseGitProc(sCmd
, true);
121 static CString
GetWinstorePath()
123 TCHAR winstorebuf
[MAX_PATH
];
124 ExpandEnvironmentStrings(_T("%AppData%\\GitCredStore\\git-credential-winstore.exe"), winstorebuf
, MAX_PATH
);
126 winstore
.Format(_T("!'%s'"), winstorebuf
);
130 static bool WincredExists()
132 CString path
= g_Git
.ms_LastMsysGitDir
;
133 if (g_Git
.ms_LastMsysGitDir
.Right(1) != _T("\\"))
134 path
.AppendChar(_T('\\'));
135 path
.Append(_T("..\\libexec\\git-core\\git-credential-wincred.exe"));
136 return !!PathFileExists(path
);
139 static bool WinstoreExists()
141 return !!PathFileExists(GetWinstorePath());
144 static CStringA
RegexEscape(CStringA str
)
147 for (int i
= 0; i
< str
.GetLength(); ++i
)
152 case '\\': case '*': case '+': case '?': case '|':
153 case '{': case '[': case '(': case ')': case '^':
154 case '$': case '.': case '#': case ' ':
155 result
.AppendChar('\\');
156 result
.AppendChar(c
);
158 case '\t': result
.Append("\\t"); break;
159 case '\n': result
.Append("\\n"); break;
160 case '\r': result
.Append("\\r"); break;
161 case '\f': result
.Append("\\f"); break;
162 default: result
.AppendChar(c
); break;
169 BOOL
CSettingGitCredential::OnInitDialog()
171 ISettingsPropPage::OnInitDialog();
174 bool hasLocal
= g_GitAdminDir
.HasAdminDir(m_cmdPath
, &proj
);
178 this->GetWindowText(title
);
179 this->SetWindowText(title
+ _T(" - ") + proj
);
182 m_ctrlUrlList
.ResetContent();
185 AddConfigType(ConfigType::Local
, CString(MAKEINTRESOURCE(IDS_SETTINGS_LOCAL
)), hasLocal
);
186 AddConfigType(ConfigType::Global
, CString(MAKEINTRESOURCE(IDS_SETTINGS_GLOBAL
)));
187 AddConfigType(ConfigType::System
, CString(MAKEINTRESOURCE(IDS_SETTINGS_SYSTEM
)));
188 m_ctrlConfigType
.SetCurSel(0);
191 ((CComboBox
*) GetDlgItem(IDC_COMBO_HELPER
))->AddString(_T("wincred"));
192 if (WinstoreExists())
193 ((CComboBox
*) GetDlgItem(IDC_COMBO_HELPER
))->AddString(GetWinstorePath());
195 SimpleCredentialType::Init();
196 AddSimpleCredential(SimpleCredentialType::Advanced
, CString(MAKEINTRESOURCE(IDS_ADVANCED
)));
197 AddSimpleCredential(SimpleCredentialType::None
, CString(MAKEINTRESOURCE(IDS_NONE
)));
198 AddSimpleCredential(SimpleCredentialType::LocalWincred
, CString(MAKEINTRESOURCE(IDS_LOCAL_WINCRED
)), hasLocal
&& WincredExists());
199 AddSimpleCredential(SimpleCredentialType::LocalWinstore
, CString(MAKEINTRESOURCE(IDS_LOCAL_WINSTORE
)), hasLocal
&& WinstoreExists());
200 AddSimpleCredential(SimpleCredentialType::GlobalWincred
, CString(MAKEINTRESOURCE(IDS_GLOBAL_WINCRED
)), WincredExists());
201 AddSimpleCredential(SimpleCredentialType::GlobalWinstore
, CString(MAKEINTRESOURCE(IDS_GLOBAL_WINSTORE
)), WinstoreExists());
202 AddSimpleCredential(SimpleCredentialType::SystemWincred
, CString(MAKEINTRESOURCE(IDS_SYSTEM_WINCRED
)), WincredExists());
206 EnableAdvancedOptions();
211 // CSettingGitCredential message handlers
213 void CSettingGitCredential::OnCbnSelchangeComboSimplecredential()
215 EnableAdvancedOptions();
219 void CSettingGitCredential::OnBnClickedButtonAdd()
223 if (m_strHelper
.Trim().IsEmpty())
225 CMessageBox::Show(NULL
, IDS_GITCREDENTIAL_HELPEREMPTY
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
229 m_ChangedMask
= CREDENTIAL_URL
| CREDENTIAL_HELPER
| CREDENTIAL_USERNAME
| CREDENTIAL_USEHTTPPATH
;
230 int sel
= m_ctrlConfigType
.GetCurSel();
231 CString prefix
= sel
== ConfigType::System
? _T("S") : sel
== ConfigType::Global
? _T("G") : _T("L");
233 if (!m_strUrl
.IsEmpty())
234 text
.Format(_T("%s:%s"), prefix
, m_strUrl
);
237 if (IsUrlExist(text
))
240 msg
.Format(IDS_GITCREDENTIAL_OVERWRITEHELPER
, m_strUrl
);
241 if (CMessageBox::Show(NULL
, msg
, _T("TortoiseGit"), MB_YESNO
| MB_ICONQUESTION
| MB_DEFBUTTON2
) == IDYES
)
242 m_ChangedMask
&= ~CREDENTIAL_URL
;
248 if (m_strUsername
.IsEmpty())
249 m_ChangedMask
&= ~CREDENTIAL_USERNAME
;
251 m_ChangedMask
&= ~CREDENTIAL_USEHTTPPATH
;
257 void CSettingGitCredential::EnableAdvancedOptions()
259 BOOL enable
= m_ctrlSimpleCredential
.GetCurSel() == SimpleCredentialType::Advanced
? TRUE
: FALSE
;
260 GetDlgItem(IDC_LIST_REMOTE
)->EnableWindow(enable
);
261 GetDlgItem(IDC_EDIT_URL
)->EnableWindow(enable
);
262 GetDlgItem(IDC_COMBO_HELPER
)->EnableWindow(enable
);
263 GetDlgItem(IDC_EDIT_USERNAME
)->EnableWindow(enable
);
264 GetDlgItem(IDC_COMBO_CONFIGTYPE
)->EnableWindow(enable
);
265 GetDlgItem(IDC_CHECK_USEHTTPPATH
)->EnableWindow(enable
);
266 GetDlgItem(IDC_BUTTON_ADD
)->EnableWindow(enable
);
267 GetDlgItem(IDC_BUTTON_REMOVE
)->EnableWindow(enable
);
270 BOOL
CSettingGitCredential::IsUrlExist(CString
&text
)
273 for(int i
= 0; i
< m_ctrlUrlList
.GetCount();i
++)
275 m_ctrlUrlList
.GetText(i
, str
);
284 void CSettingGitCredential::OnLbnSelchangeListUrl()
290 if (CMessageBox::Show(NULL
, IDS_GITCREDENTIAL_SAVEHELPER
, IDS_APPNAME
, 1, IDI_QUESTION
, IDS_SAVEBUTTON
, IDS_DISCARDBUTTON
) == 1)
296 int index
= m_ctrlUrlList
.GetCurSel();
302 m_bUseHttpPath
= FALSE
;
308 m_ctrlUrlList
.GetText(index
, text
);
309 int pos
= text
.Find(_T(':'));
310 CString prefix
= pos
>= 0 ? text
.Left(pos
) : text
.Left(1);
311 m_ctrlConfigType
.SetCurSel(prefix
== _T("S") ? ConfigType::System
: prefix
== _T("X") ? ConfigType::Global
: prefix
== _T("G") ? ConfigType::Global
: ConfigType::Local
);
312 m_strUrl
= pos
>= 0 ? text
.Mid(pos
+ 1) : _T("");
314 m_strHelper
= Load(_T("helper"));
315 m_strUsername
= Load(_T("username"));
316 m_bUseHttpPath
= Load(_T("useHttpPath")) == _T("true") ? TRUE
: FALSE
;
320 GetDlgItem(IDC_BUTTON_ADD
)->EnableWindow(TRUE
);
321 GetDlgItem(IDC_BUTTON_REMOVE
)->EnableWindow(TRUE
);
322 this->UpdateData(FALSE
);
325 void CSettingGitCredential::OnCbnSelchangeComboConfigType()
330 void CSettingGitCredential::OnEnChangeEditUrl()
332 m_ChangedMask
|= CREDENTIAL_URL
;
336 void CSettingGitCredential::OnEnChangeEditHelper()
338 m_ChangedMask
|= CREDENTIAL_HELPER
;
341 if (!m_strHelper
.IsEmpty())
347 void CSettingGitCredential::OnEnChangeEditUsername()
349 m_ChangedMask
|= CREDENTIAL_USERNAME
;
353 void CSettingGitCredential::OnBnClickedCheckUsehttppath()
355 m_ChangedMask
|= CREDENTIAL_USEHTTPPATH
;
359 static int GetCredentialDefaultUrlCallback(const git_config_entry
*entry
, void *payload
)
361 CString display
= entry
->level
== 1 ? _T("S") : entry
->level
== 2 ? _T("X") : entry
->level
== 3 ? _T("G") : _T("L");
362 ((STRING_VECTOR
*)payload
)->push_back(display
);
366 static int GetCredentialUrlCallback(const git_config_entry
*entry
, void *payload
)
368 CString name
= CUnicodeUtils::GetUnicode(entry
->name
);
369 int pos1
= name
.Find(_T('.'));
370 int pos2
= name
.ReverseFind(_T('.'));
371 CString url
= name
.Mid(pos1
+ 1, pos2
- pos1
- 1);
373 display
.Format(_T("%s:%s"), entry
->level
== 1 ? _T("S") : entry
->level
== 2 ? _T("X") : entry
->level
== 3 ? _T("G") : _T("L"), url
);
374 ((STRING_VECTOR
*)payload
)->push_back(display
);
378 static int GetCredentialEntryCallback(const git_config_entry
*entry
, void *payload
)
380 CString name
= CUnicodeUtils::GetUnicode(entry
->name
);
381 ((STRING_VECTOR
*)payload
)->push_back(name
);
385 static int GetCredentialAnyEntryCallback(const git_config_entry
*entry
, void *payload
)
387 CString name
= CUnicodeUtils::GetUnicode(entry
->name
);
388 CString value
= CUnicodeUtils::GetUnicode(entry
->value
);
389 CString display
= entry
->level
== 1 ? _T("S") : entry
->level
== 2 ? _T("X") : entry
->level
== 3 ? _T("G") : _T("L");
391 text
.Format(_T("%s\n%s\n%s"), display
, name
, value
);
392 ((STRING_VECTOR
*)payload
)->push_back(text
);
396 void CSettingGitCredential::AddConfigType(int &index
, CString text
, bool add
)
399 index
= m_ctrlConfigType
.AddString(text
);
402 void CSettingGitCredential::AddSimpleCredential(int &index
, CString text
, bool add
)
405 index
= m_ctrlSimpleCredential
.AddString(text
);
408 void CSettingGitCredential::LoadList()
411 git_config_new(&config
);
412 CStringA projectConfigA
= CUnicodeUtils::GetUTF8(g_Git
.GetGitLocalConfig());
413 git_config_add_file_ondisk(config
, projectConfigA
.GetBuffer(), 4, FALSE
);
414 projectConfigA
.ReleaseBuffer();
415 CStringA globalConfigA
= CUnicodeUtils::GetUTF8(g_Git
.GetGitGlobalConfig());
416 git_config_add_file_ondisk(config
, globalConfigA
.GetBuffer(), 3, FALSE
);
417 globalConfigA
.ReleaseBuffer();
418 CStringA globalXDGConfigA
= CUnicodeUtils::GetUTF8(g_Git
.GetGitGlobalXDGConfig());
419 git_config_add_file_ondisk(config
, globalXDGConfigA
.GetBuffer(), 2, FALSE
);
420 globalXDGConfigA
.ReleaseBuffer();
421 CStringA systemConfigA
= CUnicodeUtils::GetUTF8(g_Git
.GetGitSystemConfig());
422 git_config_add_file_ondisk(config
, systemConfigA
.GetBuffer(), 1, FALSE
);
423 systemConfigA
.ReleaseBuffer();
425 STRING_VECTOR defaultList
, urlList
;
426 git_config_foreach_match(config
, "credential\\.helper", GetCredentialDefaultUrlCallback
, &defaultList
);
427 git_config_foreach_match(config
, "credential\\..*\\.helper", GetCredentialUrlCallback
, &urlList
);
428 STRING_VECTOR anyList
;
429 git_config_foreach_match(config
, "credential\\..*", GetCredentialAnyEntryCallback
, &anyList
);
430 git_config_free(config
);
432 for (int i
= 0; i
< defaultList
.size(); ++i
)
433 m_ctrlUrlList
.AddString(defaultList
[i
]);
434 for (int i
= 0; i
< urlList
.size(); ++i
)
435 m_ctrlUrlList
.AddString(urlList
[i
]);
439 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::None
);
442 if (anyList
.size() > 1)
444 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::Advanced
);
449 CString prefix
= anyList
[0].Tokenize(_T("\n"), pos
);
450 CString key
= anyList
[0].Tokenize(_T("\n"), pos
);
451 CString value
= anyList
[0].Tokenize(_T("\n"), pos
);
452 if (key
!= _T("credential.helper"))
454 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::Advanced
);
458 CString winstore
= GetWinstorePath();
459 if (prefix
== _T("L"))
461 if (value
== _T("wincred"))
463 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::LocalWincred
);
466 else if (value
== winstore
)
468 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::LocalWinstore
);
473 if (prefix
== _T("G") || prefix
== _T("X"))
475 if (value
== _T("wincred"))
477 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::GlobalWincred
);
480 else if (value
== winstore
)
482 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::GlobalWinstore
);
487 if (prefix
== _T("S"))
489 if (value
== _T("wincred"))
491 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::SystemWincred
);
496 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::Advanced
);
499 CString
CSettingGitCredential::Load(CString key
)
503 if (m_strUrl
.IsEmpty())
504 cmd
.Format(_T("credential.%s"), key
);
506 cmd
.Format(_T("credential.%s.%s"), m_strUrl
, key
);
509 git_config_new(&config
);
510 int sel
= m_ctrlConfigType
.GetCurSel();
511 if (sel
== ConfigType::Local
)
513 CStringA projectConfigA
= CUnicodeUtils::GetUTF8(g_Git
.GetGitLocalConfig());
514 git_config_add_file_ondisk(config
, projectConfigA
.GetBuffer(), 1, FALSE
);
515 projectConfigA
.ReleaseBuffer();
517 else if (sel
== ConfigType::Global
)
519 CStringA globalConfigA
= CUnicodeUtils::GetUTF8(g_Git
.GetGitGlobalConfig());
520 git_config_add_file_ondisk(config
, globalConfigA
.GetBuffer(), 2, FALSE
);
521 globalConfigA
.ReleaseBuffer();
522 CStringA globalXDGConfigA
= CUnicodeUtils::GetUTF8(g_Git
.GetGitGlobalXDGConfig());
523 git_config_add_file_ondisk(config
, globalXDGConfigA
.GetBuffer(), 1, FALSE
);
524 globalXDGConfigA
.ReleaseBuffer();
526 else if (sel
== ConfigType::System
)
528 CStringA systemConfigA
= CUnicodeUtils::GetUTF8(g_Git
.GetGitSystemConfig());
529 git_config_add_file_ondisk(config
, systemConfigA
.GetBuffer(), 1, FALSE
);
530 systemConfigA
.ReleaseBuffer();
533 CStringA cmdA
= CUnicodeUtils::GetUTF8(cmd
);
535 const git_config_entry
*entry
;
536 if (!git_config_get_entry(&entry
, config
, cmdA
))
537 valueA
= CStringA(entry
->value
);
538 cmdA
.ReleaseBuffer();
539 git_config_free(config
);
541 return CUnicodeUtils::GetUnicode(valueA
);
544 void CSettingGitCredential::Save(CString key
, CString value
)
548 if (m_strUrl
.IsEmpty())
549 cmd
.Format(_T("credential.%s"), key
);
551 cmd
.Format(_T("credential.%s.%s"), m_strUrl
, key
);
553 int sel
= m_ctrlConfigType
.GetCurSel();
554 CONFIG_TYPE configLevel
= sel
== ConfigType::System
? CONFIG_SYSTEM
: sel
== ConfigType::Global
? CONFIG_GLOBAL
: CONFIG_LOCAL
;
556 bool old
= g_Git
.m_IsUseGitDLL
;
557 // workaround gitdll bug
558 // TODO: switch to libgit2
559 g_Git
.m_IsUseGitDLL
= false;
560 if (g_Git
.SetConfigValue(cmd
, value
, configLevel
, CP_UTF8
, &g_Git
.m_CurrentDir
))
563 msg
.Format(IDS_PROC_SAVECONFIGFAILED
, cmd
, value
);
564 CMessageBox::Show(NULL
, msg
, _T("TortoiseGit"), MB_OK
| MB_ICONERROR
);
568 if (g_Git
.UnsetConfigValue(cmd
, configLevel
, CP_UTF8
, &g_Git
.m_CurrentDir
))
571 msg
.Format(IDS_PROC_SAVECONFIGFAILED
, cmd
, value
);
572 CMessageBox::Show(NULL
, msg
, _T("TortoiseGit"), MB_OK
| MB_ICONERROR
);
575 g_Git
.m_IsUseGitDLL
= old
;
578 static int DeleteOtherKeys(int type
)
581 if (type
== SimpleCredentialType::LocalWincred
)
582 match
= _T("L\ncredential.helper\nwincred");
583 else if (type
== SimpleCredentialType::LocalWinstore
)
584 match
= _T("L\ncredential.helper\n") + GetWinstorePath();
585 else if (type
== SimpleCredentialType::GlobalWincred
)
586 match
= _T("G\ncredential.helper\nwincred");
587 else if (type
== SimpleCredentialType::GlobalWinstore
)
588 match
= _T("G\ncredential.helper\n") + GetWinstorePath();
589 else if (type
== SimpleCredentialType::SystemWincred
)
590 match
= _T("S\ncredential.helper\nwincred");
593 git_config_new(&config
);
594 CStringA projectConfigA
= CUnicodeUtils::GetUTF8(g_Git
.GetGitLocalConfig());
595 git_config_add_file_ondisk(config
, projectConfigA
.GetBuffer(), 4, FALSE
);
596 projectConfigA
.ReleaseBuffer();
597 CStringA globalConfigA
= CUnicodeUtils::GetUTF8(g_Git
.GetGitGlobalConfig());
598 git_config_add_file_ondisk(config
, globalConfigA
.GetBuffer(), 3, FALSE
);
599 globalConfigA
.ReleaseBuffer();
600 CStringA globalXDGConfigA
= CUnicodeUtils::GetUTF8(g_Git
.GetGitGlobalXDGConfig());
601 git_config_add_file_ondisk(config
, globalXDGConfigA
.GetBuffer(), 2, FALSE
);
602 globalXDGConfigA
.ReleaseBuffer();
603 CStringA systemConfigA
= CUnicodeUtils::GetUTF8(g_Git
.GetGitSystemConfig());
604 git_config_add_file_ondisk(config
, systemConfigA
.GetBuffer(), 1, FALSE
);
605 systemConfigA
.ReleaseBuffer();
608 git_config_foreach_match(config
, "credential\\..*", GetCredentialAnyEntryCallback
, &list
);
609 for (size_t i
= 0; i
< list
.size(); ++i
)
612 CString prefix
= list
[i
].Tokenize(_T("\n"), pos
);
613 if (prefix
== _T("S") && !CAppUtils::IsAdminLogin())
621 // workaround gitdll bug
622 // TODO: switch to libgit2
623 bool old
= g_Git
.m_IsUseGitDLL
;
624 g_Git
.m_IsUseGitDLL
= false;
625 for (size_t i
= 0; i
< list
.size(); ++i
)
627 if (list
[i
] != match
)
630 CString prefix
= list
[i
].Tokenize(_T("\n"), pos
);
631 CString key
= list
[i
].Tokenize(_T("\n"), pos
);
632 CONFIG_TYPE configLevel
= prefix
== _T("S") ? CONFIG_SYSTEM
: prefix
== _T("G") || prefix
== _T("X") ? CONFIG_GLOBAL
: CONFIG_LOCAL
;
633 if (g_Git
.UnsetConfigValue(key
, configLevel
, CP_UTF8
, &g_Git
.m_CurrentDir
))
636 msg
.Format(IDS_PROC_SAVECONFIGFAILED
, key
, _T(""));
637 CMessageBox::Show(NULL
, msg
, _T("TortoiseGit"), MB_OK
| MB_ICONERROR
);
643 g_Git
.m_IsUseGitDLL
= old
;
648 bool SaveSimpleCredential(int type
)
650 CONFIG_TYPE configLevel
;
652 if (type
== SimpleCredentialType::LocalWincred
)
654 configLevel
= CONFIG_LOCAL
;
655 value
= _T("wincred");
657 else if (type
== SimpleCredentialType::LocalWinstore
)
659 configLevel
= CONFIG_LOCAL
;
660 value
= GetWinstorePath();
662 else if (type
== SimpleCredentialType::GlobalWincred
)
664 configLevel
= CONFIG_GLOBAL
;
665 value
= _T("wincred");
667 else if (type
== SimpleCredentialType::GlobalWinstore
)
669 configLevel
= CONFIG_GLOBAL
;
670 value
= GetWinstorePath();
672 else if (type
== SimpleCredentialType::SystemWincred
)
674 configLevel
= CONFIG_SYSTEM
;
675 value
= _T("wincred");
682 // workaround gitdll bug
683 // TODO: switch to libgit2
684 bool old
= g_Git
.m_IsUseGitDLL
;
685 g_Git
.m_IsUseGitDLL
= false;
686 if (g_Git
.SetConfigValue(_T("credential.helper"), value
, configLevel
, CP_UTF8
, &g_Git
.m_CurrentDir
))
689 msg
.Format(IDS_PROC_SAVECONFIGFAILED
, _T("credential.helper"), value
);
690 CMessageBox::Show(NULL
, msg
, _T("TortoiseGit"), MB_OK
| MB_ICONERROR
);
693 g_Git
.m_IsUseGitDLL
= old
;
697 BOOL
CSettingGitCredential::OnApply()
702 int type
= m_ctrlSimpleCredential
.GetCurSel();
703 if (type
== SimpleCredentialType::SystemWincred
&& !CAppUtils::IsAdminLogin())
709 if (type
!= SimpleCredentialType::Advanced
)
711 if (!SaveSimpleCredential(type
))
714 if (!DeleteOtherKeys(type
))
719 return ISettingsPropPage::OnApply();
722 int sel
= m_ctrlConfigType
.GetCurSel();
723 if (sel
== ConfigType::System
&& !CAppUtils::IsAdminLogin())
730 if (m_ChangedMask
& CREDENTIAL_URL
)
733 if (m_strHelper
.IsEmpty())
735 CMessageBox::Show(NULL
, IDS_GITCREDENTIAL_HELPEREMPTY
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
738 m_strUrl
.Replace(L
'\\', L
'/');
739 m_strHelper
.Replace(L
'\\', L
'/');
741 Save(_T("helper"), m_strHelper
);
742 m_ChangedMask
&= ~CREDENTIAL_HELPER
;
744 int sel
= m_ctrlConfigType
.GetCurSel();
745 CString prefix
= sel
== ConfigType::System
? _T("S") : sel
== ConfigType::Global
? _T("G") : _T("L");
747 if (!m_strUrl
.IsEmpty())
748 text
.Format(_T("%s:%s"), prefix
, m_strUrl
);
751 int urlIndex
= m_ctrlUrlList
.AddString(text
);
752 m_ctrlUrlList
.SetCurSel(urlIndex
);
753 GetDlgItem(IDC_BUTTON_ADD
)->EnableWindow(TRUE
);
756 if (m_ChangedMask
& CREDENTIAL_HELPER
)
758 m_strHelper
.Replace(L
'\\', L
'/');
759 Save(_T("helper"), m_strHelper
);
762 if (m_ChangedMask
& CREDENTIAL_USERNAME
)
763 Save(_T("username"), m_strUsername
);
765 if (m_ChangedMask
& CREDENTIAL_USEHTTPPATH
)
766 Save(_T("useHttpPath"), m_bUseHttpPath
? _T("true") : _T(""));
771 return ISettingsPropPage::OnApply();
774 void CSettingGitCredential::OnBnClickedButtonRemove()
776 int index
= m_ctrlUrlList
.GetCurSel();
780 m_ctrlUrlList
.GetText(index
, str
);
782 msg
.Format(IDS_GITCREDENTIAL_DELETEHELPER
, str
);
783 if (CMessageBox::Show(NULL
, msg
, _T("TortoiseGit"), MB_YESNO
| MB_ICONQUESTION
) == IDYES
)
786 git_config_new(&config
);
787 int pos
= str
.Find(_T(':'));
788 CString prefix
= pos
>= 0 ? str
.Left(pos
) : str
;
789 CString url
= pos
>= 0 ? str
.Mid(pos
+ 1) : _T("");
790 CONFIG_TYPE configLevel
= CONFIG_LOCAL
;
795 configLevel
= CONFIG_LOCAL
;
796 CStringA projectConfigA
= CUnicodeUtils::GetUTF8(g_Git
.GetGitLocalConfig());
797 git_config_add_file_ondisk(config
, projectConfigA
.GetBuffer(), 1, FALSE
);
798 projectConfigA
.ReleaseBuffer();
804 configLevel
= CONFIG_GLOBAL
;
805 CStringA globalConfigA
= CUnicodeUtils::GetUTF8(g_Git
.GetGitGlobalConfig());
806 git_config_add_file_ondisk(config
, globalConfigA
.GetBuffer(), 2, FALSE
);
807 globalConfigA
.ReleaseBuffer();
808 CStringA globalXDGConfigA
= CUnicodeUtils::GetUTF8(g_Git
.GetGitGlobalXDGConfig());
809 git_config_add_file_ondisk(config
, globalXDGConfigA
.GetBuffer(), 1, FALSE
);
810 globalXDGConfigA
.ReleaseBuffer();
815 if (!CAppUtils::IsAdminLogin())
821 configLevel
= CONFIG_SYSTEM
;
822 CStringA systemConfigA
= CUnicodeUtils::GetUTF8(g_Git
.GetGitSystemConfig());
823 git_config_add_file_ondisk(config
, systemConfigA
.GetBuffer(), 1, FALSE
);
824 systemConfigA
.ReleaseBuffer();
830 CStringA urlA
= CUnicodeUtils::GetUTF8(url
);
831 CStringA pattern
= urlA
.IsEmpty() ? "^credential\\.[^.]+$" : ("credential\\." + RegexEscape(urlA
) + "\\..*");
832 git_config_foreach_match(config
, pattern
, GetCredentialEntryCallback
, &list
);
833 for (size_t i
= 0; i
< list
.size(); ++i
)
834 g_Git
.UnsetConfigValue(list
[i
], configLevel
, CP_UTF8
, &g_Git
.m_CurrentDir
);
836 m_ctrlUrlList
.DeleteString(index
);
837 OnLbnSelchangeListUrl();