int main(int argc, char *argv[])
{
    if (!MainInit(argc, argv))
    {
        printf("Error: %s\n", GetTranslation("Init failed, aborting"));
        return 1;
    }
    
    // Init
    if (!(MainWin = initscr())) throwerror(false, "Could not init ncurses");
    if (!(CDKScreen = initCDKScreen(MainWin))) throwerror(false, "Could not init CDK");
    initCDKColor();

    if ((InstallInfo.dest_dir_type == DEST_DEFAULT) && !ReadAccess(InstallInfo.dest_dir))
        throwerror(true, CreateText("This installer will install files to the following directory:\n%s\n"
                                    "However you don't have read permissions to this directory\n"
                                    "Please restart the installer as a user who does or as the root user",
                                    InstallInfo.dest_dir.c_str()));
    
    int i=0;
    while(Functions[i])
    {
        if (Functions[i]()) i++;
        else
        {
            if (YesNoBox(GetTranslation("This will abort the installation\nAre you sure?")))
                break;
        }
    }

    EndProg();
    return 0;
}
bool CInstaller::AskQuit()
{
    const char *msg;
    if (Installing())
        msg = GetTranslation("Install commands are still running\n"
        "If you abort now this may lead to a broken installation\n"
        "Are you sure?");
    else
        msg = GetTranslation("This will abort the installation\nAre you sure?");
    
    return YesNoBox(msg);
}
/*! @function
*************************************************************************
<PRE>
函数名  : OnButton1
功能    : 按钮1相应事件
参数    :
返回值  :
作者    : 唐日升
日期    : 2010-12-01
备注    :
</PRE>
************************************************************************/
void CInvRetServerWin::OnButton1(int iEvent, unsigned char * pEventData, int iDataLen)
{

    string strErr("");
    CaProgressBar porbar("");
    CInvVol invVol;
    string strMsg1("");
    string strMsg2("");
    string strMsg3("");
    char sqlbuf[128] = {0};
    INT32 nRet;

    if (0 == g_globalArg->m_IngSegPoint)
    {
        strMsg1 = "是否发票缴销?";
        strMsg2 = "发票缴销中...";
        strMsg3 = "发票缴销成功";
    }
    else
    {
        strMsg1 = "是否发票退回主机?";
        strMsg2 = "发票退回中...";
        strMsg3 = "发票退回成功";
    }

    if(FAILURE == YesNoBox(strMsg1))
    {
        return;
    }


    UINT8 ret = CheckInput(strErr);
    if (ret != SUCCESS)
    {
        CaMsgBox::ShowMsg(strErr);
        return;
    }

    memset(sqlbuf, 0x00, sizeof(sqlbuf));
    sprintf(sqlbuf, "where CODE = '%s' and IS_NO >= %s and IE_NO <= %s",
            m_strCode.c_str(), m_strSno.c_str(), m_strEno.c_str());
    invVol.m_filter = sqlbuf;

    DBG_PRINT(("sqlbuf : %s", sqlbuf));
// 	invVol.Requery();
// 	INT32 errCode = invVol.LoadOneRecord();
// 	if (errCode == SQLITE_DONE)
// 	{
// 		CaMsgBox::ShowMsg("无该号段的发票");
// 		return;
// 	}
// 	else if(errCode != SQLITE_OK)
// 	{
// 		CaMsgBox::ShowMsg("查询数据库错误");
// 		DBG_PRINT(("errCode : %d", errCode));
// 		return;
// 	}
//
// 	m_invVol.m_kindcode = invVol.m_kindcode;//发票种类代码

    porbar.SetText(strMsg2.c_str());
    porbar.ReFresh();
    //开始业务
    CDownLoadInvVolFun retHandle;
    if (0 == g_globalArg->m_IngSegPoint)
    {
        nRet = retHandle.InvVolRetToServer(&m_invVol, strErr);
    }
    else
    {
        nRet = retHandle.InvVolRetToMach(&m_invVol, "0", strErr);//退回给主机(分机号0)
    }

    if (SUCCESS != nRet)
    {
        CaMsgBox::ShowMsg(strErr);
        DBG_PRINT(("%s" ,strErr.c_str()));
        return;
    }
    //更新本地数据库
    invVol.m_filter = sqlbuf;
    INT32 errCode = invVol.Delete();
    if (errCode != SQLITE_OK)
    {
        CaMsgBox::ShowMsg("更新数据库错误,请执行票源下载");
        DBG_PRINT(("errCode : %d", errCode));
        return;
    }

    DBG_PRINT(("发票缴销/退回成功"));
    CaMsgBox::ShowMsg(strMsg3);
    ChangeWin(INV_SEG_MENU);
}
bool InstallFiles()
{
    ButtonBar.Clear();
    ButtonBar.AddButton("C", "Cancel");
    ButtonBar.Draw();

    char *msg;
    char *dbuttons[2] = { GetTranslation("Continue"), GetTranslation("Exit program") };
    
    if ((InstallInfo.dest_dir_type == DEST_SELECT) || (InstallInfo.dest_dir_type == DEST_DEFAULT))
    {
        msg = CreateText(GetTranslation("This will install %s to the following directory:\n%s\nContinue?"),
                                   InstallInfo.program_name.c_str(), MakeCString(InstallInfo.dest_dir));
    }
    else
    {
        msg = CreateText(GetTranslation("This will install %s\nContinue?"), InstallInfo.program_name.c_str());
    }

    CCDKDialog Diag(CDKScreen, CENTER, CENTER, msg, dbuttons, 2);
    Diag.SetBgColor(26);
        
    int sel = Diag.Activate();
    
    Diag.Destroy();
    refreshCDKScreen(CDKScreen);
                
    if (sel == 1)
        return false;
    
    CCDKSWindow InstallOutput(CDKScreen, 0, 6, GetDefaultHeight()-5, -1,
                              CreateText("<C></29/B>%s", GetTranslation("Install output")), 2000);
    InstallOutput.SetBgColor(5);
    nodelay(WindowOf(InstallOutput.GetSWin()), true); // Make sure input doesn't block

    const int maxx = getmaxx(InstallOutput.GetSWin()->win);

    CCDKSWindow ProggWindow(CDKScreen, 0, 2, 5, maxx, NULL, 4);
    ProggWindow.SetBgColor(5);
    ProggWindow.AddText("");
    ProggWindow.AddText(CreateText("</B/29>%s:<!29!B>", GetTranslation("Status")));
    ProggWindow.AddText(CreateText("%s (1/%d)", GetTranslation("Extracting files"), InstallInfo.command_entries.size()+1),
                        true, BOTTOM, 24);
    
    CCDKHistogram ProgressBar(CDKScreen, 25, 3, 1, maxx-29, HORIZONTAL,
                              CreateText("<C></29/B>%s", GetTranslation("Progress")), false);
    ProgressBar.SetBgColor(5);
    ProgressBar.SetHistogram(vPERCENT, TOP, 0, 100, 0, COLOR_PAIR (24) | A_REVERSE | ' ', A_BOLD);
    
    setCDKSwindowLLChar(ProggWindow.GetSWin(), ACS_LTEE);
    setCDKSwindowLRChar(ProggWindow.GetSWin(), ACS_RTEE);
    
    InstallOutput.Draw();
    ProggWindow.Draw();
    
    // Check if we need root access
    char *passwd = NULL;
    LIBSU::CLibSU SuHandler;
    SuHandler.SetUser("root");
    SuHandler.SetTerminalOutput(false);

    bool askpass = false;
    
    for (std::list<command_entry_s *>::iterator it=InstallInfo.command_entries.begin();
        it!=InstallInfo.command_entries.end(); it++)
    {
        if ((*it)->need_root != NO_ROOT)
        {
            // Command may need root permission, check if it is so
            if ((*it)->need_root == DEPENDED_ROOT)
            {
                param_entry_s *p = GetParamByVar((*it)->dep_param);
                if (p && !WriteAccess(p->value))
                {
                    (*it)->need_root = NEED_ROOT;
                    if (!askpass) askpass = true;
                }
            }
            else if (!askpass) askpass = true;
        }
    }

    if (!askpass)
        askpass = !WriteAccess(InstallInfo.dest_dir);
    
    // Ask root password if one of the command entries need root access and root isn't passwordless
    if (askpass && SuHandler.NeedPassword())
    {
        CCDKEntry entry(CDKScreen, CENTER, CENTER,
                        GetTranslation("This installation requires root(administrator) privileges in order to continue\n"
                                       "Please enter the password of the root user"), "", 60, 0, 256, vHMIXED);
        entry.SetHiddenChar('*');
        entry.SetBgColor(26);

        while(1)
        {
            char *sz = entry.Activate();

            if ((entry.ExitType() != vNORMAL) || !sz || !sz[0])
            {
                if (YesNoBox(GetTranslation("Root access is required to continue\nAbort installation?")))
                    EndProg();
                refreshCDKScreen(CDKScreen);
            }
            else
            {
                if (SuHandler.TestSU(sz))
                {
                    passwd = strdup(sz);
                    for (short s=0;s<strlen(sz);s++) sz[s] = 0;
                    break;
                }

                for (short s=0;s<strlen(sz);s++) sz[s] = 0;
                entry.Clean();
                
                // Some error appeared
                if (SuHandler.GetError() == LIBSU::CLibSU::SU_ERROR_INCORRECTPASS)
                {
                    WarningBox(GetTranslation("Incorrect password given for root user\nPlease retype"));
                }
                else
                {
                    throwerror(true, GetTranslation("Could not use su to gain root access\n"
                               "Make sure you can use su(adding the current user to the wheel group may help)"));
                }
            }
        }
        // Restore screen
        entry.Destroy();
        refreshCDKScreen(CDKScreen);
    }

    short percent = 0;
    
    bool alwaysroot = false;
    if (!WriteAccess(InstallInfo.dest_dir))
    {
        CExtractAsRootFunctor Extracter;
        Extracter.SetUpdateProgFunc(SUUpdateProgress, &ProgressBar);
        Extracter.SetUpdateTextFunc(SUUpdateText, &InstallOutput);
        
        if (!Extracter(passwd))
        {
            CleanPasswdString(passwd);
            passwd = NULL;
            throwerror(true, "Error during extracting files");
        }

        InstallOutput.AddText("Done!\n");
        alwaysroot = true; // Install commands need root now too
    }
    else
    {

        while(percent<100)
        {
            std::string curfile;
            percent = ExtractArchive(curfile);
            
            InstallOutput.AddText("Extracting file: " + curfile, false);
            if (percent==100) InstallOutput.AddText("Done!", false);
            else if (percent==-1) throwerror(true, "Error during extracting files");
    
            ProgressBar.SetValue(0, 100, percent/(1+InstallInfo.command_entries.size()));
            ProgressBar.Draw();
    
            chtype input = getch();
            if (input == 'c')
            {
                if (YesNoBox(GetTranslation("Install commands are still running\n"
                    "If you abort now this may lead to a broken installation\n"
                    "Are you sure?")))
                {
                    CleanPasswdString(passwd);
                    passwd = NULL;
                    EndProg();
                }
            }
        }
    }

    SuHandler.SetThinkFunc(InstThinkFunc, passwd);
    SuHandler.SetOutputFunc(PrintInstOutput, &InstallOutput);

    percent = 100/(1+InstallInfo.command_entries.size()); // Convert to overall progress
    
    short step = 2; // Not 1, because extracting files is also a step
    for (std::list<command_entry_s*>::iterator it=InstallInfo.command_entries.begin();
         it!=InstallInfo.command_entries.end(); it++, step++)
    {
        if ((*it)->command.empty()) continue;

        ProggWindow.Clear();
        ProggWindow.AddText("");
        ProggWindow.AddText(CreateText("</B/29>%s:<!29!B>", GetTranslation("Status")));
        ProggWindow.AddText(CreateText("%s (%d/%d)", GetTranslation((*it)->description.c_str()), step,
                            InstallInfo.command_entries.size()+1), true, BOTTOM, 24);

        ProgressBar.Draw();
        
        std::string command = (*it)->command + " " + GetParameters(*it);
        InstallOutput.AddText("");
        InstallOutput.AddText(CreateText("Execute: %s", command.c_str()));
        InstallOutput.AddText("");
        InstallOutput.AddText("");
        
        if (((*it)->need_root == NEED_ROOT) || alwaysroot)
        {
            SuHandler.SetPath((*it)->path.c_str());
            SuHandler.SetCommand(command);
            if (!SuHandler.ExecuteCommand(passwd))
            {
                if ((*it)->exit_on_failure)
                {
                    CleanPasswdString(passwd);
                    passwd = NULL;
                    throwerror(true, "%s\n('%s')", GetTranslation("Failed to execute install command"),
                               SuHandler.GetErrorMsgC());
                }
            }
        }
        else
        {
            // Redirect stderr to stdout, so that errors will be displayed too
            command += " 2>&1";
            
            setenv("PATH", (*it)->path.c_str(), 1);
            FILE *pipe = popen(command.c_str(), "r");
            char term[1024];
            if (pipe)
            {
                while (fgets(term, sizeof(term), pipe))
                {
                    InstallOutput.AddText(term);

                    chtype input = getch();
                    if (input == 'c') /*injectCDKSwindow(InstallOutput.GetSWin(), input);*/
                    {
                        if (YesNoBox(GetTranslation("Install commands are still running\n"
                                                    "If you abort now this may lead to a broken installation\n"
                                                    "Are you sure?")))
                        {
                            CleanPasswdString(passwd);
                            passwd = NULL;
                            EndProg();
                        }
                    }
                }
                
                // Check if command exitted normally and close pipe
                int state = pclose(pipe);
                if (!WIFEXITED(state) || (WEXITSTATUS(state) == 127)) // SH returns 127 if command execution failes
                {
                    if ((*it)->exit_on_failure)
                    {
                        CleanPasswdString(passwd);
                        passwd = NULL;
                        throwerror(true, "Failed to execute install command");
                    }
                }
            }
            else
            {
                CleanPasswdString(passwd);
                passwd = NULL;
                throwerror(true, "Could not execute installation commands (could not open pipe)");
            }
            
#if 0
            // Need to find a good way to safely suspend a process...this code doesn't always work :(
            
            int pipefd[2];

            pipe(pipefd);
            pid_t pid = fork();
            if (pid == -1) throwerror(true, "Error during command execution: Could not fork process");
            else if (pid) // Parent process
            {
                close(pipefd[1]); // We're not going to write here

                std::string out;
                char c;
                int compid = -1; // PID of the executed command

                while(read(pipefd[0], &c, sizeof(c)) > 0)
                {
                    out += c;
                    if (c == '\n')
                    {
                        if (compid == -1)
                        {
                            compid = atoi(out.c_str());
                            InstallOutput.AddText(CreateText("pid: %d compid: %d", pid, compid), false);
                        }
                        else InstallOutput.AddText(out, false);
                        out.clear();
                    }

                    chtype input = getch();
                    if (input != ERR) /*injectCDKSwindow(InstallOutput.GetSWin(), input);*/
                    {
                        if (kill(compid, SIGTSTP) < 0) // Pause command execution
                            WarningBox("PID Error: %s\n", strerror(errno));
                        
                        char *buttons[2] = { GetTranslation("Yes"), GetTranslation("No") };
                        CCharListHelper msg;
    
                        msg.AddItem(GetTranslation("This will abort the installation"));
                        msg.AddItem(GetTranslation("Are you sure?"));
    
                        CCDKDialog dialog(CDKScreen, CENTER, CENTER, msg, msg.Count(), buttons, 2);
                        dialog.SetBgColor(26);
                        int ret = dialog.Activate();
                        bool cont = ((ret == 1) || (dialog.ExitType() != vNORMAL));

                        dialog.Destroy();
                        refreshCDKScreen(CDKScreen);

                        if (!cont)
                        {
                            kill(pid, SIGTERM);
                            EndProg();
                        }

                        kill(compid, SIGCONT); // Continue command execution
                    }
                }
                close (pipefd[0]);

                int status;
                //waitpid(pid, &status, 0);
            }
            else // Child process
            {
                // Redirect stdout to pipe
                close(STDOUT_FILENO);
                dup (pipefd[1]);
                
                close (pipefd[0]); // No need to read here

                // Make sure no errors are printed and write pid of new command
                command += " 2> /dev/null &  echo $!";
                execl("/bin/sh", "sh", "-c", command.c_str(), NULL);
                system(CreateText("echo %s", strerror(errno)));
                _exit(1);
            }
#endif
        }

        percent += (1.0f/((float)InstallInfo.command_entries.size()+1.0f))*100.0f;
        ProgressBar.SetValue(0, 100, percent);
    }

    ProgressBar.SetValue(0, 100, 100);
    ProgressBar.Draw();
    
    CleanPasswdString(passwd);
    passwd = NULL;
    
    ButtonBar.Clear();
    ButtonBar.AddButton("Arrows", "Scroll install output");
    ButtonBar.AddButton("Enter", (FileExists(InstallInfo.own_dir + "/config/finish")) ? "Continue" : "Finish"); // HACK
    ButtonBar.Draw();

    WarningBox("Installation of %s complete!", InstallInfo.program_name.c_str());

    InstallOutput.Activate();
    return (InstallOutput.ExitType() == vNORMAL);
}
bool CFileDialog::Activate()
{
    char *buttons[] = { GetTranslation("Open directory"), GetTranslation("Select directory"), GetTranslation("Cancel") };
    char label[] = "Dir: ";
    char curdir[1024];
    
    ButtonBar.Push();
    ButtonBar.AddButton("TAB", "Next button");
    ButtonBar.AddButton("ENTER", "Activate button");
    ButtonBar.AddButton("Arrows", "Navigate menu");
    ButtonBar.AddButton("C", "Create directory");
    ButtonBar.AddButton("A", "About");
    ButtonBar.AddButton("ESC", "Cancel");
    ButtonBar.Draw();

    if (!getcwd(curdir, sizeof(curdir))) throwerror(true, "Could not read current directory");
    
    if (chdir(m_szStartDir.c_str()) != 0)
        throwerror(true, "Could not open directory '%s'", m_szStartDir.c_str());

    if (!ReadDir(m_szStartDir)) throwerror(true, "Could not read directory '%s'", m_szStartDir.c_str());
    
    CCDKButtonBox ButtonBox(CDKScreen, CENTER, GetDefaultHeight(), 1, GetDefaultWidth(), 0, 1, 3, buttons, 3);
    ButtonBox.SetBgColor(5);

    if (!m_pCurDirWin && !m_pFileList)
    {
        m_pCurDirWin = new CCDKSWindow(CDKScreen, CENTER, getbegy(ButtonBox.GetBBox()->win)-2, 2, GetDefaultWidth()+1,
                                                           NULL, 1);
        m_pCurDirWin->SetBgColor(5);

        if (!m_pFileList)
        {
            m_pFileList = new CCDKAlphaList(CDKScreen, CENTER, 2, getbegy(m_pCurDirWin->GetSWin()->win)-1, GetDefaultWidth()+1,
                                            const_cast<char*>(m_szTitle.c_str()), label, &m_DirItems[0], m_DirItems.size());
            m_pFileList->SetBgColor(5);
            setCDKEntryPreProcess(m_pFileList->GetAList()->entryField, CreateDirCB, this);
    
            //m_pFileList->GetAList()->entryField->dispType = vVIEWONLY;  // HACK: Disable backspace
        }
    
        setCDKAlphalistLLChar(m_pFileList->GetAList(), ACS_LTEE);
        setCDKAlphalistLRChar(m_pFileList->GetAList(), ACS_RTEE);
        setCDKLabelLLChar(m_pCurDirWin->GetSWin(), ACS_LTEE);
        setCDKLabelLRChar(m_pCurDirWin->GetSWin(), ACS_RTEE);
        setCDKButtonboxULChar(ButtonBox.GetBBox(), ACS_LTEE);
        setCDKButtonboxURChar(ButtonBox.GetBBox(), ACS_RTEE);
    }
    
    m_pFileList->Draw();
    m_pCurDirWin->Draw();
    ButtonBox.Draw();
    
    m_pFileList->Bind(KEY_TAB, SwitchButtonK, ButtonBox.GetBBox()); // Pas TAB through ButtonBox

    m_szDestDir = m_szStartDir;
    UpdateCurDirText();
    
    while(true)
    {
        // HACK: Give textbox content
        setCDKEntryValue(m_pFileList->GetAList()->entryField,
                         chtype2Char(m_pFileList->GetAList()->scrollField->item[m_pFileList->GetAList()->scrollField->currentItem]));

        char *selection = m_pFileList->Activate();

        if ((m_pFileList->ExitType() != vNORMAL) || (ButtonBox.GetCurrent() == 2)) break;
        if (!selection || !selection[0]) continue;

        if (ButtonBox.GetCurrent() == 1)
        {
            if (m_bAskWAccess && !WriteAccess(m_szDestDir))
            {
                char *dbuttons[2] = { GetTranslation("Continue as root"), GetTranslation("Choose another directory") };
                CCDKDialog Diag(CDKScreen, CENTER, CENTER,
                                GetTranslation("You don't have write permissions for this directory.\n"
                                        "The files can be extracted as the root user,\n"
                                        "but you'll need to enter the root password for this later."), dbuttons, 2);
                Diag.SetBgColor(26);
        
                int sel = Diag.Activate();
    
                Diag.Destroy();
                refreshCDKScreen(CDKScreen);
                if (sel)
                    continue;
            }
            break;
        }
        
        if (!FileExists(selection))
        {
            if (YesNoBox(GetTranslation("Directory does not exist\nDo you want to create it?")))
            {
                if (mkdir(selection, (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH)) != 0)
                {
                    WarningBox("%s\n%.75s\n%.75s", GetTranslation("Could not create directory"), selection,
                               strerror(errno));
                    continue;
                }
            }
            else
                continue;
        }
        
        UpdateFileList(selection);
    }
    
    bool success = ((m_pFileList->ExitType() != vESCAPE_HIT) && (ButtonBox.GetCurrent() == 1));
    
    ButtonBar.Pop();

    if (m_bRestoreDir)
        chdir(curdir); // Return back to original directory
    
    return success;
}