Merge bitcoin v0.4.0 into ppcoin
[novacoin.git] / src / ui.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2011 The Bitcoin developers
3 // Copyright (c) 2011 The PPCoin developers
4 // Distributed under the MIT/X11 software license, see the accompanying
5 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
6
7 #include "headers.h"
8 #include "db.h"
9 #include "init.h"
10 #include "strlcpy.h"
11 #include <boost/filesystem/fstream.hpp>
12 #include <boost/filesystem/convenience.hpp>
13 #ifdef _MSC_VER
14 #include <crtdbg.h>
15 #endif
16
17 using namespace std;
18 using namespace boost;
19
20
21 DEFINE_EVENT_TYPE(wxEVT_UITHREADCALL)
22
23 CMainFrame* pframeMain = NULL;
24 CMyTaskBarIcon* ptaskbaricon = NULL;
25 bool fClosedToTray = false;
26 wxLocale g_locale;
27
28 #ifdef __WXMSW__
29 double nScaleX = 1.0;
30 double nScaleY = 1.0;
31 #else
32 static const double nScaleX = 1.0;
33 static const double nScaleY = 1.0;
34 #endif
35
36
37
38
39
40
41
42
43 //////////////////////////////////////////////////////////////////////////////
44 //
45 // Util
46 //
47
48 void HandleCtrlA(wxKeyEvent& event)
49 {
50     // Ctrl-a select all
51     event.Skip();
52     wxTextCtrl* textCtrl = (wxTextCtrl*)event.GetEventObject();
53     if (event.GetModifiers() == wxMOD_CONTROL && event.GetKeyCode() == 'A')
54         textCtrl->SetSelection(-1, -1);
55 }
56
57 bool Is24HourTime()
58 {
59     //char pszHourFormat[256];
60     //pszHourFormat[0] = '\0';
61     //GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, pszHourFormat, 256);
62     //return (pszHourFormat[0] != '0');
63     return true;
64 }
65
66 string DateStr(int64 nTime)
67 {
68     // Can only be used safely here in the UI
69     return (string)wxDateTime((time_t)nTime).FormatDate();
70 }
71
72 string DateTimeStr(int64 nTime)
73 {
74     // Can only be used safely here in the UI
75     wxDateTime datetime((time_t)nTime);
76     if (Is24HourTime())
77         return (string)datetime.Format("%x %H:%M");
78     else
79         return (string)datetime.Format("%x ") + itostr((datetime.GetHour() + 11) % 12 + 1) + (string)datetime.Format(":%M %p");
80 }
81
82 wxString GetItemText(wxListCtrl* listCtrl, int nIndex, int nColumn)
83 {
84     // Helper to simplify access to listctrl
85     wxListItem item;
86     item.m_itemId = nIndex;
87     item.m_col = nColumn;
88     item.m_mask = wxLIST_MASK_TEXT;
89     if (!listCtrl->GetItem(item))
90         return "";
91     return item.GetText();
92 }
93
94 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1)
95 {
96     int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
97     listCtrl->SetItem(nIndex, 1, str1);
98     return nIndex;
99 }
100
101 int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
102 {
103     int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
104     listCtrl->SetItem(nIndex, 1, str1);
105     listCtrl->SetItem(nIndex, 2, str2);
106     listCtrl->SetItem(nIndex, 3, str3);
107     listCtrl->SetItem(nIndex, 4, str4);
108     return nIndex;
109 }
110
111 int InsertLine(wxListCtrl* listCtrl, void* pdata, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
112 {
113     int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
114     listCtrl->SetItemPtrData(nIndex, (wxUIntPtr)pdata);
115     listCtrl->SetItem(nIndex, 1, str1);
116     listCtrl->SetItem(nIndex, 2, str2);
117     listCtrl->SetItem(nIndex, 3, str3);
118     listCtrl->SetItem(nIndex, 4, str4);
119     return nIndex;
120 }
121
122 void SetItemTextColour(wxListCtrl* listCtrl, int nIndex, const wxColour& colour)
123 {
124     // Repaint on Windows is more flickery if the colour has ever been set,
125     // so don't want to set it unless it's different.  Default colour has
126     // alpha 0 transparent, so our colours don't match using operator==.
127     wxColour c1 = listCtrl->GetItemTextColour(nIndex);
128     if (!c1.IsOk())
129         c1 = wxColour(0,0,0);
130     if (colour.Red() != c1.Red() || colour.Green() != c1.Green() || colour.Blue() != c1.Blue())
131         listCtrl->SetItemTextColour(nIndex, colour);
132 }
133
134 void SetSelection(wxListCtrl* listCtrl, int nIndex)
135 {
136     int nSize = listCtrl->GetItemCount();
137     long nState = (wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
138     for (int i = 0; i < nSize; i++)
139         listCtrl->SetItemState(i, (i == nIndex ? nState : 0), nState);
140 }
141
142 int GetSelection(wxListCtrl* listCtrl)
143 {
144     int nSize = listCtrl->GetItemCount();
145     for (int i = 0; i < nSize; i++)
146         if (listCtrl->GetItemState(i, wxLIST_STATE_FOCUSED))
147             return i;
148     return -1;
149 }
150
151 string HtmlEscape(const char* psz, bool fMultiLine=false)
152 {
153     int len = 0;
154     for (const char* p = psz; *p; p++)
155     {
156              if (*p == '<') len += 4;
157         else if (*p == '>') len += 4;
158         else if (*p == '&') len += 5;
159         else if (*p == '"') len += 6;
160         else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') len += 6;
161         else if (*p == '\n' && fMultiLine) len += 5;
162         else
163             len++;
164     }
165     string str;
166     str.reserve(len);
167     for (const char* p = psz; *p; p++)
168     {
169              if (*p == '<') str += "&lt;";
170         else if (*p == '>') str += "&gt;";
171         else if (*p == '&') str += "&amp;";
172         else if (*p == '"') str += "&quot;";
173         else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += "&nbsp;";
174         else if (*p == '\n' && fMultiLine) str += "<br>\n";
175         else
176             str += *p;
177     }
178     return str;
179 }
180
181 string HtmlEscape(const string& str, bool fMultiLine=false)
182 {
183     return HtmlEscape(str.c_str(), fMultiLine);
184 }
185
186 void CalledMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y, int* pnRet, bool* pfDone)
187 {
188     *pnRet = wxMessageBox(message, caption, style, parent, x, y);
189     *pfDone = true;
190 }
191
192 int ThreadSafeMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y)
193 {
194 #ifdef __WXMSW__
195     return wxMessageBox(message, caption, style, parent, x, y);
196 #else
197     if (wxThread::IsMain() || fDaemon)
198     {
199         return wxMessageBox(message, caption, style, parent, x, y);
200     }
201     else
202     {
203         int nRet = 0;
204         bool fDone = false;
205         UIThreadCall(bind(CalledMessageBox, message, caption, style, parent, x, y, &nRet, &fDone));
206         while (!fDone)
207             Sleep(100);
208         return nRet;
209     }
210 #endif
211 }
212
213 bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* parent)
214 {
215     if (nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon)
216         return true;
217     string strMessage = strprintf(
218         _("This transaction is over the size limit.  You can still send it for a fee of %s, "
219           "which goes to the nodes that process your transaction and helps to support the network.  "
220           "Do you want to pay the fee?"),
221         FormatMoney(nFeeRequired).c_str());
222     return (ThreadSafeMessageBox(strMessage, strCaption, wxYES_NO, parent) == wxYES);
223 }
224
225 void CalledSetStatusBar(const string& strText, int nField)
226 {
227     if (nField == 0 && GetWarnings("statusbar") != "")
228         return;
229     if (pframeMain && pframeMain->m_statusBar)
230         pframeMain->m_statusBar->SetStatusText(strText, nField);
231 }
232
233 void SetDefaultReceivingAddress(const string& strAddress)
234 {
235     // Update main window address and database
236     if (pframeMain == NULL)
237         return;
238     if (strAddress != pframeMain->m_textCtrlAddress->GetValue())
239     {
240         CBitcoinAddress address(strAddress);
241         if (!address.IsValid())
242             return;
243         vector<unsigned char> vchPubKey;
244         if (!pwalletMain->GetPubKey(address, vchPubKey))
245             return;
246         pwalletMain->SetDefaultKey(vchPubKey);
247         pframeMain->m_textCtrlAddress->SetValue(strAddress);
248     }
249 }
250
251 bool GetWalletPassphrase()
252 {
253     if (pwalletMain->IsLocked())
254     {
255         string strWalletPass;
256         strWalletPass.reserve(100);
257         mlock(&strWalletPass[0], strWalletPass.capacity());
258
259         // obtain current wallet encrypt/decrypt key, from passphrase
260         // Note that the passphrase is not mlock()d during this entry and could potentially
261         // be obtained from disk long after bitcoin has run.
262         strWalletPass = wxGetPasswordFromUser(_("Enter the current passphrase to the wallet."),
263                                               _("Passphrase")).ToStdString();
264
265         if (!strWalletPass.size())
266         {
267             fill(strWalletPass.begin(), strWalletPass.end(), '\0');
268             munlock(&strWalletPass[0], strWalletPass.capacity());
269             wxMessageBox(_("Please supply the current wallet decryption passphrase."), "Bitcoin");
270             return false;
271         }
272
273         if (!pwalletMain->Unlock(strWalletPass))
274         {
275             fill(strWalletPass.begin(), strWalletPass.end(), '\0');
276             munlock(&strWalletPass[0], strWalletPass.capacity());
277             wxMessageBox(_("The passphrase entered for the wallet decryption was incorrect."), "Bitcoin");
278             return false;
279         }
280         fill(strWalletPass.begin(), strWalletPass.end(), '\0');
281         munlock(&strWalletPass[0], strWalletPass.capacity());
282     }
283     return true;
284 }
285
286
287
288
289
290
291
292
293
294
295 //////////////////////////////////////////////////////////////////////////////
296 //
297 // CMainFrame
298 //
299
300 CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
301 {
302     Connect(wxEVT_UITHREADCALL, wxCommandEventHandler(CMainFrame::OnUIThreadCall), NULL, this);
303
304     // Set initially selected page
305     wxNotebookEvent event;
306     event.SetSelection(0);
307     OnNotebookPageChanged(event);
308     m_notebook->ChangeSelection(0);
309
310     // Init
311     fRefreshListCtrl = false;
312     fRefreshListCtrlRunning = false;
313     fOnSetFocusAddress = false;
314     fRefresh = false;
315     m_choiceFilter->SetSelection(0);
316     double dResize = nScaleX;
317 #ifdef __WXMSW__
318     SetIcon(wxICON(bitcoin));
319     SetSize(dResize * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
320 #else
321     SetIcon(bitcoin80_xpm);
322     SetBackgroundColour(m_toolBar->GetBackgroundColour());
323     wxFont fontTmp = m_staticText41->GetFont();
324     fontTmp.SetFamily(wxFONTFAMILY_TELETYPE);
325     m_staticTextBalance->SetFont(fontTmp);
326     m_staticTextBalance->SetSize(140, 17);
327     // resize to fit ubuntu's huge default font
328     dResize = 1.22;
329     SetSize(dResize * GetSize().GetWidth(), 1.15 * GetSize().GetHeight());
330 #endif
331     m_staticTextBalance->SetLabel(FormatMoney(pwalletMain->GetBalance()) + "  ");
332     m_listCtrl->SetFocus();
333     ptaskbaricon = new CMyTaskBarIcon();
334 #ifdef __WXMAC_OSX__
335     // Mac automatically moves wxID_EXIT, wxID_PREFERENCES and wxID_ABOUT
336     // to their standard places, leaving these menus empty.
337     GetMenuBar()->Remove(2); // remove Help menu
338     GetMenuBar()->Remove(0); // remove File menu
339 #endif
340
341     // Init column headers
342     int nDateWidth = DateTimeStr(1229413914).size() * 6 + 8;
343     if (!strstr(DateTimeStr(1229413914).c_str(), "2008"))
344         nDateWidth += 12;
345 #ifdef __WXMAC_OSX__
346     nDateWidth += 5;
347     dResize -= 0.01;
348 #endif
349     wxListCtrl* pplistCtrl[] = {m_listCtrlAll, m_listCtrlSentReceived, m_listCtrlSent, m_listCtrlReceived};
350     BOOST_FOREACH(wxListCtrl* p, pplistCtrl)
351     {
352         p->InsertColumn(0, "",               wxLIST_FORMAT_LEFT,  dResize * 0);
353         p->InsertColumn(1, "",               wxLIST_FORMAT_LEFT,  dResize * 0);
354         p->InsertColumn(2, _("Status"),      wxLIST_FORMAT_LEFT,  dResize * 112);
355         p->InsertColumn(3, _("Date"),        wxLIST_FORMAT_LEFT,  dResize * nDateWidth);
356         p->InsertColumn(4, _("Description"), wxLIST_FORMAT_LEFT,  dResize * 409 - nDateWidth);
357         p->InsertColumn(5, _("Debit"),       wxLIST_FORMAT_RIGHT, dResize * 79);
358         p->InsertColumn(6, _("Credit"),      wxLIST_FORMAT_RIGHT, dResize * 79);
359     }
360
361     // Init status bar
362     int pnWidths[3] = { -100, 88, 300 };
363 #ifndef __WXMSW__
364     pnWidths[1] = pnWidths[1] * 1.1 * dResize;
365     pnWidths[2] = pnWidths[2] * 1.1 * dResize;
366 #endif
367     m_statusBar->SetFieldsCount(3, pnWidths);
368
369     // Fill your address text box
370     vector<unsigned char> vchPubKey;
371     if (CWalletDB(pwalletMain->strWalletFile,"r").ReadDefaultKey(vchPubKey))
372         m_textCtrlAddress->SetValue(CBitcoinAddress(vchPubKey).ToString());
373
374     if (pwalletMain->IsCrypted())
375         m_menuOptions->Remove(m_menuOptionsEncryptWallet);
376     else
377         m_menuOptions->Remove(m_menuOptionsChangeWalletPassphrase);
378
379     // Fill listctrl with wallet transactions
380     RefreshListCtrl();
381 }
382
383 CMainFrame::~CMainFrame()
384 {
385     pframeMain = NULL;
386     delete ptaskbaricon;
387     ptaskbaricon = NULL;
388 }
389
390 void CMainFrame::OnNotebookPageChanged(wxNotebookEvent& event)
391 {
392     event.Skip();
393     nPage = event.GetSelection();
394     if (nPage == ALL)
395     {
396         m_listCtrl = m_listCtrlAll;
397         fShowGenerated = true;
398         fShowSent = true;
399         fShowReceived = true;
400     }
401     else if (nPage == SENTRECEIVED)
402     {
403         m_listCtrl = m_listCtrlSentReceived;
404         fShowGenerated = false;
405         fShowSent = true;
406         fShowReceived = true;
407     }
408     else if (nPage == SENT)
409     {
410         m_listCtrl = m_listCtrlSent;
411         fShowGenerated = false;
412         fShowSent = true;
413         fShowReceived = false;
414     }
415     else if (nPage == RECEIVED)
416     {
417         m_listCtrl = m_listCtrlReceived;
418         fShowGenerated = false;
419         fShowSent = false;
420         fShowReceived = true;
421     }
422     RefreshListCtrl();
423     m_listCtrl->SetFocus();
424 }
425
426 void CMainFrame::OnClose(wxCloseEvent& event)
427 {
428     if (fMinimizeOnClose && event.CanVeto() && !IsIconized())
429     {
430         // Divert close to minimize
431         event.Veto();
432         fClosedToTray = true;
433         Iconize(true);
434     }
435     else
436     {
437         Destroy();
438         CreateThread(Shutdown, NULL);
439     }
440 }
441
442 void CMainFrame::OnIconize(wxIconizeEvent& event)
443 {
444     event.Skip();
445     // Hide the task bar button when minimized.
446     // Event is sent when the frame is minimized or restored.
447     // wxWidgets 2.8.9 doesn't have IsIconized() so there's no way
448     // to get rid of the deprecated warning.  Just ignore it.
449     if (!event.Iconized())
450         fClosedToTray = false;
451 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
452     if (GetBoolArg("-minimizetotray")) {
453 #endif
454     // The tray icon sometimes disappears on ubuntu karmic
455     // Hiding the taskbar button doesn't work cleanly on ubuntu lucid
456     // Reports of CPU peg on 64-bit linux
457     if (fMinimizeToTray && event.Iconized())
458         fClosedToTray = true;
459     Show(!fClosedToTray);
460     ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
461 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
462     }
463 #endif
464 }
465
466 void CMainFrame::OnMouseEvents(wxMouseEvent& event)
467 {
468     event.Skip();
469     RandAddSeed();
470     RAND_add(&event.m_x, sizeof(event.m_x), 0.25);
471     RAND_add(&event.m_y, sizeof(event.m_y), 0.25);
472 }
473
474 void CMainFrame::OnListColBeginDrag(wxListEvent& event)
475 {
476     // Hidden columns not resizeable
477     if (event.GetColumn() <= 1 && !fDebug)
478         event.Veto();
479     else
480         event.Skip();
481 }
482
483 int CMainFrame::GetSortIndex(const string& strSort)
484 {
485 #ifdef __WXMSW__
486     return 0;
487 #else
488     // The wx generic listctrl implementation used on GTK doesn't sort,
489     // so we have to do it ourselves.  Remember, we sort in reverse order.
490     // In the wx generic implementation, they store the list of items
491     // in a vector, so indexed lookups are fast, but inserts are slower
492     // the closer they are to the top.
493     int low = 0;
494     int high = m_listCtrl->GetItemCount();
495     while (low < high)
496     {
497         int mid = low + ((high - low) / 2);
498         if (strSort.compare(m_listCtrl->GetItemText(mid).c_str()) >= 0)
499             high = mid;
500         else
501             low = mid + 1;
502     }
503     return low;
504 #endif
505 }
506
507 void CMainFrame::InsertLine(bool fNew, int nIndex, uint256 hashKey, string strSort, const wxColour& colour, const wxString& str2, const wxString& str3, const wxString& str4, const wxString& str5, const wxString& str6)
508 {
509     strSort = " " + strSort;       // leading space to workaround wx2.9.0 ubuntu 9.10 bug
510     long nData = *(long*)&hashKey; //  where first char of hidden column is displayed
511
512     // Find item
513     if (!fNew && nIndex == -1)
514     {
515         string strHash = " " + hashKey.ToString();
516         while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
517             if (GetItemText(m_listCtrl, nIndex, 1) == strHash)
518                 break;
519     }
520
521     // fNew is for blind insert, only use if you're sure it's new
522     if (fNew || nIndex == -1)
523     {
524         nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), strSort);
525     }
526     else
527     {
528         // If sort key changed, must delete and reinsert to make it relocate
529         if (GetItemText(m_listCtrl, nIndex, 0) != strSort)
530         {
531             m_listCtrl->DeleteItem(nIndex);
532             nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), strSort);
533         }
534     }
535
536     m_listCtrl->SetItem(nIndex, 1, " " + hashKey.ToString());
537     m_listCtrl->SetItem(nIndex, 2, str2);
538     m_listCtrl->SetItem(nIndex, 3, str3);
539     m_listCtrl->SetItem(nIndex, 4, str4);
540     m_listCtrl->SetItem(nIndex, 5, str5);
541     m_listCtrl->SetItem(nIndex, 6, str6);
542     m_listCtrl->SetItemData(nIndex, nData);
543     SetItemTextColour(m_listCtrl, nIndex, colour);
544 }
545
546 bool CMainFrame::DeleteLine(uint256 hashKey)
547 {
548     long nData = *(long*)&hashKey;
549
550     // Find item
551     int nIndex = -1;
552     string strHash = " " + hashKey.ToString();
553     while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
554         if (GetItemText(m_listCtrl, nIndex, 1) == strHash)
555             break;
556
557     if (nIndex != -1)
558         m_listCtrl->DeleteItem(nIndex);
559
560     return nIndex != -1;
561 }
562
563 string FormatTxStatus(const CWalletTx& wtx)
564 {
565     // Status
566     if (!wtx.IsFinal())
567     {
568         if (wtx.nLockTime < LOCKTIME_THRESHOLD)
569             return strprintf(_("Open for %d blocks"), nBestHeight - wtx.nLockTime);
570         else
571             return strprintf(_("Open until %s"), DateTimeStr(wtx.nLockTime).c_str());
572     }
573     else
574     {
575         int nDepth = wtx.GetDepthInMainChain();
576         if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
577             return strprintf(_("%d/offline?"), nDepth);
578         else if (nDepth < 6)
579             return strprintf(_("%d/unconfirmed"), nDepth);
580         else
581             return strprintf(_("%d confirmations"), nDepth);
582     }
583 }
584
585 string SingleLine(const string& strIn)
586 {
587     string strOut;
588     bool fOneSpace = false;
589     BOOST_FOREACH(unsigned char c, strIn)
590     {
591         if (isspace(c))
592         {
593             fOneSpace = true;
594         }
595         else if (c > ' ')
596         {
597             if (fOneSpace && !strOut.empty())
598                 strOut += ' ';
599             strOut += c;
600             fOneSpace = false;
601         }
602     }
603     return strOut;
604 }
605
606 bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
607 {
608     int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
609     int64 nCredit = wtx.GetCredit(true);
610     int64 nDebit = wtx.GetDebit();
611     int64 nNet = nCredit - nDebit;
612     uint256 hash = wtx.GetHash();
613     string strStatus = FormatTxStatus(wtx);
614     bool fConfirmed = wtx.fConfirmedDisplayed = wtx.IsConfirmed();
615     wxColour colour = (fConfirmed ? wxColour(0,0,0) : wxColour(128,128,128));
616     map<string, string> mapValue = wtx.mapValue;
617     wtx.nLinesDisplayed = 1;
618     nListViewUpdated++;
619
620     // Filter
621     if (wtx.IsCoinBase())
622     {
623         // Don't show generated coin until confirmed by at least one block after it
624         // so we don't get the user's hopes up until it looks like it's probably accepted.
625         //
626         // It is not an error when generated blocks are not accepted.  By design,
627         // some percentage of blocks, like 10% or more, will end up not accepted.
628         // This is the normal mechanism by which the network copes with latency.
629         //
630         // We display regular transactions right away before any confirmation
631         // because they can always get into some block eventually.  Generated coins
632         // are special because if their block is not accepted, they are not valid.
633         //
634         if (wtx.GetDepthInMainChain() < 2)
635         {
636             wtx.nLinesDisplayed = 0;
637             return false;
638         }
639
640         if (!fShowGenerated)
641             return false;
642     }
643
644     // Find the block the tx is in
645     CBlockIndex* pindex = NULL;
646     map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);
647     if (mi != mapBlockIndex.end())
648         pindex = (*mi).second;
649
650     // Sort order, unrecorded transactions sort to the top
651     string strSort = strprintf("%010d-%01d-%010u",
652         (pindex ? pindex->nHeight : INT_MAX),
653         (wtx.IsCoinBase() ? 1 : 0),
654         wtx.nTimeReceived);
655
656     // Insert line
657     if (nNet > 0 || wtx.IsCoinBase())
658     {
659         //
660         // Credit
661         //
662         string strDescription;
663         if (wtx.IsCoinBase())
664         {
665             // Generated
666             strDescription = _("Generated");
667             if (nCredit == 0)
668             {
669                 int64 nUnmatured = 0;
670                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
671                     nUnmatured += pwalletMain->GetCredit(txout);
672                 if (wtx.IsInMainChain())
673                 {
674                     strDescription = strprintf(_("Generated (%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
675
676                     // Check if the block was requested by anyone
677                     if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
678                         strDescription = _("Generated - Warning: This block was not received by any other nodes and will probably not be accepted!");
679                 }
680                 else
681                 {
682                     strDescription = _("Generated (not accepted)");
683                 }
684             }
685         }
686         else if (!mapValue["from"].empty() || !mapValue["message"].empty())
687         {
688             // Received by IP connection
689             if (!fShowReceived)
690                 return false;
691             if (!mapValue["from"].empty())
692                 strDescription += _("From: ") + mapValue["from"];
693             if (!mapValue["message"].empty())
694             {
695                 if (!strDescription.empty())
696                     strDescription += " - ";
697                 strDescription += mapValue["message"];
698             }
699         }
700         else
701         {
702             // Received by Bitcoin Address
703             if (!fShowReceived)
704                 return false;
705             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
706             {
707                 if (pwalletMain->IsMine(txout))
708                 {
709                     CBitcoinAddress address;
710                     if (ExtractAddress(txout.scriptPubKey, pwalletMain, address))
711                     {
712                         CRITICAL_BLOCK(pwalletMain->cs_wallet)
713                         {
714                             //strDescription += _("Received payment to ");
715                             //strDescription += _("Received with address ");
716                             strDescription += _("Received with: ");
717                             map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
718                             if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
719                             {
720                                 string strLabel = (*mi).second;
721                                 strDescription += address.ToString().substr(0,12) + "... ";
722                                 strDescription += "(" + strLabel + ")";
723                             }
724                             else
725                                 strDescription += address.ToString();
726                         }
727                     }
728                     break;
729                 }
730             }
731         }
732
733         string strCredit = FormatMoney(nNet, true);
734         if (!fConfirmed)
735             strCredit = "[" + strCredit + "]";
736
737         InsertLine(fNew, nIndex, hash, strSort, colour,
738                    strStatus,
739                    nTime ? DateTimeStr(nTime) : "",
740                    SingleLine(strDescription),
741                    "",
742                    strCredit);
743     }
744     else
745     {
746         bool fAllFromMe = true;
747         BOOST_FOREACH(const CTxIn& txin, wtx.vin)
748             fAllFromMe = fAllFromMe && pwalletMain->IsMine(txin);
749
750         bool fAllToMe = true;
751         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
752             fAllToMe = fAllToMe && pwalletMain->IsMine(txout);
753
754         if (fAllFromMe && fAllToMe)
755         {
756             // Payment to self
757             int64 nChange = wtx.GetChange();
758             InsertLine(fNew, nIndex, hash, strSort, colour,
759                        strStatus,
760                        nTime ? DateTimeStr(nTime) : "",
761                        _("Payment to yourself"),
762                        FormatMoney(-(nDebit - nChange), true),
763                        FormatMoney(nCredit - nChange, true));
764         }
765         else if (fAllFromMe)
766         {
767             //
768             // Debit
769             //
770             if (!fShowSent)
771                 return false;
772
773             int64 nTxFee = nDebit - wtx.GetValueOut();
774             wtx.nLinesDisplayed = 0;
775             for (int nOut = 0; nOut < wtx.vout.size(); nOut++)
776             {
777                 const CTxOut& txout = wtx.vout[nOut];
778                 if (pwalletMain->IsMine(txout))
779                     continue;
780
781                 CBitcoinAddress address;
782                 string strAddress;
783                 if (!mapValue["to"].empty())
784                 {
785                     // Sent to IP
786                     strAddress = mapValue["to"];
787                 }
788                 else
789                 {
790                     // Sent to Bitcoin Address
791                     if (ExtractAddress(txout.scriptPubKey, NULL, address))
792                         strAddress = address.ToString();
793                 }
794
795                 string strDescription = _("To: ");
796                 CRITICAL_BLOCK(pwalletMain->cs_wallet)
797                     if (pwalletMain->mapAddressBook.count(address) && !pwalletMain->mapAddressBook[address].empty())
798                         strDescription += pwalletMain->mapAddressBook[address] + " ";
799                 strDescription += strAddress;
800                 if (!mapValue["message"].empty())
801                 {
802                     if (!strDescription.empty())
803                         strDescription += " - ";
804                     strDescription += mapValue["message"];
805                 }
806                 else if (!mapValue["comment"].empty())
807                 {
808                     if (!strDescription.empty())
809                         strDescription += " - ";
810                     strDescription += mapValue["comment"];
811                 }
812
813                 int64 nValue = txout.nValue;
814                 if (nTxFee > 0)
815                 {
816                     nValue += nTxFee;
817                     nTxFee = 0;
818                 }
819
820                 InsertLine(fNew, nIndex, hash, strprintf("%s-%d", strSort.c_str(), nOut), colour,
821                            strStatus,
822                            nTime ? DateTimeStr(nTime) : "",
823                            SingleLine(strDescription),
824                            FormatMoney(-nValue, true),
825                            "");
826                 nIndex = -1;
827                 wtx.nLinesDisplayed++;
828             }
829         }
830         else
831         {
832             //
833             // Mixed debit transaction, can't break down payees
834             //
835             bool fAllMine = true;
836             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
837                 fAllMine = fAllMine && pwalletMain->IsMine(txout);
838             BOOST_FOREACH(const CTxIn& txin, wtx.vin)
839                 fAllMine = fAllMine && pwalletMain->IsMine(txin);
840
841             InsertLine(fNew, nIndex, hash, strSort, colour,
842                        strStatus,
843                        nTime ? DateTimeStr(nTime) : "",
844                        "",
845                        FormatMoney(nNet, true),
846                        "");
847         }
848     }
849
850     return true;
851 }
852
853 void CMainFrame::RefreshListCtrl()
854 {
855     fRefreshListCtrl = true;
856     ::wxWakeUpIdle();
857 }
858
859 void CMainFrame::OnIdle(wxIdleEvent& event)
860 {
861     if (fRefreshListCtrl)
862     {
863         // Collect list of wallet transactions and sort newest first
864         bool fEntered = false;
865         vector<pair<unsigned int, uint256> > vSorted;
866         TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
867         {
868             printf("RefreshListCtrl starting\n");
869             fEntered = true;
870             fRefreshListCtrl = false;
871             pwalletMain->vWalletUpdated.clear();
872
873             // Do the newest transactions first
874             vSorted.reserve(pwalletMain->mapWallet.size());
875             for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
876             {
877                 const CWalletTx& wtx = (*it).second;
878                 unsigned int nTime = UINT_MAX - wtx.GetTxTime();
879                 vSorted.push_back(make_pair(nTime, (*it).first));
880             }
881             m_listCtrl->DeleteAllItems();
882         }
883         if (!fEntered)
884             return;
885
886         sort(vSorted.begin(), vSorted.end());
887
888         // Fill list control
889         for (int i = 0; i < vSorted.size();)
890         {
891             if (fShutdown)
892                 return;
893             bool fEntered = false;
894             TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
895             {
896                 fEntered = true;
897                 uint256& hash = vSorted[i++].second;
898                 map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
899                 if (mi != pwalletMain->mapWallet.end())
900                     InsertTransaction((*mi).second, true);
901             }
902             if (!fEntered || i == 100 || i % 500 == 0)
903                 wxYield();
904         }
905
906         printf("RefreshListCtrl done\n");
907
908         // Update transaction total display
909         MainFrameRepaint();
910     }
911     else
912     {
913         // Check for time updates
914         static int64 nLastTime;
915         if (GetTime() > nLastTime + 30)
916         {
917             TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
918             {
919                 nLastTime = GetTime();
920                 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
921                 {
922                     CWalletTx& wtx = (*it).second;
923                     if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime())
924                         InsertTransaction(wtx, false);
925                 }
926             }
927         }
928     }
929 }
930
931 void CMainFrame::RefreshStatusColumn()
932 {
933     static int nLastTop;
934     static CBlockIndex* pindexLastBest;
935     static unsigned int nLastRefreshed;
936
937     int nTop = max((int)m_listCtrl->GetTopItem(), 0);
938     if (nTop == nLastTop && pindexLastBest == pindexBest)
939         return;
940
941     TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
942     {
943         int nStart = nTop;
944         int nEnd = min(nStart + 100, m_listCtrl->GetItemCount());
945
946         if (pindexLastBest == pindexBest && nLastRefreshed == nListViewUpdated)
947         {
948             // If no updates, only need to do the part that moved onto the screen
949             if (nStart >= nLastTop && nStart < nLastTop + 100)
950                 nStart = nLastTop + 100;
951             if (nEnd >= nLastTop && nEnd < nLastTop + 100)
952                 nEnd = nLastTop;
953         }
954         nLastTop = nTop;
955         pindexLastBest = pindexBest;
956         nLastRefreshed = nListViewUpdated;
957
958         for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++)
959         {
960             uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1));
961             map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
962             if (mi == pwalletMain->mapWallet.end())
963             {
964                 printf("CMainFrame::RefreshStatusColumn() : tx not found in mapWallet\n");
965                 continue;
966             }
967             CWalletTx& wtx = (*mi).second;
968             if (wtx.IsCoinBase() ||
969                 wtx.GetTxTime() != wtx.nTimeDisplayed ||
970                 wtx.IsConfirmed() != wtx.fConfirmedDisplayed)
971             {
972                 if (!InsertTransaction(wtx, false, nIndex))
973                     m_listCtrl->DeleteItem(nIndex--);
974             }
975             else
976             {
977                 m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx));
978             }
979         }
980     }
981 }
982
983 void CMainFrame::OnPaint(wxPaintEvent& event)
984 {
985     event.Skip();
986     if (fRefresh)
987     {
988         fRefresh = false;
989         Refresh();
990     }
991 }
992
993
994 unsigned int nNeedRepaint = 0;
995 unsigned int nLastRepaint = 0;
996 int64 nLastRepaintTime = 0;
997 int64 nRepaintInterval = 500;
998
999 void ThreadDelayedRepaint(void* parg)
1000 {
1001     while (!fShutdown)
1002     {
1003         if (nLastRepaint != nNeedRepaint && GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
1004         {
1005             nLastRepaint = nNeedRepaint;
1006             if (pframeMain)
1007             {
1008                 printf("DelayedRepaint\n");
1009                 wxPaintEvent event;
1010                 pframeMain->fRefresh = true;
1011                 pframeMain->GetEventHandler()->AddPendingEvent(event);
1012             }
1013         }
1014         Sleep(nRepaintInterval);
1015     }
1016 }
1017
1018 void MainFrameRepaint()
1019 {
1020     // This is called by network code that shouldn't access pframeMain
1021     // directly because it could still be running after the UI is closed.
1022     if (pframeMain)
1023     {
1024         // Don't repaint too often
1025         static int64 nLastRepaintRequest;
1026         if (GetTimeMillis() - nLastRepaintRequest < 100)
1027         {
1028             nNeedRepaint++;
1029             return;
1030         }
1031         nLastRepaintRequest = GetTimeMillis();
1032
1033         printf("MainFrameRepaint\n");
1034         wxPaintEvent event;
1035         pframeMain->fRefresh = true;
1036         pframeMain->GetEventHandler()->AddPendingEvent(event);
1037     }
1038 }
1039
1040 void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
1041 {
1042     // Skip lets the listctrl do the paint, we're just hooking the message
1043     event.Skip();
1044
1045     if (ptaskbaricon)
1046         ptaskbaricon->UpdateTooltip();
1047
1048     //
1049     // Slower stuff
1050     //
1051     static int nTransactionCount;
1052     bool fPaintedBalance = false;
1053     if (GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
1054     {
1055         nLastRepaint = nNeedRepaint;
1056         nLastRepaintTime = GetTimeMillis();
1057
1058         // Update listctrl contents
1059         if (!pwalletMain->vWalletUpdated.empty())
1060         {
1061             TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
1062             {
1063                 string strTop;
1064                 if (m_listCtrl->GetItemCount())
1065                     strTop = (string)m_listCtrl->GetItemText(0);
1066                 BOOST_FOREACH(uint256 hash, pwalletMain->vWalletUpdated)
1067                 {
1068                     map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
1069                     if (mi != pwalletMain->mapWallet.end())
1070                         InsertTransaction((*mi).second, false);
1071                 }
1072                 pwalletMain->vWalletUpdated.clear();
1073                 if (m_listCtrl->GetItemCount() && strTop != (string)m_listCtrl->GetItemText(0))
1074                     m_listCtrl->ScrollList(0, INT_MIN/2);
1075             }
1076         }
1077
1078         // Balance total
1079         TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
1080         {
1081             fPaintedBalance = true;
1082             m_staticTextBalance->SetLabel(FormatMoney(pwalletMain->GetBalance()) + "  ");
1083
1084             // Count hidden and multi-line transactions
1085             nTransactionCount = 0;
1086             for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1087             {
1088                 CWalletTx& wtx = (*it).second;
1089                 nTransactionCount += wtx.nLinesDisplayed;
1090             }
1091         }
1092     }
1093     if (!pwalletMain->vWalletUpdated.empty() || !fPaintedBalance)
1094         nNeedRepaint++;
1095
1096     // Update status column of visible items only
1097     RefreshStatusColumn();
1098
1099     // Update status bar
1100     static string strPrevWarning;
1101     string strWarning = GetWarnings("statusbar");
1102     if (strWarning != "")
1103         m_statusBar->SetStatusText(string("    ") + _(strWarning), 0);
1104     else if (strPrevWarning != "")
1105         m_statusBar->SetStatusText("", 0);
1106     strPrevWarning = strWarning;
1107
1108     string strGen = "";
1109     if (fGenerateBitcoins)
1110         strGen = _("    Generating");
1111     if (fGenerateBitcoins && vNodes.empty())
1112         strGen = _("(not connected)");
1113     m_statusBar->SetStatusText(strGen, 1);
1114
1115     string strStatus = strprintf(_("     %d connections     %d blocks     %d transactions"), vNodes.size(), nBestHeight, nTransactionCount);
1116     m_statusBar->SetStatusText(strStatus, 2);
1117
1118     // Update receiving address
1119     string strDefaultAddress = CBitcoinAddress(pwalletMain->vchDefaultKey).ToString();
1120     if (m_textCtrlAddress->GetValue() != strDefaultAddress)
1121         m_textCtrlAddress->SetValue(strDefaultAddress);
1122 }
1123
1124
1125 void UIThreadCall(boost::function0<void> fn)
1126 {
1127     // Call this with a function object created with bind.
1128     // bind needs all parameters to match the function's expected types
1129     // and all default parameters specified.  Some examples:
1130     //  UIThreadCall(bind(wxBell));
1131     //  UIThreadCall(bind(wxMessageBox, wxT("Message"), wxT("Title"), wxOK, (wxWindow*)NULL, -1, -1));
1132     //  UIThreadCall(bind(&CMainFrame::OnMenuHelpAbout, pframeMain, event));
1133     if (pframeMain)
1134     {
1135         wxCommandEvent event(wxEVT_UITHREADCALL);
1136         event.SetClientData((void*)new boost::function0<void>(fn));
1137         pframeMain->GetEventHandler()->AddPendingEvent(event);
1138     }
1139 }
1140
1141 void CMainFrame::OnUIThreadCall(wxCommandEvent& event)
1142 {
1143     boost::function0<void>* pfn = (boost::function0<void>*)event.GetClientData();
1144     (*pfn)();
1145     delete pfn;
1146 }
1147
1148 void CMainFrame::OnMenuFileExit(wxCommandEvent& event)
1149 {
1150     // File->Exit
1151     Close(true);
1152 }
1153
1154 void CMainFrame::OnUpdateUIOptionsGenerate(wxUpdateUIEvent& event)
1155 {
1156     event.Check(fGenerateBitcoins);
1157 }
1158
1159 void CMainFrame::OnMenuOptionsChangeYourAddress(wxCommandEvent& event)
1160 {
1161     // Options->Your Receiving Addresses
1162     CAddressBookDialog dialog(this, "", CAddressBookDialog::RECEIVING, false);
1163     if (!dialog.ShowModal())
1164         return;
1165 }
1166
1167 void CMainFrame::OnMenuOptionsEncryptWallet(wxCommandEvent& event)
1168 {
1169     // Options->Encrypt Wallet
1170     if (pwalletMain->IsCrypted())
1171     {
1172         wxMessageBox(_("Wallet already encrypted."), "Bitcoin", wxOK | wxICON_ERROR);
1173         return;
1174     }
1175
1176     string strWalletPass;
1177     strWalletPass.reserve(100);
1178     mlock(&strWalletPass[0], strWalletPass.capacity());
1179
1180     // obtain current wallet encrypt/decrypt key, from passphrase
1181     // Note that the passphrase is not mlock()d during this entry and could potentially
1182     // be obtained from disk long after bitcoin has run.
1183     strWalletPass = wxGetPasswordFromUser(_("Enter the new passphrase to the wallet.\nPlease use a passphrase of 10 or more random characters, or eight or more words."),
1184                                           _("Passphrase")).ToStdString();
1185
1186     if (!strWalletPass.size())
1187     {
1188         fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1189         munlock(&strWalletPass[0], strWalletPass.capacity());
1190         wxMessageBox(_("Error: The supplied passphrase was too short."), "Bitcoin", wxOK | wxICON_ERROR);
1191         return;
1192     }
1193
1194     if(wxMessageBox(_("WARNING: If you encrypt your wallet and lose your passphrase, you will LOSE ALL OF YOUR BITCOINS!\nAre you sure you wish to encrypt your wallet?"), "Bitcoin", wxYES_NO) != wxYES)
1195         return;
1196
1197     string strWalletPassTest;
1198     strWalletPassTest.reserve(100);
1199     mlock(&strWalletPassTest[0], strWalletPassTest.capacity());
1200     strWalletPassTest = wxGetPasswordFromUser(_("Please re-enter your new wallet passphrase."),
1201                                               _("Passphrase")).ToStdString();
1202
1203     if (strWalletPassTest != strWalletPass)
1204     {
1205         fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1206         fill(strWalletPassTest.begin(), strWalletPassTest.end(), '\0');
1207         munlock(&strWalletPass[0], strWalletPass.capacity());
1208         munlock(&strWalletPassTest[0], strWalletPassTest.capacity());
1209         wxMessageBox(_("Error: the supplied passphrases didn't match."), "Bitcoin", wxOK | wxICON_ERROR);
1210         return;
1211     }
1212
1213     if (!pwalletMain->EncryptWallet(strWalletPass))
1214     {
1215         fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1216         fill(strWalletPassTest.begin(), strWalletPassTest.end(), '\0');
1217         munlock(&strWalletPass[0], strWalletPass.capacity());
1218         munlock(&strWalletPassTest[0], strWalletPassTest.capacity());
1219         wxMessageBox(_("Wallet encryption failed."), "Bitcoin", wxOK | wxICON_ERROR);
1220         return;
1221     }
1222     fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1223     fill(strWalletPassTest.begin(), strWalletPassTest.end(), '\0');
1224     munlock(&strWalletPass[0], strWalletPass.capacity());
1225     munlock(&strWalletPassTest[0], strWalletPassTest.capacity());
1226     wxMessageBox(_("Wallet Encrypted.\nRemember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer."), "Bitcoin");
1227
1228     m_menuOptions->Remove(m_menuOptionsEncryptWallet);
1229     m_menuOptions->Insert(m_menuOptions->GetMenuItemCount() - 1, m_menuOptionsChangeWalletPassphrase);
1230 }
1231
1232 void CMainFrame::OnMenuOptionsChangeWalletPassphrase(wxCommandEvent& event)
1233 {
1234     // Options->Change Wallet Encryption Passphrase
1235     if (!pwalletMain->IsCrypted())
1236     {
1237         wxMessageBox(_("Wallet is unencrypted, please encrypt it first."), "Bitcoin", wxOK | wxICON_ERROR);
1238         return;
1239     }
1240
1241     string strOldWalletPass;
1242     strOldWalletPass.reserve(100);
1243     mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1244
1245     // obtain current wallet encrypt/decrypt key, from passphrase
1246     // Note that the passphrase is not mlock()d during this entry and could potentially
1247     // be obtained from disk long after bitcoin has run.
1248     strOldWalletPass = wxGetPasswordFromUser(_("Enter the current passphrase to the wallet."),
1249                                              _("Passphrase")).ToStdString();
1250
1251     bool fWasLocked = pwalletMain->IsLocked();
1252     pwalletMain->Lock();
1253
1254     if (!strOldWalletPass.size() || !pwalletMain->Unlock(strOldWalletPass))
1255     {
1256         fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1257         munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1258         wxMessageBox(_("The passphrase entered for the wallet decryption was incorrect."), "Bitcoin", wxOK | wxICON_ERROR);
1259         return;
1260     }
1261
1262     if (fWasLocked)
1263         pwalletMain->Lock();
1264
1265     string strNewWalletPass;
1266     strNewWalletPass.reserve(100);
1267     mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1268
1269     // obtain new wallet encrypt/decrypt key, from passphrase
1270     // Note that the passphrase is not mlock()d during this entry and could potentially
1271     // be obtained from disk long after bitcoin has run.
1272     strNewWalletPass = wxGetPasswordFromUser(_("Enter the new passphrase for the wallet."),
1273                                              _("Passphrase")).ToStdString();
1274
1275     if (!strNewWalletPass.size())
1276     {
1277         fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1278         fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1279         munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1280         munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1281         wxMessageBox(_("Error: The supplied passphrase was too short."), "Bitcoin", wxOK | wxICON_ERROR);
1282         return;
1283     }
1284
1285     string strNewWalletPassTest;
1286     strNewWalletPassTest.reserve(100);
1287     mlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity());
1288
1289     // obtain new wallet encrypt/decrypt key, from passphrase
1290     // Note that the passphrase is not mlock()d during this entry and could potentially
1291     // be obtained from disk long after bitcoin has run.
1292     strNewWalletPassTest = wxGetPasswordFromUser(_("Re-enter the new passphrase for the wallet."),
1293                                                  _("Passphrase")).ToStdString();
1294
1295     if (strNewWalletPassTest != strNewWalletPass)
1296     {
1297         fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1298         fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1299         fill(strNewWalletPassTest.begin(), strNewWalletPassTest.end(), '\0');
1300         munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1301         munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1302         munlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity());
1303         wxMessageBox(_("Error: the supplied passphrases didn't match."), "Bitcoin", wxOK | wxICON_ERROR);
1304         return;
1305     }
1306
1307     if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1308     {
1309         fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1310         fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1311         fill(strNewWalletPassTest.begin(), strNewWalletPassTest.end(), '\0');
1312         munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1313         munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1314         munlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity());
1315         wxMessageBox(_("The passphrase entered for the wallet decryption was incorrect."), "Bitcoin", wxOK | wxICON_ERROR);
1316         return;
1317     }
1318     fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1319     fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1320     fill(strNewWalletPassTest.begin(), strNewWalletPassTest.end(), '\0');
1321     munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1322     munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1323     munlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity());
1324     wxMessageBox(_("Wallet Passphrase Changed."), "Bitcoin");
1325 }
1326
1327 void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event)
1328 {
1329     // Options->Options
1330     COptionsDialog dialog(this);
1331     dialog.ShowModal();
1332 }
1333
1334 void CMainFrame::OnMenuHelpAbout(wxCommandEvent& event)
1335 {
1336     // Help->About
1337     CAboutDialog dialog(this);
1338     dialog.ShowModal();
1339 }
1340
1341 void CMainFrame::OnButtonSend(wxCommandEvent& event)
1342 {
1343     // Toolbar: Send
1344     CSendDialog dialog(this);
1345     dialog.ShowModal();
1346 }
1347
1348 void CMainFrame::OnButtonAddressBook(wxCommandEvent& event)
1349 {
1350     // Toolbar: Address Book
1351     CAddressBookDialog dialogAddr(this, "", CAddressBookDialog::SENDING, false);
1352     if (dialogAddr.ShowModal() == 2)
1353     {
1354         // Send
1355         CSendDialog dialogSend(this, dialogAddr.GetSelectedAddress());
1356         dialogSend.ShowModal();
1357     }
1358 }
1359
1360 void CMainFrame::OnSetFocusAddress(wxFocusEvent& event)
1361 {
1362     // Automatically select-all when entering window
1363     event.Skip();
1364     m_textCtrlAddress->SetSelection(-1, -1);
1365     fOnSetFocusAddress = true;
1366 }
1367
1368 void CMainFrame::OnMouseEventsAddress(wxMouseEvent& event)
1369 {
1370     event.Skip();
1371     if (fOnSetFocusAddress)
1372         m_textCtrlAddress->SetSelection(-1, -1);
1373     fOnSetFocusAddress = false;
1374 }
1375
1376 void CMainFrame::OnButtonNew(wxCommandEvent& event)
1377 {
1378     // Ask name
1379     CGetTextFromUserDialog dialog(this,
1380         _("New Receiving Address"),
1381         _("You should use a new address for each payment you receive.\n\nLabel"),
1382         "");
1383     if (!dialog.ShowModal())
1384         return;
1385     string strName = dialog.GetValue();
1386
1387     string strAddress;
1388
1389     bool fWasLocked = pwalletMain->IsLocked();
1390     if (!GetWalletPassphrase())
1391         return;
1392
1393     // Generate new key
1394     std::vector<unsigned char> newKey;
1395     pwalletMain->GetKeyFromPool(newKey, true);
1396     strAddress = CBitcoinAddress(newKey).ToString();
1397
1398     if (fWasLocked)
1399         pwalletMain->Lock();
1400
1401     // Save
1402     CRITICAL_BLOCK(pwalletMain->cs_wallet)
1403         pwalletMain->SetAddressBookName(strAddress, strName);
1404     SetDefaultReceivingAddress(strAddress);
1405 }
1406
1407 void CMainFrame::OnButtonCopy(wxCommandEvent& event)
1408 {
1409     // Copy address box to clipboard
1410     if (wxTheClipboard->Open())
1411     {
1412         wxTheClipboard->SetData(new wxTextDataObject(m_textCtrlAddress->GetValue()));
1413         wxTheClipboard->Close();
1414     }
1415 }
1416
1417 void CMainFrame::OnListItemActivated(wxListEvent& event)
1418 {
1419     uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1));
1420     CWalletTx wtx;
1421     CRITICAL_BLOCK(pwalletMain->cs_wallet)
1422     {
1423         map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
1424         if (mi == pwalletMain->mapWallet.end())
1425         {
1426             printf("CMainFrame::OnListItemActivated() : tx not found in mapWallet\n");
1427             return;
1428         }
1429         wtx = (*mi).second;
1430     }
1431     CTxDetailsDialog dialog(this, wtx);
1432     dialog.ShowModal();
1433     //CTxDetailsDialog* pdialog = new CTxDetailsDialog(this, wtx);
1434     //pdialog->Show();
1435 }
1436
1437
1438
1439
1440
1441
1442 //////////////////////////////////////////////////////////////////////////////
1443 //
1444 // CTxDetailsDialog
1445 //
1446
1447 CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetailsDialogBase(parent)
1448 {
1449 #ifdef __WXMSW__
1450     SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
1451 #endif
1452     CRITICAL_BLOCK(pwalletMain->cs_wallet)
1453     {
1454         string strHTML;
1455         strHTML.reserve(4000);
1456         strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
1457
1458         int64 nTime = wtx.GetTxTime();
1459         int64 nCredit = wtx.GetCredit();
1460         int64 nDebit = wtx.GetDebit();
1461         int64 nNet = nCredit - nDebit;
1462
1463
1464
1465         strHTML += _("<b>Status:</b> ") + FormatTxStatus(wtx);
1466         int nRequests = wtx.GetRequestCount();
1467         if (nRequests != -1)
1468         {
1469             if (nRequests == 0)
1470                 strHTML += _(", has not been successfully broadcast yet");
1471             else if (nRequests == 1)
1472                 strHTML += strprintf(_(", broadcast through %d node"), nRequests);
1473             else
1474                 strHTML += strprintf(_(", broadcast through %d nodes"), nRequests);
1475         }
1476         strHTML += "<br>";
1477
1478         strHTML += _("<b>Date:</b> ") + (nTime ? DateTimeStr(nTime) : "") + "<br>";
1479
1480
1481         //
1482         // From
1483         //
1484         if (wtx.IsCoinBase())
1485         {
1486             strHTML += _("<b>Source:</b> Generated<br>");
1487         }
1488         else if (!wtx.mapValue["from"].empty())
1489         {
1490             // Online transaction
1491             if (!wtx.mapValue["from"].empty())
1492                 strHTML += _("<b>From:</b> ") + HtmlEscape(wtx.mapValue["from"]) + "<br>";
1493         }
1494         else
1495         {
1496             // Offline transaction
1497             if (nNet > 0)
1498             {
1499                 // Credit
1500                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1501                 {
1502                     if (pwalletMain->IsMine(txout))
1503                     {
1504                         CBitcoinAddress address;
1505                         if (ExtractAddress(txout.scriptPubKey, pwalletMain, address))
1506                         {
1507                             if (pwalletMain->mapAddressBook.count(address))
1508                             {
1509                                 strHTML += string() + _("<b>From:</b> ") + _("unknown") + "<br>";
1510                                 strHTML += _("<b>To:</b> ");
1511                                 strHTML += HtmlEscape(address.ToString());
1512                                 if (!pwalletMain->mapAddressBook[address].empty())
1513                                     strHTML += _(" (yours, label: ") + pwalletMain->mapAddressBook[address] + ")";
1514                                 else
1515                                     strHTML += _(" (yours)");
1516                                 strHTML += "<br>";
1517                             }
1518                         }
1519                         break;
1520                     }
1521                 }
1522             }
1523         }
1524
1525
1526         //
1527         // To
1528         //
1529         string strAddress;
1530         if (!wtx.mapValue["to"].empty())
1531         {
1532             // Online transaction
1533             strAddress = wtx.mapValue["to"];
1534             strHTML += _("<b>To:</b> ");
1535             if (pwalletMain->mapAddressBook.count(strAddress) && !pwalletMain->mapAddressBook[strAddress].empty())
1536                 strHTML += pwalletMain->mapAddressBook[strAddress] + " ";
1537             strHTML += HtmlEscape(strAddress) + "<br>";
1538         }
1539
1540
1541         //
1542         // Amount
1543         //
1544         if (wtx.IsCoinBase() && nCredit == 0)
1545         {
1546             //
1547             // Coinbase
1548             //
1549             int64 nUnmatured = 0;
1550             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1551                 nUnmatured += pwalletMain->GetCredit(txout);
1552             strHTML += _("<b>Credit:</b> ");
1553             if (wtx.IsInMainChain())
1554                 strHTML += strprintf(_("(%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
1555             else
1556                 strHTML += _("(not accepted)");
1557             strHTML += "<br>";
1558         }
1559         else if (nNet > 0)
1560         {
1561             //
1562             // Credit
1563             //
1564             strHTML += _("<b>Credit:</b> ") + FormatMoney(nNet) + "<br>";
1565         }
1566         else
1567         {
1568             bool fAllFromMe = true;
1569             BOOST_FOREACH(const CTxIn& txin, wtx.vin)
1570                 fAllFromMe = fAllFromMe && pwalletMain->IsMine(txin);
1571
1572             bool fAllToMe = true;
1573             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1574                 fAllToMe = fAllToMe && pwalletMain->IsMine(txout);
1575
1576             if (fAllFromMe)
1577             {
1578                 //
1579                 // Debit
1580                 //
1581                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1582                 {
1583                     if (pwalletMain->IsMine(txout))
1584                         continue;
1585
1586                     if (wtx.mapValue["to"].empty())
1587                     {
1588                         // Offline transaction
1589                         CBitcoinAddress address;
1590                         if (ExtractAddress(txout.scriptPubKey, pwalletMain, address))
1591                         {
1592                             string strAddress = address.ToString();
1593                             strHTML += _("<b>To:</b> ");
1594                             if (pwalletMain->mapAddressBook.count(address) && !pwalletMain->mapAddressBook[address].empty())
1595                                 strHTML += pwalletMain->mapAddressBook[address] + " ";
1596                             strHTML += strAddress;
1597                             strHTML += "<br>";
1598                         }
1599                     }
1600
1601                     strHTML += _("<b>Debit:</b> ") + FormatMoney(-txout.nValue) + "<br>";
1602                 }
1603
1604                 if (fAllToMe)
1605                 {
1606                     // Payment to self
1607                     int64 nChange = wtx.GetChange();
1608                     int64 nValue = nCredit - nChange;
1609                     strHTML += _("<b>Debit:</b> ") + FormatMoney(-nValue) + "<br>";
1610                     strHTML += _("<b>Credit:</b> ") + FormatMoney(nValue) + "<br>";
1611                 }
1612
1613                 int64 nTxFee = nDebit - wtx.GetValueOut();
1614                 if (nTxFee > 0)
1615                     strHTML += _("<b>Transaction fee:</b> ") + FormatMoney(-nTxFee) + "<br>";
1616             }
1617             else
1618             {
1619                 //
1620                 // Mixed debit transaction
1621                 //
1622                 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
1623                     if (pwalletMain->IsMine(txin))
1624                         strHTML += _("<b>Debit:</b> ") + FormatMoney(-pwalletMain->GetDebit(txin)) + "<br>";
1625                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1626                     if (pwalletMain->IsMine(txout))
1627                         strHTML += _("<b>Credit:</b> ") + FormatMoney(pwalletMain->GetCredit(txout)) + "<br>";
1628             }
1629         }
1630
1631         strHTML += _("<b>Net amount:</b> ") + FormatMoney(nNet, true) + "<br>";
1632
1633
1634         //
1635         // Message
1636         //
1637         if (!wtx.mapValue["message"].empty())
1638             strHTML += string() + "<br><b>" + _("Message:") + "</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
1639         if (!wtx.mapValue["comment"].empty())
1640             strHTML += string() + "<br><b>" + _("Comment:") + "</b><br>" + HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
1641
1642         if (wtx.IsCoinBase())
1643             strHTML += string() + "<br>" + _("Generated coins must wait 120 blocks before they can be spent.  When you generated this block, it was broadcast to the network to be added to the block chain.  If it fails to get into the chain, it will change to \"not accepted\" and not be spendable.  This may occasionally happen if another node generates a block within a few seconds of yours.") + "<br>";
1644
1645
1646         //
1647         // Debug view
1648         //
1649         if (fDebug)
1650         {
1651             strHTML += "<hr><br>debug print<br><br>";
1652             BOOST_FOREACH(const CTxIn& txin, wtx.vin)
1653                 if (pwalletMain->IsMine(txin))
1654                     strHTML += "<b>Debit:</b> " + FormatMoney(-pwalletMain->GetDebit(txin)) + "<br>";
1655             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1656                 if (pwalletMain->IsMine(txout))
1657                     strHTML += "<b>Credit:</b> " + FormatMoney(pwalletMain->GetCredit(txout)) + "<br>";
1658
1659             strHTML += "<br><b>Transaction:</b><br>";
1660             strHTML += HtmlEscape(wtx.ToString(), true);
1661
1662             strHTML += "<br><b>Inputs:</b><br>";
1663             CRITICAL_BLOCK(pwalletMain->cs_wallet)
1664             {
1665                 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
1666                 {
1667                     COutPoint prevout = txin.prevout;
1668                     map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(prevout.hash);
1669                     if (mi != pwalletMain->mapWallet.end())
1670                     {
1671                         const CWalletTx& prev = (*mi).second;
1672                         if (prevout.n < prev.vout.size())
1673                         {
1674                             strHTML += HtmlEscape(prev.ToString(), true);
1675                             strHTML += " &nbsp;&nbsp; " + FormatTxStatus(prev) + ", ";
1676                             strHTML = strHTML + "IsMine=" + (pwalletMain->IsMine(prev.vout[prevout.n]) ? "true" : "false") + "<br>";
1677                         }
1678                     }
1679                 }
1680             }
1681         }
1682
1683
1684
1685         strHTML += "</font></html>";
1686         string(strHTML.begin(), strHTML.end()).swap(strHTML);
1687         m_htmlWin->SetPage(strHTML);
1688         m_buttonOK->SetFocus();
1689     }
1690 }
1691
1692 void CTxDetailsDialog::OnButtonOK(wxCommandEvent& event)
1693 {
1694     EndModal(false);
1695 }
1696
1697
1698
1699
1700
1701
1702 //////////////////////////////////////////////////////////////////////////////
1703 //
1704 // Startup folder
1705 //
1706
1707 #ifdef __WXMSW__
1708 string StartupShortcutPath()
1709 {
1710     return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk";
1711 }
1712
1713 bool GetStartOnSystemStartup()
1714 {
1715     return filesystem::exists(StartupShortcutPath().c_str());
1716 }
1717
1718 void SetStartOnSystemStartup(bool fAutoStart)
1719 {
1720     // If the shortcut exists already, remove it for updating
1721     remove(StartupShortcutPath().c_str());
1722
1723     if (fAutoStart)
1724     {
1725         CoInitialize(NULL);
1726
1727         // Get a pointer to the IShellLink interface.
1728         IShellLink* psl = NULL;
1729         HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
1730                                 CLSCTX_INPROC_SERVER, IID_IShellLink,
1731                                 reinterpret_cast<void**>(&psl));
1732
1733         if (SUCCEEDED(hres))
1734         {
1735             // Get the current executable path
1736             TCHAR pszExePath[MAX_PATH];
1737             GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
1738
1739             // Set the path to the shortcut target
1740             psl->SetPath(pszExePath);
1741             PathRemoveFileSpec(pszExePath);
1742             psl->SetWorkingDirectory(pszExePath);
1743             psl->SetShowCmd(SW_SHOWMINNOACTIVE);
1744
1745             // Query IShellLink for the IPersistFile interface for
1746             // saving the shortcut in persistent storage.
1747             IPersistFile* ppf = NULL;
1748             hres = psl->QueryInterface(IID_IPersistFile,
1749                                        reinterpret_cast<void**>(&ppf));
1750             if (SUCCEEDED(hres))
1751             {
1752                 WCHAR pwsz[MAX_PATH];
1753                 // Ensure that the string is ANSI.
1754                 MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().c_str(), -1, pwsz, MAX_PATH);
1755                 // Save the link by calling IPersistFile::Save.
1756                 hres = ppf->Save(pwsz, TRUE);
1757                 ppf->Release();
1758             }
1759             psl->Release();
1760         }
1761         CoUninitialize();
1762     }
1763 }
1764
1765 #elif defined(__WXGTK__)
1766
1767 // Follow the Desktop Application Autostart Spec:
1768 //  http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
1769
1770 boost::filesystem::path GetAutostartDir()
1771 {
1772     namespace fs = boost::filesystem;
1773
1774     char* pszConfigHome = getenv("XDG_CONFIG_HOME");
1775     if (pszConfigHome) return fs::path(pszConfigHome) / fs::path("autostart");
1776     char* pszHome = getenv("HOME");
1777     if (pszHome) return fs::path(pszHome) / fs::path(".config/autostart");
1778     return fs::path();
1779 }
1780
1781 boost::filesystem::path GetAutostartFilePath()
1782 {
1783     return GetAutostartDir() / boost::filesystem::path("ppcoin.desktop");
1784 }
1785
1786 bool GetStartOnSystemStartup()
1787 {
1788     boost::filesystem::ifstream optionFile(GetAutostartFilePath());
1789     if (!optionFile.good())
1790         return false;
1791     // Scan through file for "Hidden=true":
1792     string line;
1793     while (!optionFile.eof())
1794     {
1795         getline(optionFile, line);
1796         if (line.find("Hidden") != string::npos &&
1797             line.find("true") != string::npos)
1798             return false;
1799     }
1800     optionFile.close();
1801
1802     return true;
1803 }
1804
1805 void SetStartOnSystemStartup(bool fAutoStart)
1806 {
1807     if (!fAutoStart)
1808     {
1809 #if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3
1810         unlink(GetAutostartFilePath().string().c_str());
1811 #else
1812         unlink(GetAutostartFilePath().native_file_string().c_str());
1813 #endif
1814     }
1815     else
1816     {
1817         char pszExePath[MAX_PATH+1];
1818         memset(pszExePath, 0, sizeof(pszExePath));
1819         if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
1820             return;
1821
1822         boost::filesystem::create_directories(GetAutostartDir());
1823
1824         boost::filesystem::ofstream optionFile(GetAutostartFilePath(), ios_base::out|ios_base::trunc);
1825         if (!optionFile.good())
1826         {
1827             wxMessageBox(_("Cannot write autostart/ppcoin.desktop file"), "Bitcoin");
1828             return;
1829         }
1830         // Write a ppcoin.desktop file to the autostart directory:
1831         optionFile << "[Desktop Entry]\n";
1832         optionFile << "Type=Application\n";
1833         optionFile << "Name=Bitcoin\n";
1834         optionFile << "Exec=" << pszExePath << "\n";
1835         optionFile << "Terminal=false\n";
1836         optionFile << "Hidden=false\n";
1837         optionFile.close();
1838     }
1839 }
1840 #else
1841
1842 // TODO: OSX startup stuff; see:
1843 // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html
1844
1845 bool GetStartOnSystemStartup() { return false; }
1846 void SetStartOnSystemStartup(bool fAutoStart) { }
1847
1848 #endif
1849
1850
1851
1852
1853
1854
1855 //////////////////////////////////////////////////////////////////////////////
1856 //
1857 // COptionsDialog
1858 //
1859
1860 COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)
1861 {
1862     // Set up list box of page choices
1863     m_listBox->Append(_("Main"));
1864     //m_listBox->Append(_("Test 2"));
1865     m_listBox->SetSelection(0);
1866     SelectPage(0);
1867 #ifndef __WXMSW__
1868     SetSize(1.0 * GetSize().GetWidth(), 1.2 * GetSize().GetHeight());
1869 #else
1870     SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
1871 #endif
1872 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
1873     m_checkBoxStartOnSystemStartup->SetLabel(_("&Start Bitcoin on window system startup"));
1874     if (!GetBoolArg("-minimizetotray"))
1875     {
1876         // Minimize to tray is just too buggy on Linux
1877         fMinimizeToTray = false;
1878         m_checkBoxMinimizeToTray->SetValue(false);
1879         m_checkBoxMinimizeToTray->Enable(false);
1880         m_checkBoxMinimizeOnClose->SetLabel(_("&Minimize on close"));
1881     }
1882 #endif
1883 #ifdef __WXMAC_OSX__
1884     m_checkBoxStartOnSystemStartup->Enable(false); // not implemented yet
1885 #endif
1886
1887     // Init values
1888     m_textCtrlTransactionFee->SetValue(FormatMoney(nTransactionFee));
1889     m_checkBoxStartOnSystemStartup->SetValue(fTmpStartOnSystemStartup = GetStartOnSystemStartup());
1890     m_checkBoxMinimizeToTray->SetValue(fMinimizeToTray);
1891     m_checkBoxMinimizeOnClose->SetValue(fMinimizeOnClose);
1892     if (fHaveUPnP)
1893         m_checkBoxUseUPnP->SetValue(fUseUPnP);
1894     else
1895         m_checkBoxUseUPnP->Enable(false);
1896     m_checkBoxUseProxy->SetValue(fUseProxy);
1897     m_textCtrlProxyIP->Enable(fUseProxy);
1898     m_textCtrlProxyPort->Enable(fUseProxy);
1899     m_staticTextProxyIP->Enable(fUseProxy);
1900     m_staticTextProxyPort->Enable(fUseProxy);
1901     m_textCtrlProxyIP->SetValue(addrProxy.ToStringIP());
1902     m_textCtrlProxyPort->SetValue(addrProxy.ToStringPort());
1903
1904     m_buttonOK->SetFocus();
1905 }
1906
1907 void COptionsDialog::SelectPage(int nPage)
1908 {
1909     m_panelMain->Show(nPage == 0);
1910     m_panelTest2->Show(nPage == 1);
1911
1912     m_scrolledWindow->Layout();
1913     m_scrolledWindow->SetScrollbars(0, 0, 0, 0, 0, 0);
1914 }
1915
1916 void COptionsDialog::OnListBox(wxCommandEvent& event)
1917 {
1918     SelectPage(event.GetSelection());
1919 }
1920
1921 void COptionsDialog::OnKillFocusTransactionFee(wxFocusEvent& event)
1922 {
1923     event.Skip();
1924     int64 nTmp = nTransactionFee;
1925     ParseMoney(m_textCtrlTransactionFee->GetValue(), nTmp);
1926     m_textCtrlTransactionFee->SetValue(FormatMoney(nTmp));
1927 }
1928
1929 void COptionsDialog::OnCheckBoxUseProxy(wxCommandEvent& event)
1930 {
1931     m_textCtrlProxyIP->Enable(event.IsChecked());
1932     m_textCtrlProxyPort->Enable(event.IsChecked());
1933     m_staticTextProxyIP->Enable(event.IsChecked());
1934     m_staticTextProxyPort->Enable(event.IsChecked());
1935 }
1936
1937 CAddress COptionsDialog::GetProxyAddr()
1938 {
1939     // Be careful about byte order, addr.ip and addr.port are big endian
1940     CAddress addr(m_textCtrlProxyIP->GetValue() + ":" + m_textCtrlProxyPort->GetValue());
1941     if (addr.ip == INADDR_NONE)
1942         addr.ip = addrProxy.ip;
1943     int nPort = atoi(m_textCtrlProxyPort->GetValue());
1944     addr.port = htons(nPort);
1945     if (nPort <= 0 || nPort > USHRT_MAX)
1946         addr.port = addrProxy.port;
1947     return addr;
1948 }
1949
1950 void COptionsDialog::OnKillFocusProxy(wxFocusEvent& event)
1951 {
1952     event.Skip();
1953     m_textCtrlProxyIP->SetValue(GetProxyAddr().ToStringIP());
1954     m_textCtrlProxyPort->SetValue(GetProxyAddr().ToStringPort());
1955 }
1956
1957
1958 void COptionsDialog::OnButtonOK(wxCommandEvent& event)
1959 {
1960     OnButtonApply(event);
1961     EndModal(false);
1962 }
1963
1964 void COptionsDialog::OnButtonCancel(wxCommandEvent& event)
1965 {
1966     EndModal(false);
1967 }
1968
1969 void COptionsDialog::OnButtonApply(wxCommandEvent& event)
1970 {
1971     CWalletDB walletdb(pwalletMain->strWalletFile);
1972
1973     int64 nPrevTransactionFee = nTransactionFee;
1974     if (ParseMoney(m_textCtrlTransactionFee->GetValue(), nTransactionFee) && nTransactionFee != nPrevTransactionFee)
1975         walletdb.WriteSetting("nTransactionFee", nTransactionFee);
1976
1977     if (fTmpStartOnSystemStartup != m_checkBoxStartOnSystemStartup->GetValue())
1978     {
1979         fTmpStartOnSystemStartup = m_checkBoxStartOnSystemStartup->GetValue();
1980         SetStartOnSystemStartup(fTmpStartOnSystemStartup);
1981     }
1982
1983     if (fMinimizeToTray != m_checkBoxMinimizeToTray->GetValue())
1984     {
1985         fMinimizeToTray = m_checkBoxMinimizeToTray->GetValue();
1986         walletdb.WriteSetting("fMinimizeToTray", fMinimizeToTray);
1987         ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
1988     }
1989
1990     if (fMinimizeOnClose != m_checkBoxMinimizeOnClose->GetValue())
1991     {
1992         fMinimizeOnClose = m_checkBoxMinimizeOnClose->GetValue();
1993         walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);
1994     }
1995
1996     if (fHaveUPnP && fUseUPnP != m_checkBoxUseUPnP->GetValue())
1997     {
1998         fUseUPnP = m_checkBoxUseUPnP->GetValue();
1999         walletdb.WriteSetting("fUseUPnP", fUseUPnP);
2000         MapPort(fUseUPnP);
2001     }
2002
2003     fUseProxy = m_checkBoxUseProxy->GetValue();
2004     walletdb.WriteSetting("fUseProxy", fUseProxy);
2005
2006     addrProxy = GetProxyAddr();
2007     walletdb.WriteSetting("addrProxy", addrProxy);
2008 }
2009
2010
2011
2012
2013
2014
2015 //////////////////////////////////////////////////////////////////////////////
2016 //
2017 // CAboutDialog
2018 //
2019
2020 CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)
2021 {
2022     m_staticTextVersion->SetLabel(strprintf(_("version %s"), FormatFullVersion().c_str()));
2023
2024     // Change (c) into UTF-8 or ANSI copyright symbol
2025     wxString str = m_staticTextMain->GetLabel();
2026 #if wxUSE_UNICODE
2027     str.Replace("(c)", wxString::FromUTF8("\xC2\xA9"));
2028 #else
2029     str.Replace("(c)", "\xA9");
2030 #endif
2031     m_staticTextMain->SetLabel(str);
2032 #ifndef __WXMSW__
2033     // Resize on Linux to make the window fit the text.
2034     // The text was wrapped manually rather than using the Wrap setting because
2035     // the wrap would be too small on Linux and it can't be changed at this point.
2036     wxFont fontTmp = m_staticTextMain->GetFont();
2037     if (fontTmp.GetPointSize() > 8);
2038         fontTmp.SetPointSize(8);
2039     m_staticTextMain->SetFont(fontTmp);
2040     SetSize(GetSize().GetWidth() + 44, GetSize().GetHeight() + 10);
2041 #else
2042     SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
2043 #endif
2044 }
2045
2046 void CAboutDialog::OnButtonOK(wxCommandEvent& event)
2047 {
2048     EndModal(false);
2049 }
2050
2051
2052
2053
2054
2055
2056 //////////////////////////////////////////////////////////////////////////////
2057 //
2058 // CSendDialog
2059 //
2060
2061 CSendDialog::CSendDialog(wxWindow* parent, const wxString& strAddress) : CSendDialogBase(parent)
2062 {
2063     // Init
2064     m_textCtrlAddress->SetValue(strAddress);
2065     m_choiceTransferType->SetSelection(0);
2066     m_bitmapCheckMark->Show(false);
2067     fEnabledPrev = true;
2068     m_textCtrlAddress->SetFocus();
2069     
2070     //// todo: should add a display of your balance for convenience
2071 #ifndef __WXMSW__
2072     wxFont fontTmp = m_staticTextInstructions->GetFont();
2073     if (fontTmp.GetPointSize() > 9);
2074         fontTmp.SetPointSize(9);
2075     m_staticTextInstructions->SetFont(fontTmp);
2076     SetSize(725, 180);
2077 #else
2078     SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
2079 #endif
2080     
2081     // Set Icon
2082     if (nScaleX == 1.0 && nScaleY == 1.0) // We don't have icons of the proper size otherwise
2083     {
2084         wxIcon iconSend;
2085         iconSend.CopyFromBitmap(wxBitmap(send16noshadow_xpm));
2086         SetIcon(iconSend);
2087     }
2088 #ifdef __WXMSW__
2089     else
2090         SetIcon(wxICON(bitcoin));
2091 #endif
2092
2093     // Fixup the tab order
2094     m_buttonPaste->MoveAfterInTabOrder(m_buttonCancel);
2095     m_buttonAddress->MoveAfterInTabOrder(m_buttonPaste);
2096     this->Layout();
2097 }
2098
2099 void CSendDialog::OnKillFocusAmount(wxFocusEvent& event)
2100 {
2101     // Reformat the amount
2102     event.Skip();
2103     if (m_textCtrlAmount->GetValue().Trim().empty())
2104         return;
2105     int64 nTmp;
2106     if (ParseMoney(m_textCtrlAmount->GetValue(), nTmp))
2107         m_textCtrlAmount->SetValue(FormatMoney(nTmp));
2108 }
2109
2110 void CSendDialog::OnButtonAddressBook(wxCommandEvent& event)
2111 {
2112     // Open address book
2113     CAddressBookDialog dialog(this, m_textCtrlAddress->GetValue(), CAddressBookDialog::SENDING, true);
2114     if (dialog.ShowModal())
2115         m_textCtrlAddress->SetValue(dialog.GetSelectedAddress());
2116 }
2117
2118 void CSendDialog::OnButtonPaste(wxCommandEvent& event)
2119 {
2120     // Copy clipboard to address box
2121     if (wxTheClipboard->Open())
2122     {
2123         if (wxTheClipboard->IsSupported(wxDF_TEXT))
2124         {
2125             wxTextDataObject data;
2126             wxTheClipboard->GetData(data);
2127             m_textCtrlAddress->SetValue(data.GetText());
2128         }
2129         wxTheClipboard->Close();
2130     }
2131 }
2132
2133 void CSendDialog::OnButtonSend(wxCommandEvent& event)
2134 {
2135     static CCriticalSection cs_sendlock;
2136     TRY_CRITICAL_BLOCK(cs_sendlock)
2137     {
2138         CWalletTx wtx;
2139         string strAddress = (string)m_textCtrlAddress->GetValue();
2140
2141         // Parse amount
2142         int64 nValue = 0;
2143         if (!ParseMoney(m_textCtrlAmount->GetValue(), nValue) || nValue <= 0)
2144         {
2145             wxMessageBox(_("Error in amount  "), _("Send Coins"));
2146             return;
2147         }
2148         if (nValue > pwalletMain->GetBalance())
2149         {
2150             wxMessageBox(_("Amount exceeds your balance  "), _("Send Coins"));
2151             return;
2152         }
2153         if (nValue + nTransactionFee > pwalletMain->GetBalance())
2154         {
2155             wxMessageBox(string(_("Total exceeds your balance when the ")) + FormatMoney(nTransactionFee) + _(" transaction fee is included  "), _("Send Coins"));
2156             return;
2157         }
2158
2159         // Parse bitcoin address
2160         CBitcoinAddress address(strAddress);
2161         bool fBitcoinAddress = address.IsValid();
2162
2163         if (fBitcoinAddress)
2164         {
2165             bool fWasLocked = pwalletMain->IsLocked();
2166             if (!GetWalletPassphrase())
2167                 return;
2168
2169             string strError;
2170             CRITICAL_BLOCK(cs_main)
2171             CRITICAL_BLOCK(pwalletMain->cs_wallet)
2172             {
2173                 // Send to bitcoin address
2174                 CScript scriptPubKey;
2175                 scriptPubKey.SetBitcoinAddress(address);
2176
2177                 strError = pwalletMain->SendMoney(scriptPubKey, nValue, wtx, true);
2178             }
2179             if (strError == "")
2180             {
2181                 pframeMain->RefreshListCtrl();
2182                 wxMessageBox(_("Payment sent  "), _("Sending..."));
2183             }
2184             else if (strError == "ABORTED")
2185             {
2186                 if (fWasLocked)
2187                     pwalletMain->Lock();
2188                 return; // leave send dialog open
2189             }
2190             else
2191             {
2192                 wxMessageBox(strError + "  ", _("Sending..."));
2193                 EndModal(false);
2194                 if (fWasLocked)
2195                     pwalletMain->Lock();
2196                 return;
2197             }
2198
2199             if (fWasLocked)
2200                 pwalletMain->Lock();
2201         }
2202         else
2203         {
2204             // Parse IP address
2205             CAddress addr(strAddress);
2206             if (!addr.IsValid())
2207             {
2208                 wxMessageBox(_("Invalid address  "), _("Send Coins"));
2209                 return;
2210             }
2211
2212             // Message
2213             wtx.mapValue["to"] = strAddress;
2214
2215             // Send to IP address
2216             CSendingDialog* pdialog = new CSendingDialog(this, addr, nValue, wtx);
2217             if (!pdialog->ShowModal())
2218                 return;
2219         }
2220
2221         CRITICAL_BLOCK(pwalletMain->cs_wallet)
2222             if (!pwalletMain->mapAddressBook.count(address))
2223                 pwalletMain->SetAddressBookName(strAddress, "");
2224
2225         EndModal(true);
2226     }
2227 }
2228
2229 void CSendDialog::OnButtonCancel(wxCommandEvent& event)
2230 {
2231     // Cancel
2232     EndModal(false);
2233 }
2234
2235
2236
2237
2238
2239
2240 //////////////////////////////////////////////////////////////////////////////
2241 //
2242 // CSendingDialog
2243 //
2244
2245 CSendingDialog::CSendingDialog(wxWindow* parent, const CAddress& addrIn, int64 nPriceIn, const CWalletTx& wtxIn) : CSendingDialogBase(NULL) // we have to give null so parent can't destroy us
2246 {
2247     addr = addrIn;
2248     nPrice = nPriceIn;
2249     wtx = wtxIn;
2250     start = wxDateTime::UNow();
2251     memset(pszStatus, 0, sizeof(pszStatus));
2252     fCanCancel = true;
2253     fAbort = false;
2254     fSuccess = false;
2255     fUIDone = false;
2256     fWorkDone = false;
2257 #ifndef __WXMSW__
2258     SetSize(1.2 * GetSize().GetWidth(), 1.08 * GetSize().GetHeight());
2259 #else
2260     SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
2261 #endif
2262
2263     SetTitle(strprintf(_("Sending %s to %s"), FormatMoney(nPrice).c_str(), wtx.mapValue["to"].c_str()));
2264     m_textCtrlStatus->SetValue("");
2265
2266     CreateThread(SendingDialogStartTransfer, this);
2267 }
2268
2269 CSendingDialog::~CSendingDialog()
2270 {
2271     printf("~CSendingDialog()\n");
2272 }
2273
2274 void CSendingDialog::Close()
2275 {
2276     // Last one out turn out the lights.
2277     // fWorkDone signals that work side is done and UI thread should call destroy.
2278     // fUIDone signals that UI window has closed and work thread should call destroy.
2279     // This allows the window to disappear and end modality when cancelled
2280     // without making the user wait for ConnectNode to return.  The dialog object
2281     // hangs around in the background until the work thread exits.
2282     if (IsModal())
2283         EndModal(fSuccess);
2284     else
2285         Show(false);
2286     if (fWorkDone)
2287         Destroy();
2288     else
2289         fUIDone = true;
2290 }
2291
2292 void CSendingDialog::OnClose(wxCloseEvent& event)
2293 {
2294     if (!event.CanVeto() || fWorkDone || fAbort || !fCanCancel)
2295     {
2296         Close();
2297     }
2298     else
2299     {
2300         event.Veto();
2301         wxCommandEvent cmdevent;
2302         OnButtonCancel(cmdevent);
2303     }
2304 }
2305
2306 void CSendingDialog::OnButtonOK(wxCommandEvent& event)
2307 {
2308     if (fWorkDone)
2309         Close();
2310 }
2311
2312 void CSendingDialog::OnButtonCancel(wxCommandEvent& event)
2313 {
2314     if (fCanCancel)
2315         fAbort = true;
2316 }
2317
2318 void CSendingDialog::OnPaint(wxPaintEvent& event)
2319 {
2320     event.Skip();
2321     if (strlen(pszStatus) > 130)
2322         m_textCtrlStatus->SetValue(string("\n") + pszStatus);
2323     else
2324         m_textCtrlStatus->SetValue(string("\n\n") + pszStatus);
2325     m_staticTextSending->SetFocus();
2326     if (!fCanCancel)
2327         m_buttonCancel->Enable(false);
2328     if (fWorkDone)
2329     {
2330         m_buttonOK->Enable(true);
2331         m_buttonOK->SetFocus();
2332         m_buttonCancel->Enable(false);
2333     }
2334     if (fAbort && fCanCancel && IsShown())
2335     {
2336         strcpy(pszStatus, _("CANCELLED"));
2337         m_buttonOK->Enable(true);
2338         m_buttonOK->SetFocus();
2339         m_buttonCancel->Enable(false);
2340         m_buttonCancel->SetLabel(_("Cancelled"));
2341         Close();
2342         wxMessageBox(_("Transfer cancelled  "), _("Sending..."), wxOK, this);
2343     }
2344 }
2345
2346
2347 //
2348 // Everything from here on is not in the UI thread and must only communicate
2349 // with the rest of the dialog through variables and calling repaint.
2350 //
2351
2352 void CSendingDialog::Repaint()
2353 {
2354     Refresh();
2355     wxPaintEvent event;
2356     GetEventHandler()->AddPendingEvent(event);
2357 }
2358
2359 bool CSendingDialog::Status()
2360 {
2361     if (fUIDone)
2362     {
2363         Destroy();
2364         return false;
2365     }
2366     if (fAbort && fCanCancel)
2367     {
2368         memset(pszStatus, 0, 10);
2369         strcpy(pszStatus, _("CANCELLED"));
2370         Repaint();
2371         fWorkDone = true;
2372         return false;
2373     }
2374     return true;
2375 }
2376
2377 bool CSendingDialog::Status(const string& str)
2378 {
2379     if (!Status())
2380         return false;
2381
2382     // This can be read by the UI thread at any time,
2383     // so copy in a way that can be read cleanly at all times.
2384     memset(pszStatus, 0, min(str.size()+1, sizeof(pszStatus)));
2385     strlcpy(pszStatus, str.c_str(), sizeof(pszStatus));
2386
2387     Repaint();
2388     return true;
2389 }
2390
2391 bool CSendingDialog::Error(const string& str)
2392 {
2393     fCanCancel = false;
2394     fWorkDone = true;
2395     Status(string(_("Error: ")) + str);
2396     return false;
2397 }
2398
2399 void SendingDialogStartTransfer(void* parg)
2400 {
2401     ((CSendingDialog*)parg)->StartTransfer();
2402 }
2403
2404 void CSendingDialog::StartTransfer()
2405 {
2406     // Make sure we have enough money
2407     if (nPrice + nTransactionFee > pwalletMain->GetBalance())
2408     {
2409         Error(_("Insufficient funds"));
2410         return;
2411     }
2412
2413     // We may have connected already for product details
2414     if (!Status(_("Connecting...")))
2415         return;
2416     CNode* pnode = ConnectNode(addr, 15 * 60);
2417     if (!pnode)
2418     {
2419         Error(_("Unable to connect"));
2420         return;
2421     }
2422
2423     // Send order to seller, with response going to OnReply2 via event handler
2424     if (!Status(_("Requesting public key...")))
2425         return;
2426     pnode->PushRequest("checkorder", wtx, SendingDialogOnReply2, this);
2427 }
2428
2429 void SendingDialogOnReply2(void* parg, CDataStream& vRecv)
2430 {
2431     ((CSendingDialog*)parg)->OnReply2(vRecv);
2432 }
2433
2434 void CSendingDialog::OnReply2(CDataStream& vRecv)
2435 {
2436     if (!Status(_("Received public key...")))
2437         return;
2438
2439     CScript scriptPubKey;
2440     int nRet;
2441     try
2442     {
2443         vRecv >> nRet;
2444         if (nRet > 0)
2445         {
2446             string strMessage;
2447             if (!vRecv.empty())
2448                 vRecv >> strMessage;
2449             if (nRet == 2)
2450                 Error(_("Recipient is not accepting transactions sent by IP address"));
2451             else
2452                 Error(_("Transfer was not accepted"));
2453             //// todo: enlarge the window and enable a hidden white box to put seller's message
2454             return;
2455         }
2456         vRecv >> scriptPubKey;
2457     }
2458     catch (...)
2459     {
2460         //// what do we want to do about this?
2461         Error(_("Invalid response received"));
2462         return;
2463     }
2464
2465     // Pause to give the user a chance to cancel
2466     while (wxDateTime::UNow() < start + wxTimeSpan(0, 0, 0, 2 * 1000))
2467     {
2468         Sleep(200);
2469         if (!Status())
2470             return;
2471     }
2472
2473     // Pay
2474     if (!Status(_("Creating transaction...")))
2475         return;
2476     if (nPrice + nTransactionFee > pwalletMain->GetBalance())
2477     {
2478         Error(_("Insufficient funds"));
2479         return;
2480     }
2481
2482     CReserveKey reservekey(pwalletMain);
2483     int64 nFeeRequired;
2484     bool fWasLocked = pwalletMain->IsLocked();
2485     if (!GetWalletPassphrase())
2486         return;
2487
2488     bool fTxCreated = false;
2489     CRITICAL_BLOCK(cs_main)
2490     CRITICAL_BLOCK(pwalletMain->cs_wallet)
2491     {
2492         fTxCreated = pwalletMain->CreateTransaction(scriptPubKey, nPrice, wtx, reservekey, nFeeRequired);
2493     }
2494     if (!fTxCreated)
2495     {
2496         if (nPrice + nFeeRequired > pwalletMain->GetBalance())
2497             Error(strprintf(_("This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds"), FormatMoney(nFeeRequired).c_str()));
2498         else
2499             Error(_("Transaction creation failed"));
2500         return;
2501     }
2502
2503     if (fWasLocked)
2504         pwalletMain->Lock();
2505
2506     // Transaction fee
2507     if (!ThreadSafeAskFee(nFeeRequired, _("Sending..."), this))
2508     {
2509         Error(_("Transaction aborted"));
2510         return;
2511     }
2512
2513     // Make sure we're still connected
2514     CNode* pnode = ConnectNode(addr, 2 * 60 * 60);
2515     if (!pnode)
2516     {
2517         Error(_("Lost connection, transaction cancelled"));
2518         return;
2519     }
2520
2521     // Last chance to cancel
2522     Sleep(50);
2523     if (!Status())
2524         return;
2525     fCanCancel = false;
2526     if (fAbort)
2527     {
2528         fCanCancel = true;
2529         if (!Status())
2530             return;
2531         fCanCancel = false;
2532     }
2533     if (!Status(_("Sending payment...")))
2534         return;
2535
2536     // Commit
2537     bool fTxCommitted = false;
2538     CRITICAL_BLOCK(cs_main)
2539     CRITICAL_BLOCK(pwalletMain->cs_wallet)
2540     {
2541         fTxCommitted = pwalletMain->CommitTransaction(wtx, reservekey);
2542     }
2543     if (!fTxCommitted)
2544     {
2545         Error(_("The transaction was rejected.  This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."));
2546         return;
2547     }
2548
2549     // Send payment tx to seller, with response going to OnReply3 via event handler
2550     CWalletTx wtxSend = wtx;
2551     wtxSend.fFromMe = false;
2552     pnode->PushRequest("submitorder", wtxSend, SendingDialogOnReply3, this);
2553
2554     Status(_("Waiting for confirmation..."));
2555     MainFrameRepaint();
2556 }
2557
2558 void SendingDialogOnReply3(void* parg, CDataStream& vRecv)
2559 {
2560     ((CSendingDialog*)parg)->OnReply3(vRecv);
2561 }
2562
2563 void CSendingDialog::OnReply3(CDataStream& vRecv)
2564 {
2565     int nRet;
2566     try
2567     {
2568         vRecv >> nRet;
2569         if (nRet > 0)
2570         {
2571             Error(_("The payment was sent, but the recipient was unable to verify it.\n"
2572                     "The transaction is recorded and will credit to the recipient,\n"
2573                     "but the comment information will be blank."));
2574             return;
2575         }
2576     }
2577     catch (...)
2578     {
2579         //// what do we want to do about this?
2580         Error(_("Payment was sent, but an invalid response was received"));
2581         return;
2582     }
2583
2584     fSuccess = true;
2585     fWorkDone = true;
2586     Status(_("Payment completed"));
2587 }
2588
2589
2590
2591
2592
2593
2594 //////////////////////////////////////////////////////////////////////////////
2595 //
2596 // CAddressBookDialog
2597 //
2598
2599 CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInitSelected, int nPageIn, bool fDuringSendIn) : CAddressBookDialogBase(parent)
2600 {
2601 #ifdef __WXMSW__
2602     SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
2603 #endif
2604
2605     // Set initially selected page
2606     wxNotebookEvent event;
2607     event.SetSelection(nPageIn);
2608     OnNotebookPageChanged(event);
2609     m_notebook->ChangeSelection(nPageIn);
2610
2611     fDuringSend = fDuringSendIn;
2612     if (!fDuringSend)
2613         m_buttonCancel->Show(false);
2614
2615     // Set Icon
2616     if (nScaleX == 1.0 && nScaleY == 1.0) // We don't have icons of the proper size otherwise
2617     {
2618         wxIcon iconAddressBook;
2619         iconAddressBook.CopyFromBitmap(wxBitmap(addressbook16_xpm));
2620         SetIcon(iconAddressBook);
2621     }
2622 #ifdef __WXMSW__
2623     else
2624         SetIcon(wxICON(bitcoin));
2625 #endif
2626
2627     // Init column headers
2628     m_listCtrlSending->InsertColumn(0, _("Name"), wxLIST_FORMAT_LEFT, 200);
2629     m_listCtrlSending->InsertColumn(1, _("Address"), wxLIST_FORMAT_LEFT, 350);
2630     m_listCtrlSending->SetFocus();
2631     m_listCtrlReceiving->InsertColumn(0, _("Label"), wxLIST_FORMAT_LEFT, 200);
2632     m_listCtrlReceiving->InsertColumn(1, _("Bitcoin Address"), wxLIST_FORMAT_LEFT, 350);
2633     m_listCtrlReceiving->SetFocus();
2634
2635     // Fill listctrl with address book data
2636     CRITICAL_BLOCK(pwalletMain->cs_wallet)
2637     {
2638         string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue();
2639         BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
2640         {
2641             const CBitcoinAddress& address = item.first;
2642             string strName = item.second;
2643             bool fMine = pwalletMain->HaveKey(address);
2644             wxListCtrl* plistCtrl = fMine ? m_listCtrlReceiving : m_listCtrlSending;
2645             int nIndex = InsertLine(plistCtrl, strName, address.ToString());
2646             if (address.ToString() == (fMine ? strDefaultReceiving : string(strInitSelected)))
2647                 plistCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
2648         }
2649     }
2650 }
2651
2652 wxString CAddressBookDialog::GetSelectedAddress()
2653 {
2654     int nIndex = GetSelection(m_listCtrl);
2655     if (nIndex == -1)
2656         return "";
2657     return GetItemText(m_listCtrl, nIndex, 1);
2658 }
2659
2660 wxString CAddressBookDialog::GetSelectedSendingAddress()
2661 {
2662     int nIndex = GetSelection(m_listCtrlSending);
2663     if (nIndex == -1)
2664         return "";
2665     return GetItemText(m_listCtrlSending, nIndex, 1);
2666 }
2667
2668 wxString CAddressBookDialog::GetSelectedReceivingAddress()
2669 {
2670     int nIndex = GetSelection(m_listCtrlReceiving);
2671     if (nIndex == -1)
2672         return "";
2673     return GetItemText(m_listCtrlReceiving, nIndex, 1);
2674 }
2675
2676 void CAddressBookDialog::OnNotebookPageChanged(wxNotebookEvent& event)
2677 {
2678     event.Skip();
2679     nPage = event.GetSelection();
2680     if (nPage == SENDING)
2681         m_listCtrl = m_listCtrlSending;
2682     else if (nPage == RECEIVING)
2683         m_listCtrl = m_listCtrlReceiving;
2684     m_buttonDelete->Show(nPage == SENDING);
2685     m_buttonCopy->Show(nPage == RECEIVING);
2686     this->Layout();
2687     m_listCtrl->SetFocus();
2688 }
2689
2690 void CAddressBookDialog::OnListEndLabelEdit(wxListEvent& event)
2691 {
2692     // Update address book with edited name
2693     event.Skip();
2694     if (event.IsEditCancelled())
2695         return;
2696     string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1);
2697     CRITICAL_BLOCK(pwalletMain->cs_wallet)
2698         pwalletMain->SetAddressBookName(strAddress, string(event.GetText()));
2699     pframeMain->RefreshListCtrl();
2700 }
2701
2702 void CAddressBookDialog::OnListItemSelected(wxListEvent& event)
2703 {
2704     event.Skip();
2705     if (nPage == RECEIVING)
2706         SetDefaultReceivingAddress((string)GetSelectedReceivingAddress());
2707 }
2708
2709 void CAddressBookDialog::OnListItemActivated(wxListEvent& event)
2710 {
2711     event.Skip();
2712     if (fDuringSend)
2713     {
2714         // Doubleclick returns selection
2715         EndModal(GetSelectedAddress() != "" ? 2 : 0);
2716         return;
2717     }
2718
2719     // Doubleclick edits item
2720     wxCommandEvent event2;
2721     OnButtonEdit(event2);
2722 }
2723
2724 void CAddressBookDialog::OnButtonDelete(wxCommandEvent& event)
2725 {
2726     if (nPage != SENDING)
2727         return;
2728     for (int nIndex = m_listCtrl->GetItemCount()-1; nIndex >= 0; nIndex--)
2729     {
2730         if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED))
2731         {
2732             string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
2733             CRITICAL_BLOCK(pwalletMain->cs_wallet)
2734                 pwalletMain->DelAddressBookName(strAddress);
2735             m_listCtrl->DeleteItem(nIndex);
2736         }
2737     }
2738     pframeMain->RefreshListCtrl();
2739 }
2740
2741 void CAddressBookDialog::OnButtonCopy(wxCommandEvent& event)
2742 {
2743     // Copy address box to clipboard
2744     if (wxTheClipboard->Open())
2745     {
2746         wxTheClipboard->SetData(new wxTextDataObject(GetSelectedAddress()));
2747         wxTheClipboard->Close();
2748     }
2749 }
2750
2751 bool CAddressBookDialog::CheckIfMine(const string& strAddress, const string& strTitle)
2752 {
2753     CBitcoinAddress address(strAddress);
2754     bool fMine = address.IsValid() && pwalletMain->HaveKey(address);
2755     if (fMine)
2756         wxMessageBox(_("This is one of your own addresses for receiving payments and cannot be entered in the address book.  "), strTitle);
2757     return fMine;
2758 }
2759
2760 void CAddressBookDialog::OnButtonEdit(wxCommandEvent& event)
2761 {
2762     int nIndex = GetSelection(m_listCtrl);
2763     if (nIndex == -1)
2764         return;
2765     string strName = (string)m_listCtrl->GetItemText(nIndex);
2766     string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
2767     string strAddressOrg = strAddress;
2768
2769     if (nPage == SENDING)
2770     {
2771         // Ask name and address
2772         do
2773         {
2774             CGetTextFromUserDialog dialog(this, _("Edit Address"), _("Name"), strName, _("Address"), strAddress);
2775             if (!dialog.ShowModal())
2776                 return;
2777             strName = dialog.GetValue1();
2778             strAddress = dialog.GetValue2();
2779         }
2780         while (CheckIfMine(strAddress, _("Edit Address")));
2781
2782     }
2783     else if (nPage == RECEIVING)
2784     {
2785         // Ask name
2786         CGetTextFromUserDialog dialog(this, _("Edit Address Label"), _("Label"), strName);
2787         if (!dialog.ShowModal())
2788             return;
2789         strName = dialog.GetValue();
2790     }
2791
2792     // Write back
2793     CRITICAL_BLOCK(pwalletMain->cs_wallet)
2794     {
2795         if (strAddress != strAddressOrg)
2796             pwalletMain->DelAddressBookName(strAddressOrg);
2797         pwalletMain->SetAddressBookName(strAddress, strName);
2798     }
2799     m_listCtrl->SetItem(nIndex, 1, strAddress);
2800     m_listCtrl->SetItemText(nIndex, strName);
2801     pframeMain->RefreshListCtrl();
2802 }
2803
2804 void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
2805 {
2806     string strName;
2807     string strAddress;
2808
2809     if (nPage == SENDING)
2810     {
2811         // Ask name and address
2812         do
2813         {
2814             CGetTextFromUserDialog dialog(this, _("Add Address"), _("Name"), strName, _("Address"), strAddress);
2815             if (!dialog.ShowModal())
2816                 return;
2817             strName = dialog.GetValue1();
2818             strAddress = dialog.GetValue2();
2819         }
2820         while (CheckIfMine(strAddress, _("Add Address")));
2821     }
2822     else if (nPage == RECEIVING)
2823     {
2824         // Ask name
2825         CGetTextFromUserDialog dialog(this,
2826             _("New Receiving Address"),
2827             _("You should use a new address for each payment you receive.\n\nLabel"),
2828             "");
2829         if (!dialog.ShowModal())
2830             return;
2831         strName = dialog.GetValue();
2832
2833         bool fWasLocked = pwalletMain->IsLocked();
2834         if (!GetWalletPassphrase())
2835             return;
2836
2837         // Generate new key
2838         std::vector<unsigned char> newKey;
2839         pwalletMain->GetKeyFromPool(newKey, true);
2840         strAddress = CBitcoinAddress(newKey).ToString();
2841
2842         if (fWasLocked)
2843             pwalletMain->Lock();
2844     }
2845
2846     // Add to list and select it
2847     CRITICAL_BLOCK(pwalletMain->cs_wallet)
2848         pwalletMain->SetAddressBookName(strAddress, strName);
2849     int nIndex = InsertLine(m_listCtrl, strName, strAddress);
2850     SetSelection(m_listCtrl, nIndex);
2851     m_listCtrl->SetFocus();
2852     if (nPage == SENDING)
2853         pframeMain->RefreshListCtrl();
2854 }
2855
2856 void CAddressBookDialog::OnButtonOK(wxCommandEvent& event)
2857 {
2858     // OK
2859     EndModal(GetSelectedAddress() != "" ? 1 : 0);
2860 }
2861
2862 void CAddressBookDialog::OnButtonCancel(wxCommandEvent& event)
2863 {
2864     // Cancel
2865     EndModal(0);
2866 }
2867
2868 void CAddressBookDialog::OnClose(wxCloseEvent& event)
2869 {
2870     // Close
2871     EndModal(0);
2872 }
2873
2874
2875
2876
2877
2878
2879 //////////////////////////////////////////////////////////////////////////////
2880 //
2881 // CMyTaskBarIcon
2882 //
2883
2884 enum
2885 {
2886     ID_TASKBAR_RESTORE = 10001,
2887     ID_TASKBAR_SEND,
2888     ID_TASKBAR_OPTIONS,
2889     ID_TASKBAR_GENERATE,
2890     ID_TASKBAR_EXIT,
2891 };
2892
2893 BEGIN_EVENT_TABLE(CMyTaskBarIcon, wxTaskBarIcon)
2894     EVT_TASKBAR_LEFT_DCLICK(CMyTaskBarIcon::OnLeftButtonDClick)
2895     EVT_MENU(ID_TASKBAR_RESTORE, CMyTaskBarIcon::OnMenuRestore)
2896     EVT_MENU(ID_TASKBAR_SEND, CMyTaskBarIcon::OnMenuSend)
2897     EVT_MENU(ID_TASKBAR_OPTIONS, CMyTaskBarIcon::OnMenuOptions)
2898     EVT_UPDATE_UI(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnUpdateUIGenerate)
2899     EVT_MENU(ID_TASKBAR_EXIT, CMyTaskBarIcon::OnMenuExit)
2900 END_EVENT_TABLE()
2901
2902 void CMyTaskBarIcon::Show(bool fShow)
2903 {
2904     static char pszPrevTip[200];
2905     if (fShow)
2906     {
2907         string strTooltip = _("Bitcoin");
2908         if (fGenerateBitcoins)
2909             strTooltip = _("Bitcoin - Generating");
2910         if (fGenerateBitcoins && vNodes.empty())
2911             strTooltip = _("Bitcoin - (not connected)");
2912
2913         // Optimization, only update when changed, using char array to be reentrant
2914         if (strncmp(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip)-1) != 0)
2915         {
2916             strlcpy(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip));
2917 #ifdef __WXMSW__
2918             // somehow it'll choose the wrong size and scale it down if
2919             // we use the main icon, so we hand it one with only 16x16
2920             SetIcon(wxICON(favicon), strTooltip);
2921 #else
2922             SetIcon(bitcoin80_xpm, strTooltip);
2923 #endif
2924         }
2925     }
2926     else
2927     {
2928         strlcpy(pszPrevTip, "", sizeof(pszPrevTip));
2929         RemoveIcon();
2930     }
2931 }
2932
2933 void CMyTaskBarIcon::Hide()
2934 {
2935     Show(false);
2936 }
2937
2938 void CMyTaskBarIcon::OnLeftButtonDClick(wxTaskBarIconEvent& event)
2939 {
2940     Restore();
2941 }
2942
2943 void CMyTaskBarIcon::OnMenuRestore(wxCommandEvent& event)
2944 {
2945     Restore();
2946 }
2947
2948 void CMyTaskBarIcon::OnMenuSend(wxCommandEvent& event)
2949 {
2950     // Taskbar: Send
2951     CSendDialog dialog(pframeMain);
2952     dialog.ShowModal();
2953 }
2954
2955 void CMyTaskBarIcon::OnMenuOptions(wxCommandEvent& event)
2956 {
2957     // Since it's modal, get the main window to do it
2958     wxCommandEvent event2(wxEVT_COMMAND_MENU_SELECTED, wxID_PREFERENCES);
2959     pframeMain->GetEventHandler()->AddPendingEvent(event2);
2960 }
2961
2962 void CMyTaskBarIcon::Restore()
2963 {
2964     pframeMain->Show();
2965     wxIconizeEvent event(0, false);
2966     pframeMain->GetEventHandler()->AddPendingEvent(event);
2967     pframeMain->Iconize(false);
2968     pframeMain->Raise();
2969 }
2970
2971 void CMyTaskBarIcon::OnUpdateUIGenerate(wxUpdateUIEvent& event)
2972 {
2973     event.Check(fGenerateBitcoins);
2974 }
2975
2976 void CMyTaskBarIcon::OnMenuExit(wxCommandEvent& event)
2977 {
2978     pframeMain->Close(true);
2979 }
2980
2981 void CMyTaskBarIcon::UpdateTooltip()
2982 {
2983     if (IsIconInstalled())
2984         Show(true);
2985 }
2986
2987 wxMenu* CMyTaskBarIcon::CreatePopupMenu()
2988 {
2989     wxMenu* pmenu = new wxMenu;
2990     pmenu->Append(ID_TASKBAR_RESTORE, _("&Open Bitcoin"));
2991     pmenu->Append(ID_TASKBAR_SEND, _("&Send Bitcoins"));
2992     pmenu->Append(ID_TASKBAR_OPTIONS, _("O&ptions..."));
2993 #ifndef __WXMAC_OSX__ // Mac has built-in quit menu
2994     pmenu->AppendSeparator();
2995     pmenu->Append(ID_TASKBAR_EXIT, _("E&xit"));
2996 #endif
2997     return pmenu;
2998 }
2999
3000
3001
3002
3003
3004
3005 //////////////////////////////////////////////////////////////////////////////
3006 //
3007 // CMyApp
3008 //
3009
3010 void CreateMainWindow()
3011 {
3012     pframeMain = new CMainFrame(NULL);
3013     if (GetBoolArg("-min"))
3014         pframeMain->Iconize(true);
3015 #if defined(__WXGTK__) || defined(__WXMAC_OSX__)
3016     if (!GetBoolArg("-minimizetotray"))
3017         fMinimizeToTray = false;
3018 #endif
3019     pframeMain->Show(true);  // have to show first to get taskbar button to hide
3020     if (fMinimizeToTray && pframeMain->IsIconized())
3021         fClosedToTray = true;
3022     pframeMain->Show(!fClosedToTray);
3023     ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
3024     CreateThread(ThreadDelayedRepaint, NULL);
3025 }
3026
3027
3028 // Define a new application
3029 class CMyApp : public wxApp
3030 {
3031 public:
3032     CMyApp(){};
3033     ~CMyApp(){};
3034     bool OnInit();
3035     bool OnInit2();
3036     int OnExit();
3037
3038     // Hook Initialize so we can start without GUI
3039     virtual bool Initialize(int& argc, wxChar** argv);
3040
3041     // 2nd-level exception handling: we get all the exceptions occurring in any
3042     // event handler here
3043     virtual bool OnExceptionInMainLoop();
3044
3045     // 3rd, and final, level exception handling: whenever an unhandled
3046     // exception is caught, this function is called
3047     virtual void OnUnhandledException();
3048
3049     // and now for something different: this function is called in case of a
3050     // crash (e.g. dereferencing null pointer, division by 0, ...)
3051     virtual void OnFatalException();
3052 };
3053
3054 IMPLEMENT_APP(CMyApp)
3055
3056 bool CMyApp::Initialize(int& argc, wxChar** argv)
3057 {
3058     for (int i = 1; i < argc; i++)
3059         if (!IsSwitchChar(argv[i][0]))
3060             fCommandLine = true;
3061
3062     if (!fCommandLine)
3063     {
3064         // wxApp::Initialize will remove environment-specific parameters,
3065         // so it's too early to call ParseParameters yet
3066         for (int i = 1; i < argc; i++)
3067         {
3068             wxString str = argv[i];
3069             #ifdef __WXMSW__
3070             if (str.size() >= 1 && str[0] == '/')
3071                 str[0] = '-';
3072             char pszLower[MAX_PATH];
3073             strlcpy(pszLower, str.c_str(), sizeof(pszLower));
3074             strlwr(pszLower);
3075             str = pszLower;
3076             #endif
3077             if (str == "-daemon")
3078                 fDaemon = true;
3079         }
3080     }
3081
3082 #ifdef __WXGTK__
3083     if (fDaemon || fCommandLine)
3084     {
3085         // Call the original Initialize while suppressing error messages
3086         // and ignoring failure.  If unable to initialize GTK, it fails
3087         // near the end so hopefully the last few things don't matter.
3088         {
3089             wxLogNull logNo;
3090             wxApp::Initialize(argc, argv);
3091         }
3092
3093         if (fDaemon)
3094         {
3095             // Daemonize
3096             pid_t pid = fork();
3097             if (pid < 0)
3098             {
3099                 fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
3100                 return false;
3101             }
3102             if (pid > 0)
3103                 pthread_exit((void*)0);
3104
3105             pid_t sid = setsid();
3106             if (sid < 0)
3107                 fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
3108         }
3109
3110         return true;
3111     }
3112 #endif
3113
3114     return wxApp::Initialize(argc, argv);
3115 }
3116
3117 bool CMyApp::OnInit()
3118 {
3119 #if defined(__WXMSW__) && defined(__WXDEBUG__) && defined(GUI)
3120     // Disable malfunctioning wxWidgets debug assertion
3121     extern int g_isPainting;
3122     g_isPainting = 10000;
3123 #endif
3124 #if defined(__WXMSW__ ) || defined(__WXMAC_OSX__)
3125     SetAppName("PPCoin");
3126 #else
3127     SetAppName("ppcoin");
3128 #endif
3129 #ifdef __WXMSW__
3130 #if wxUSE_UNICODE
3131     // Hack to set wxConvLibc codepage to UTF-8 on Windows,
3132     // may break if wxMBConv_win32 implementation in strconv.cpp changes.
3133     class wxMBConv_win32 : public wxMBConv
3134     {
3135     public:
3136         long m_CodePage;
3137         size_t m_minMBCharWidth;
3138     };
3139     if (((wxMBConv_win32*)&wxConvLibc)->m_CodePage == CP_ACP)
3140         ((wxMBConv_win32*)&wxConvLibc)->m_CodePage = CP_UTF8;
3141 #endif
3142 #endif
3143
3144     // Load locale/<lang>/LC_MESSAGES/bitcoin.mo language file
3145     g_locale.Init(wxLANGUAGE_DEFAULT, 0);
3146     g_locale.AddCatalogLookupPathPrefix("locale");
3147 #ifndef __WXMSW__
3148     g_locale.AddCatalogLookupPathPrefix("/usr/share/locale");
3149     g_locale.AddCatalogLookupPathPrefix("/usr/local/share/locale");
3150 #endif
3151     g_locale.AddCatalog("wxstd"); // wxWidgets standard translations, if any
3152     g_locale.AddCatalog("bitcoin");
3153
3154 #ifdef __WXMSW__
3155     HDC hdc = GetDC(NULL);
3156     if (hdc)
3157     {
3158         nScaleX = GetDeviceCaps(hdc, LOGPIXELSX) / 96.0;
3159         nScaleY = GetDeviceCaps(hdc, LOGPIXELSY) / 96.0;
3160         ReleaseDC(NULL, hdc);
3161     }
3162 #endif
3163
3164     return AppInit(argc, argv);
3165 }
3166
3167 int CMyApp::OnExit()
3168 {
3169     Shutdown(NULL);
3170     return wxApp::OnExit();
3171 }
3172
3173 bool CMyApp::OnExceptionInMainLoop()
3174 {
3175     try
3176     {
3177         throw;
3178     }
3179     catch (std::exception& e)
3180     {
3181         PrintException(&e, "CMyApp::OnExceptionInMainLoop()");
3182         wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
3183         Sleep(1000);
3184         throw;
3185     }
3186     catch (...)
3187     {
3188         PrintException(NULL, "CMyApp::OnExceptionInMainLoop()");
3189         wxLogWarning("Unknown exception");
3190         Sleep(1000);
3191         throw;
3192     }
3193     return true;
3194 }
3195
3196 void CMyApp::OnUnhandledException()
3197 {
3198     // this shows how we may let some exception propagate uncaught
3199     try
3200     {
3201         throw;
3202     }
3203     catch (std::exception& e)
3204     {
3205         PrintException(&e, "CMyApp::OnUnhandledException()");
3206         wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
3207         Sleep(1000);
3208         throw;
3209     }
3210     catch (...)
3211     {
3212         PrintException(NULL, "CMyApp::OnUnhandledException()");
3213         wxLogWarning("Unknown exception");
3214         Sleep(1000);
3215         throw;
3216     }
3217 }
3218
3219 void CMyApp::OnFatalException()
3220 {
3221     wxMessageBox(_("Program has crashed and will terminate.  "), "Bitcoin", wxOK | wxICON_ERROR);
3222 }