1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9 #include "GUIDialogNumeric.h"
10
11 #include "ServiceBroker.h"
12 #include "guilib/GUIComponent.h"
13 #include "guilib/GUILabelControl.h"
14 #include "guilib/GUIWindowManager.h"
15 #include "guilib/LocalizeStrings.h"
16 #include "input/Key.h"
17 #include "input/XBMC_vkeys.h"
18 #include "interfaces/AnnouncementManager.h"
19 #include "messaging/helpers/DialogOKHelper.h"
20 #include "utils/Digest.h"
21 #include "utils/StringUtils.h"
22 #include "utils/Variant.h"
23
24 #include <cassert>
25
26 #define CONTROL_HEADING_LABEL 1
27 #define CONTROL_INPUT_LABEL 4
28 #define CONTROL_NUM0 10
29 #define CONTROL_NUM9 19
30 #define CONTROL_PREVIOUS 20
31 #define CONTROL_ENTER 21
32 #define CONTROL_NEXT 22
33 #define CONTROL_BACKSPACE 23
34
35 using namespace KODI::MESSAGING;
36 using KODI::UTILITY::CDigest;
37
CGUIDialogNumeric(void)38 CGUIDialogNumeric::CGUIDialogNumeric(void)
39 : CGUIDialog(WINDOW_DIALOG_NUMERIC, "DialogNumeric.xml")
40 , m_bConfirmed{false}
41 , m_bCanceled{false}
42 , m_mode{INPUT_PASSWORD}
43 , m_block{0}
44 , m_lastblock{0}
45 , m_dirty{false}
46 {
47 memset(&m_datetime, 0, sizeof(KODI::TIME::SystemTime));
48 m_loadType = KEEP_IN_MEMORY;
49 }
50
51 CGUIDialogNumeric::~CGUIDialogNumeric(void) = default;
52
OnInitWindow()53 void CGUIDialogNumeric::OnInitWindow()
54 {
55 CGUIDialog::OnInitWindow();
56
57 CVariant data;
58 switch (m_mode)
59 {
60 case INPUT_TIME:
61 data["type"] = "time";
62 break;
63 case INPUT_DATE:
64 data["type"] = "date";
65 break;
66 case INPUT_IP_ADDRESS:
67 data["type"] = "ip";
68 break;
69 case INPUT_PASSWORD:
70 data["type"] = "numericpassword";
71 break;
72 case INPUT_NUMBER:
73 data["type"] = "number";
74 break;
75 case INPUT_TIME_SECONDS:
76 data["type"] = "seconds";
77 break;
78 default:
79 data["type"] = "keyboard";
80 break;
81 }
82
83 const CGUIControl *control = GetControl(CONTROL_HEADING_LABEL);
84 if (control != nullptr)
85 data["title"] = control->GetDescription();
86
87 data["value"] = GetOutputString();
88
89 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Input, "OnInputRequested", data);
90 }
91
OnDeinitWindow(int nextWindowID)92 void CGUIDialogNumeric::OnDeinitWindow(int nextWindowID)
93 {
94 // call base class
95 CGUIDialog::OnDeinitWindow(nextWindowID);
96
97 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Input, "OnInputFinished");
98 }
99
OnAction(const CAction & action)100 bool CGUIDialogNumeric::OnAction(const CAction &action)
101 {
102 if (action.GetID() == ACTION_NEXT_ITEM)
103 OnNext();
104 else if (action.GetID() == ACTION_PREV_ITEM)
105 OnPrevious();
106 else if (action.GetID() == ACTION_BACKSPACE)
107 OnBackSpace();
108 else if (action.GetID() == ACTION_ENTER)
109 OnOK();
110 else if (action.GetID() >= REMOTE_0 && action.GetID() <= REMOTE_9)
111 OnNumber(action.GetID() - REMOTE_0);
112 else if (action.GetID() >= KEY_VKEY && action.GetID() < KEY_UNICODE)
113 {
114 // input from the keyboard (vkey, not ascii)
115 uint8_t b = action.GetID() & 0xFF;
116 if (b == XBMCVK_LEFT)
117 OnPrevious();
118 else if (b == XBMCVK_RIGHT)
119 OnNext();
120 else if (b == XBMCVK_RETURN || b == XBMCVK_NUMPADENTER)
121 OnOK();
122 else if (b == XBMCVK_BACK)
123 OnBackSpace();
124 else if (b == XBMCVK_ESCAPE)
125 OnCancel();
126 }
127 else if (action.GetID() == KEY_UNICODE)
128 { // input from the keyboard
129 if (action.GetUnicode() == 10 || action.GetUnicode() == 13)
130 OnOK(); // enter
131 else if (action.GetUnicode() == 8)
132 OnBackSpace(); // backspace
133 else if (action.GetUnicode() == 27)
134 OnCancel(); // escape
135 else if (action.GetUnicode() == 46)
136 OnNext(); // '.'
137 else if (action.GetUnicode() >= 48 && action.GetUnicode() < 58) // number
138 OnNumber(action.GetUnicode() - 48);
139 }
140 else
141 return CGUIDialog::OnAction(action);
142
143 return true;
144 }
145
OnBack(int actionID)146 bool CGUIDialogNumeric::OnBack(int actionID)
147 {
148 OnCancel();
149 return true;
150 }
151
OnMessage(CGUIMessage & message)152 bool CGUIDialogNumeric::OnMessage(CGUIMessage& message)
153 {
154 switch ( message.GetMessage() )
155 {
156 case GUI_MSG_WINDOW_INIT:
157 {
158 m_bConfirmed = false;
159 m_bCanceled = false;
160 m_dirty = false;
161 return CGUIDialog::OnMessage(message);
162 }
163 break;
164
165 case GUI_MSG_CLICKED:
166 {
167 int iControl = message.GetSenderId();
168 m_bConfirmed = false;
169 m_bCanceled = false;
170 if (CONTROL_NUM0 <= iControl && iControl <= CONTROL_NUM9) // User numeric entry via dialog button UI
171 {
172 OnNumber(iControl - 10);
173 return true;
174 }
175 else if (iControl == CONTROL_PREVIOUS)
176 {
177 OnPrevious();
178 return true;
179 }
180 else if (iControl == CONTROL_NEXT)
181 {
182 OnNext();
183 return true;
184 }
185 else if (iControl == CONTROL_BACKSPACE)
186 {
187 OnBackSpace();
188 return true;
189 }
190 else if (iControl == CONTROL_ENTER)
191 {
192 OnOK();
193 return true;
194 }
195 }
196 break;
197
198 case GUI_MSG_SET_TEXT:
199 SetMode(m_mode, message.GetLabel());
200
201 // close the dialog if requested
202 if (message.GetParam1() > 0)
203 OnOK();
204 break;
205 }
206 return CGUIDialog::OnMessage(message);
207 }
208
OnBackSpace()209 void CGUIDialogNumeric::OnBackSpace()
210 {
211 if (!m_dirty && m_block)
212 {
213 --m_block;
214 return;
215 }
216 if (m_mode == INPUT_NUMBER || m_mode == INPUT_PASSWORD)
217 { // just go back one character
218 if (!m_number.empty())
219 m_number.erase(m_number.length() - 1);
220 }
221 else if (m_mode == INPUT_IP_ADDRESS)
222 {
223 if (m_ip[m_block])
224 m_ip[m_block] /= 10;
225 else if (m_block)
226 {
227 --m_block;
228 m_dirty = false;
229 }
230 }
231 else if (m_mode == INPUT_TIME)
232 {
233 if (m_block == 0)
234 m_datetime.hour /= 10;
235 else if (m_datetime.minute)
236 m_datetime.minute /= 10;
237 else
238 {
239 m_block = 0;
240 m_dirty = false;
241 }
242 }
243 else if (m_mode == INPUT_TIME_SECONDS)
244 {
245 if (m_block == 0)
246 m_datetime.hour /= 10;
247 else if (m_block == 1)
248 {
249 if (m_datetime.minute)
250 m_datetime.minute /= 10;
251 else
252 {
253 m_block = 0;
254 m_dirty = false;
255 }
256 }
257 else if (m_datetime.second)
258 m_datetime.minute /= 10;
259 else
260 {
261 m_block = 0;
262 m_dirty = false;
263 }
264 }
265 else if (m_mode == INPUT_DATE)
266 {
267 if (m_block == 0)
268 m_datetime.day /= 10;
269 else if (m_block == 1)
270 {
271 if (m_datetime.month)
272 m_datetime.month /= 10;
273 else
274 {
275 m_block = 0;
276 m_dirty = false;
277 }
278 }
279 else if (m_datetime.year) // m_block == 2
280 m_datetime.year /= 10;
281 else
282 {
283 m_block = 1;
284 m_dirty = false;
285 }
286 }
287 }
288
OnPrevious()289 void CGUIDialogNumeric::OnPrevious()
290 {
291 if (m_block)
292 m_block--;
293 m_dirty = false;
294 }
295
OnNext()296 void CGUIDialogNumeric::OnNext()
297 {
298 if (m_mode == INPUT_IP_ADDRESS && m_block==0 && m_ip[0]==0)
299 return;
300
301 if (m_block < m_lastblock)
302 m_block++;
303 m_dirty = false;
304 if (m_mode == INPUT_DATE)
305 VerifyDate(m_block == 2);
306 }
307
FrameMove()308 void CGUIDialogNumeric::FrameMove()
309 {
310 std::string strLabel;
311 unsigned int start = 0;
312 unsigned int end = 0;
313 if (m_mode == INPUT_PASSWORD)
314 strLabel.assign(m_number.length(), '*');
315 else if (m_mode == INPUT_NUMBER)
316 strLabel = m_number;
317 else if (m_mode == INPUT_TIME)
318 { // format up the time
319 strLabel = StringUtils::Format("%2d:%02d", m_datetime.hour, m_datetime.minute);
320 start = m_block * 3;
321 end = m_block * 3 + 2;
322 }
323 else if (m_mode == INPUT_TIME_SECONDS)
324 { // format up the time
325 strLabel =
326 StringUtils::Format("%2d:%02d:%02d", m_datetime.hour, m_datetime.minute, m_datetime.second);
327 start = m_block * 3;
328 end = m_block * 3 + 2;
329 }
330 else if (m_mode == INPUT_DATE)
331 { // format up the date
332 strLabel =
333 StringUtils::Format("%2d/%2d/%4d", m_datetime.day, m_datetime.month, m_datetime.year);
334 start = m_block * 3;
335 end = m_block * 3 + 2;
336 if (m_block == 2)
337 end = m_block * 3 + 4;
338 }
339 else if (m_mode == INPUT_IP_ADDRESS)
340 { // format up the date
341 strLabel = StringUtils::Format("%3d.%3d.%3d.%3d", m_ip[0], m_ip[1], m_ip[2], m_ip[3]);
342 start = m_block * 4;
343 end = m_block * 4 + 3;
344 }
345 CGUILabelControl *pLabel = dynamic_cast<CGUILabelControl *>(GetControl(CONTROL_INPUT_LABEL));
346 if (pLabel)
347 {
348 pLabel->SetLabel(strLabel);
349 pLabel->SetHighlight(start, end);
350 }
351 CGUIDialog::FrameMove();
352 }
353
OnNumber(uint32_t num)354 void CGUIDialogNumeric::OnNumber(uint32_t num)
355 {
356 ResetAutoClose();
357
358 switch (m_mode)
359 {
360 case INPUT_NUMBER:
361 case INPUT_PASSWORD:
362 m_number += num + '0';
363 break;
364 case INPUT_TIME:
365 HandleInputTime(num);
366 break;
367 case INPUT_TIME_SECONDS:
368 HandleInputSeconds(num);
369 break;
370 case INPUT_DATE:
371 HandleInputDate(num);
372 break;
373 case INPUT_IP_ADDRESS:
374 HandleInputIP(num);
375 break;
376 }
377 }
378
SetMode(INPUT_MODE mode,const KODI::TIME::SystemTime & initial)379 void CGUIDialogNumeric::SetMode(INPUT_MODE mode, const KODI::TIME::SystemTime& initial)
380 {
381 m_mode = mode;
382 m_block = 0;
383 m_lastblock = 0;
384 if (m_mode == INPUT_TIME || m_mode == INPUT_TIME_SECONDS || m_mode == INPUT_DATE)
385 {
386 m_datetime = initial;
387 m_lastblock = (m_mode != INPUT_TIME) ? 2 : 1;
388 }
389 }
390
SetMode(INPUT_MODE mode,const std::string & initial)391 void CGUIDialogNumeric::SetMode(INPUT_MODE mode, const std::string &initial)
392 {
393 m_mode = mode;
394 m_block = 0;
395 m_lastblock = 0;
396 if (m_mode == INPUT_TIME || m_mode == INPUT_TIME_SECONDS || m_mode == INPUT_DATE)
397 {
398 CDateTime dateTime;
399 if (m_mode == INPUT_TIME || m_mode == INPUT_TIME_SECONDS)
400 {
401 // check if we have a pure number
402 if (initial.find_first_not_of("0123456789") == std::string::npos)
403 {
404 long seconds = strtol(initial.c_str(), nullptr, 10);
405 dateTime = seconds;
406 }
407 else
408 {
409 std::string tmp = initial;
410 // if we are handling seconds and if the string only contains
411 // "mm:ss" we need to add dummy "hh:" to get "hh:mm:ss"
412 if (m_mode == INPUT_TIME_SECONDS && tmp.length() <= 5)
413 tmp = "00:" + tmp;
414 dateTime.SetFromDBTime(tmp);
415 }
416 }
417 else if (m_mode == INPUT_DATE)
418 {
419 std::string tmp = initial;
420 StringUtils::Replace(tmp, '/', '.');
421 dateTime.SetFromDBDate(tmp);
422 }
423
424 if (!dateTime.IsValid())
425 return;
426
427 dateTime.GetAsSystemTime(m_datetime);
428 m_lastblock = (m_mode == INPUT_DATE) ? 2 : 1;
429 }
430 else if (m_mode == INPUT_IP_ADDRESS)
431 {
432 m_lastblock = 3;
433 auto blocks = StringUtils::Split(initial, '.');
434 if (blocks.size() != 4)
435 return;
436
437 for (size_t i = 0; i < blocks.size(); ++i)
438 {
439 if (blocks[i].length() > 3)
440 return;
441
442 m_ip[i] = static_cast<uint8_t>(atoi(blocks[i].c_str()));
443 }
444 }
445 else if (m_mode == INPUT_NUMBER || m_mode == INPUT_PASSWORD)
446 m_number = initial;
447 }
448
GetOutput() const449 KODI::TIME::SystemTime CGUIDialogNumeric::GetOutput() const
450 {
451 assert(m_mode == INPUT_TIME || m_mode == INPUT_TIME_SECONDS || m_mode == INPUT_DATE);
452 return m_datetime;
453 }
454
GetOutputString() const455 std::string CGUIDialogNumeric::GetOutputString() const
456 {
457 switch (m_mode)
458 {
459 case INPUT_DATE:
460 return StringUtils::Format("%02i/%02i/%04i", m_datetime.day, m_datetime.month, m_datetime.year);
461 case INPUT_TIME:
462 return StringUtils::Format("%i:%02i", m_datetime.hour, m_datetime.minute);
463 case INPUT_TIME_SECONDS:
464 return StringUtils::Format("%i:%02i:%02i", m_datetime.hour, m_datetime.minute,
465 m_datetime.second);
466 case INPUT_IP_ADDRESS:
467 return StringUtils::Format("%d.%d.%d.%d", m_ip[0], m_ip[1], m_ip[2], m_ip[3]);
468 case INPUT_NUMBER:
469 case INPUT_PASSWORD:
470 return m_number;
471 }
472
473 //should never get here
474 return std::string();
475 }
476
ShowAndGetSeconds(std::string & timeString,const std::string & heading)477 bool CGUIDialogNumeric::ShowAndGetSeconds(std::string &timeString, const std::string &heading)
478 {
479 CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC);
480 if (!pDialog) return false;
481 int seconds = StringUtils::TimeStringToSeconds(timeString);
482 KODI::TIME::SystemTime time = {0};
483 time.hour = seconds / 3600;
484 time.minute = (seconds - time.hour * 3600) / 60;
485 time.second = seconds - time.hour * 3600 - time.minute * 60;
486 pDialog->SetMode(INPUT_TIME_SECONDS, time);
487 pDialog->SetHeading(heading);
488 pDialog->Open();
489 if (!pDialog->IsConfirmed() || pDialog->IsCanceled())
490 return false;
491 time = pDialog->GetOutput();
492 seconds = time.hour * 3600 + time.minute * 60 + time.second;
493 timeString = StringUtils::SecondsToTimeString(seconds);
494 return true;
495 }
496
ShowAndGetTime(KODI::TIME::SystemTime & time,const std::string & heading)497 bool CGUIDialogNumeric::ShowAndGetTime(KODI::TIME::SystemTime& time, const std::string& heading)
498 {
499 CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC);
500 if (!pDialog) return false;
501 pDialog->SetMode(INPUT_TIME, time);
502 pDialog->SetHeading(heading);
503 pDialog->Open();
504 if (!pDialog->IsConfirmed() || pDialog->IsCanceled())
505 return false;
506 time = pDialog->GetOutput();
507 return true;
508 }
509
ShowAndGetDate(KODI::TIME::SystemTime & date,const std::string & heading)510 bool CGUIDialogNumeric::ShowAndGetDate(KODI::TIME::SystemTime& date, const std::string& heading)
511 {
512 CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC);
513 if (!pDialog) return false;
514 pDialog->SetMode(INPUT_DATE, date);
515 pDialog->SetHeading(heading);
516 pDialog->Open();
517 if (!pDialog->IsConfirmed() || pDialog->IsCanceled())
518 return false;
519 date = pDialog->GetOutput();
520 return true;
521 }
522
ShowAndGetIPAddress(std::string & IPAddress,const std::string & heading)523 bool CGUIDialogNumeric::ShowAndGetIPAddress(std::string &IPAddress, const std::string &heading)
524 {
525 CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC);
526 if (!pDialog) return false;
527 pDialog->SetMode(INPUT_IP_ADDRESS, IPAddress);
528 pDialog->SetHeading(heading);
529 pDialog->Open();
530 if (!pDialog->IsConfirmed() || pDialog->IsCanceled())
531 return false;
532 IPAddress = pDialog->GetOutputString();
533 return true;
534 }
535
ShowAndGetNumber(std::string & strInput,const std::string & strHeading,unsigned int iAutoCloseTimeoutMs,bool bSetHidden)536 bool CGUIDialogNumeric::ShowAndGetNumber(std::string& strInput, const std::string &strHeading, unsigned int iAutoCloseTimeoutMs /* = 0 */, bool bSetHidden /* = false */)
537 {
538 // Prompt user for password input
539 CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC);
540 pDialog->SetHeading( strHeading );
541
542 if (bSetHidden)
543 pDialog->SetMode(INPUT_PASSWORD, strInput);
544 else
545 pDialog->SetMode(INPUT_NUMBER, strInput);
546 if (iAutoCloseTimeoutMs)
547 pDialog->SetAutoClose(iAutoCloseTimeoutMs);
548
549 pDialog->Open();
550
551 if (!pDialog->IsAutoClosed() && (!pDialog->IsConfirmed() || pDialog->IsCanceled()))
552 return false;
553 strInput = pDialog->GetOutputString();
554 return true;
555 }
556
557 // \brief Show numeric keypad twice to get and confirm a user-entered password string.
558 // \param strNewPassword String to preload into the keyboard accumulator. Overwritten with user input if return=true.
559 // \return true if successful display and user input entry/re-entry. false if unsuccessful display, no user input, or canceled editing.
ShowAndVerifyNewPassword(std::string & strNewPassword)560 bool CGUIDialogNumeric::ShowAndVerifyNewPassword(std::string& strNewPassword)
561 {
562 // Prompt user for password input
563 std::string strUserInput;
564 InputVerificationResult ret = ShowAndVerifyInput(strUserInput, g_localizeStrings.Get(12340), false);
565 if (ret != InputVerificationResult::SUCCESS)
566 {
567 if (ret == InputVerificationResult::FAILED)
568 {
569 // Show error to user saying the password entry was blank
570 HELPERS::ShowOKDialogText(CVariant{12357}, CVariant{12358}); // Password is empty/blank
571 }
572 return false;
573 }
574
575 if (strUserInput.empty())
576 // user canceled out
577 return false;
578
579 // Prompt again for password input, this time sending previous input as the password to verify
580 ret = ShowAndVerifyInput(strUserInput, g_localizeStrings.Get(12341), true);
581 if (ret != InputVerificationResult::SUCCESS)
582 {
583 if (ret == InputVerificationResult::FAILED)
584 {
585 // Show error to user saying the password re-entry failed
586 HELPERS::ShowOKDialogText(CVariant{12357}, CVariant{12344}); // Password do not match
587 }
588 return false;
589 }
590
591 // password entry and re-entry succeeded
592 strNewPassword = strUserInput;
593 return true;
594 }
595
596 // \brief Show numeric keypad and verify user input against strPassword.
597 // \param strPassword Value to compare against user input.
598 // \param strHeading String shown on dialog title. Converts to localized string if contains a positive integer.
599 // \param iRetries If greater than 0, shows "Incorrect password, %d retries left" on dialog line 2, else line 2 is blank.
600 // \return 0 if successful display and user input. 1 if unsuccessful input. -1 if no user input or canceled editing.
ShowAndVerifyPassword(std::string & strPassword,const std::string & strHeading,int iRetries)601 int CGUIDialogNumeric::ShowAndVerifyPassword(std::string& strPassword, const std::string& strHeading, int iRetries)
602 {
603 std::string strTempHeading = strHeading;
604 if (iRetries > 0)
605 {
606 // Show a string telling user they have iRetries retries left
607 strTempHeading = StringUtils::Format("%s. %s %i %s", strHeading.c_str(), g_localizeStrings.Get(12342).c_str(), iRetries, g_localizeStrings.Get(12343).c_str());
608 }
609
610 // make a copy of strPassword to prevent from overwriting it later
611 std::string strPassTemp = strPassword;
612 InputVerificationResult ret = ShowAndVerifyInput(strPassTemp, strTempHeading, true);
613 if (ret == InputVerificationResult::SUCCESS)
614 return 0; // user entered correct password
615
616 if (ret == InputVerificationResult::CANCELED)
617 return -1; // user canceled out
618
619 return 1; // user must have entered an incorrect password
620 }
621
622 // \brief Show numeric keypad and verify user input against strToVerify.
623 // \param strToVerify Value to compare against user input.
624 // \param dlgHeading String shown on dialog title.
625 // \param bVerifyInput If set as true we verify the users input versus strToVerify.
626 // \return the result of the check (success, failed, or canceled by user).
ShowAndVerifyInput(std::string & strToVerify,const std::string & dlgHeading,bool bVerifyInput)627 InputVerificationResult CGUIDialogNumeric::ShowAndVerifyInput(std::string& strToVerify, const std::string& dlgHeading, bool bVerifyInput)
628 {
629 // Prompt user for password input
630 CGUIDialogNumeric *pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogNumeric>(WINDOW_DIALOG_NUMERIC);
631 pDialog->SetHeading(dlgHeading);
632
633 std::string strInput;
634 if (!bVerifyInput)
635 strInput = strToVerify;
636
637 pDialog->SetMode(INPUT_PASSWORD, strInput);
638 pDialog->Open();
639
640 strInput = pDialog->GetOutputString();
641
642 if (!pDialog->IsConfirmed() || pDialog->IsCanceled())
643 {
644 // user canceled out
645 strToVerify = "";
646 return InputVerificationResult::CANCELED;
647 }
648
649 const std::string md5pword2 = CDigest::Calculate(CDigest::Type::MD5, strInput);
650
651 if (!bVerifyInput)
652 {
653 strToVerify = md5pword2;
654 return InputVerificationResult::SUCCESS;
655 }
656
657 return StringUtils::EqualsNoCase(strToVerify, md5pword2) ? InputVerificationResult::SUCCESS : InputVerificationResult::FAILED;
658 }
659
IsConfirmed() const660 bool CGUIDialogNumeric::IsConfirmed() const
661 {
662 return m_bConfirmed;
663 }
664
IsCanceled() const665 bool CGUIDialogNumeric::IsCanceled() const
666 {
667 return m_bCanceled;
668 }
669
SetHeading(const std::string & strHeading)670 void CGUIDialogNumeric::SetHeading(const std::string& strHeading)
671 {
672 Initialize();
673 CGUIMessage msg(GUI_MSG_LABEL_SET, GetID(), CONTROL_HEADING_LABEL);
674 msg.SetLabel(strHeading);
675 OnMessage(msg);
676 }
677
VerifyDate(bool checkYear)678 void CGUIDialogNumeric::VerifyDate(bool checkYear)
679 {
680 if (m_datetime.day == 0)
681 m_datetime.day = 1;
682 if (m_datetime.month == 0)
683 m_datetime.month = 1;
684 // check for number of days in the month
685 if (m_datetime.day == 31)
686 {
687 if (m_datetime.month == 4 || m_datetime.month == 6 || m_datetime.month == 9 ||
688 m_datetime.month == 11)
689 m_datetime.day = 30;
690 }
691 if (m_datetime.month == 2 && m_datetime.day > 28)
692 {
693 m_datetime.day = 29; // max in february.
694 if (checkYear)
695 {
696 // leap years occur when the year is divisible by 4 but not by 100, or the year is divisible by 400
697 // thus they don't occur, if the year has a remainder when divided by 4, or when the year is divisible by 100 but not by 400
698 if ((m_datetime.year % 4) || (!(m_datetime.year % 100) && (m_datetime.year % 400)))
699 m_datetime.day = 28;
700 }
701 }
702 }
703
OnOK()704 void CGUIDialogNumeric::OnOK()
705 {
706 m_bConfirmed = true;
707 m_bCanceled = false;
708 Close();
709 }
710
OnCancel()711 void CGUIDialogNumeric::OnCancel()
712 {
713 m_bConfirmed = false;
714 m_bCanceled = true;
715 Close();
716 }
717
HandleInputIP(uint32_t num)718 void CGUIDialogNumeric::HandleInputIP(uint32_t num)
719 {
720 if (m_dirty && ((m_ip[m_block] < 25) || (m_ip[m_block] == 25 && num < 6) || !(m_block == 0 && num == 0)))
721 {
722 m_ip[m_block] *= 10;
723 m_ip[m_block] += num;
724 }
725 else
726 m_ip[m_block] = num;
727
728 if (m_ip[m_block] > 25 || (m_ip[m_block] == 0 && num == 0))
729 {
730 ++m_block;
731 if (m_block > 3)
732 m_block = 0;
733 m_dirty = false;
734 }
735 else
736 m_dirty = true;
737 }
738
HandleInputDate(uint32_t num)739 void CGUIDialogNumeric::HandleInputDate(uint32_t num)
740 {
741 if (m_block == 0) // day of month
742 {
743 if (m_dirty && (m_datetime.day < 3 || num < 2))
744 {
745 m_datetime.day *= 10;
746 m_datetime.day += num;
747 }
748 else
749 m_datetime.day = num;
750
751 if (m_datetime.day > 3)
752 {
753 m_block = 1; // move to months
754 m_dirty = false;
755 }
756 else
757 m_dirty = true;
758 }
759 else if (m_block == 1) // months
760 {
761 if (m_dirty && num < 3)
762 {
763 m_datetime.month *= 10;
764 m_datetime.month += num;
765 }
766 else
767 m_datetime.month = num;
768
769 if (m_datetime.month > 1)
770 {
771 VerifyDate(false);
772 m_block = 2; // move to year
773 m_dirty = false;
774 }
775 else
776 m_dirty = true;
777 }
778 else // year
779 {
780 if (m_dirty && m_datetime.year < 1000) // have taken input
781 {
782 m_datetime.year *= 10;
783 m_datetime.year += num;
784 }
785 else
786 m_datetime.year = num;
787
788 if (m_datetime.year > 1000)
789 {
790 VerifyDate(true);
791 m_block = 0; // move to day of month
792 m_dirty = false;
793 }
794 else
795 m_dirty = true;
796 }
797 }
798
HandleInputSeconds(uint32_t num)799 void CGUIDialogNumeric::HandleInputSeconds(uint32_t num)
800 {
801 if (m_block == 0) // hour
802 {
803 if (m_dirty) // have input the first digit
804 {
805 m_datetime.hour *= 10;
806 m_datetime.hour += num;
807 m_block = 1; // move to minutes - allows up to 99 hours
808 m_dirty = false;
809 }
810 else // this is the first digit
811 {
812 m_datetime.hour = num;
813 m_dirty = true;
814 }
815 }
816 else if (m_block == 1) // minute
817 {
818 if (m_dirty) // have input the first digit
819 {
820 m_datetime.minute *= 10;
821 m_datetime.minute += num;
822 m_block = 2; // move to seconds - allows up to 99 minutes
823 m_dirty = false;
824 }
825 else // this is the first digit
826 {
827 m_datetime.minute = num;
828 if (num > 5)
829 {
830 m_block = 2; // move to seconds
831 m_dirty = false;
832 }
833 else
834 m_dirty = true;
835 }
836 }
837 else // seconds
838 {
839 if (m_dirty) // have input the first digit
840 {
841 m_datetime.second *= 10;
842 m_datetime.second += num;
843 m_block = 0; // move to hours
844 m_dirty = false;
845 }
846 else // this is the first digit
847 {
848 m_datetime.second = num;
849 if (num > 5)
850 {
851 m_block = 0; // move to hours
852 m_dirty = false;
853 }
854 else
855 m_dirty = true;
856 }
857 }
858 }
859
HandleInputTime(uint32_t num)860 void CGUIDialogNumeric::HandleInputTime(uint32_t num)
861 {
862 if (m_block == 0) // hour
863 {
864 if (m_dirty) // have input the first digit
865 {
866 if (m_datetime.hour < 2 || num < 4)
867 {
868 m_datetime.hour *= 10;
869 m_datetime.hour += num;
870 }
871 else
872 m_datetime.hour = num;
873
874 m_block = 1; // move to minutes
875 m_dirty = false;
876 }
877 else // this is the first digit
878 {
879 m_datetime.hour = num;
880
881 if (num > 2)
882 {
883 m_block = 1; // move to minutes
884 m_dirty = false;
885 }
886 else
887 m_dirty = true;
888 }
889 }
890 else // minute
891 {
892 if (m_dirty) // have input the first digit
893 {
894 m_datetime.minute *= 10;
895 m_datetime.minute += num;
896 m_block = 0; // move to hours
897 m_dirty = false;
898 }
899 else // this is the first digit
900 {
901 m_datetime.minute = num;
902
903 if (num > 5)
904 {
905 m_block = 0; // move to hours
906 m_dirty = false;
907 }
908 else
909 m_dirty = true;
910 }
911 }
912 }
913
914