. FTP 저장

FTP 프로토콜은 HTTP와는 달리 업로드를 지원한다. 다운로드받은 파일을 편집한 후 이 파일을 다시 FTP 서버로 보낼 수 있는데 그래서 FTP는 웹 서버의 파일 편집용으로 아주 유용하게 활용된다. 당근은 FTP 업로드를 위한 별도의 명령을 제공하지 않으며 파일 저장 명령에 업로드 기능을 통합하기로 한다. 그래서 로컬 파일이든, FTP로 다운로드받은 파일이든 위치에 상관없이 저장 명령으로 변경 내용을 전송할 수 있다.

FTP 업로드는 결국 원격지의 서버로 파일을 저장하는 것이므로 저장 명령으로 업로드를 하는 것은 논리적으로 합당하다. 사용자는 파일을 어떻게 열었는가에 상관없이 저장 명령을 사용할 수 있으므로 일관된 명령으로 파일을 관리할 수 있으며 업로드를 위해 별도의 접속정보를 다시 제공하지 않아도 된다는 점에서 아주 좋은 것 같다. 업로드가 저장과 통합되므로 수정해야 할 함수는 SaveToFile이다. 업로드를 위한 코드가 추가되고 코드의 순서도 약간 바뀌었다.

 

BOOL SaveToFile(HWND hChild,TCHAR *Path)

{

     HANDLE hFile;

     DWORD dwWritten;

     int len;

     TCHAR *TextBuf;

     SInfo *pSi=(SInfo *)GetWindowLong(hChild,0);

     DWORD err;

     TCHAR Mes[512];

     BOOL Result;

     TCITEM tie;

     int idx;

 

     if (strnicmp(Path,"http",4)==0) {

          MessageBox(hChild, "HTTP 프로토콜은 업로드를 지원하지 않으므로 이 이름으로는 "

              "저장할 수 없습니다. 새 이름으로 하드 디스크에 저장하십시오","알림",MB_OK);

          return FALSE;

     }

 

     len=pSi->Ae.GetTextLength();

     TextBuf=(TCHAR *)malloc(len+2);

     pSi->Ae.GetText(TextBuf,len+2);

 

     if (strnicmp(Path,"ftp",3)==0) {

          Result=DgFtpUp(Path,TextBuf);

     } else {

          hFile=CreateFile(Path,GENERIC_WRITE,0,NULL,

              CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);

          if (hFile==INVALID_HANDLE_VALUE) {

              err=GetLastError();

              switch (err)

              {

              case ERROR_ACCESS_DENIED:

                   wsprintf(Mes,"%s 파일을 생성할 수 없습니다. 읽기전용 등의 이유로 "

                        "액세스가 금지되어 있습니다.",Path);

                   break;

              case ERROR_SHARING_VIOLATION:

                   wsprintf(Mes,"%s 파일을 다른 프로그램이 사용하고 있습니다.",Path);

                   break;

              case ERROR_WRITE_PROTECT:

                   wsprintf(Mes,"기록 금지된 장치입니다.");

                   break;

              default:

                   wsprintf(Mes,"알수 없는 에러입니다. 개발자에게 문의하지 마시고 "

                        "알아서 해결하십시오. 에러 코드=%d",err);

                   break;

              }

              MessageBox(g_hFrameWnd, Mes,"알림",MB_OK);

              Result=FALSE;

          } else {

              WriteFile(hFile,TextBuf,len,&dwWritten,NULL);

              CloseHandle(hFile);

              Result=TRUE;

          }

     }

 

     if (Result) {

          lstrcpy(pSi->NowFile,Path);

          pSi->Ae.SetModified(FALSE);

          tie.mask=TCIF_IMAGE;

          tie.iImage=0;

          idx=FindFileTab(pSi->NowFile);

          TabCtrl_SetItem(hFileTab,idx,&tie);

     }

     free(TextBuf);

     return Result;

}

 

저장할 파일 경로의 앞 세자가 ftp이면 원격지로 업로드를 해야 하며 DgFtpUp 함수를 호출한다. 그렇지 않으면 로컬 파일이므로 평상시와 같이 그냥 저장하면 된다. FTP 서버로 파일을 업로드하는 함수는 다음과 같다.

 

BOOL DgFtpUp(TCHAR *Path, TCHAR *Text)

{

     HINTERNET hRemote;

     DWORD FileSize,Size, RemSize;

     DWORD dwWritten;

     BOOL Result=FALSE;

     TCHAR Server[256];

     TCHAR User[32];

     TCHAR Pass[32];

     TCHAR Dir[MAX_PATH];

     int Port;

     TCHAR *p,*p2;

     MSG msg;

     TCHAR Mes[400];

     HWND hDlgDown;

 

     bContDown=TRUE;

     hDlgDown=CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_DOWNLOAD),

          g_hFrameWnd, (DLGPROC)DGDownProc);

     SetDlgItemText(hDlgDown,IDC_STDOWN1,"인터넷 접속중...");

     SetWindowText(hDlgDown,"FTP 업로드");

     ShowWindow(hDlgDown,SW_SHOW);

     UpdateWindow(hDlgDown);

     EnableWindow(g_hFrameWnd, FALSE);

 

     ParseFtpInfo(Path,Server,User,Pass,p,Port);

     if (DgFtpConnect(Server,User,Pass,Port)==FALSE) {

          MessageBox(g_hFrameWnd, "FTP 업로드를 위해 인터넷에 접속할 수 없습니다","알림",MB_OK);

          goto NetFail;

     }

 

     for (;;) {

          p2=strchr(p,’/’);

          if (p2==NULL) {

              break;

          }

          lstrcpyn(Dir,p,p2-p+1);

          if (FtpSetCurrentDirectory(hFtp,Dir)==FALSE) {

              MessageBox(g_hFrameWnd,"FTP 서버에서 폴더를 찾을 수 없습니다.","알림",MB_OK);

              goto EndUp;

          }

          p=p2+1;

     }

 

     hRemote=FtpOpenFile(hFtp,p,GENERIC_WRITE,FTP_TRANSFER_TYPE_BINARY,0);

     if (hRemote == NULL) {

          MessageBox(g_hFrameWnd,"FTP 서버에서 파일을 찾을 수 없거나 쓰기 권한이 없습니다.","알림",MB_OK);

          goto EndUp;

     }

 

     wsprintf(Mes,"위치 : %s",Path);

     SetDlgItemText(hDlgDown,IDC_STDOWN1,Mes);

 

     p=Text;

     FileSize=RemSize=lstrlen(Text);

     for (;;) {

          Size=min(10000,RemSize);

          if (Size==0) {

              Result=TRUE;

              break;

          }

          Result=InternetWriteFile(hRemote,p,Size,&dwWritten);

          if (Result==FALSE) {

              MessageBox(g_hFrameWnd, "FTP 서버에 파일을 쓸 수 없습니다","알림",MB_OK);

              break;

          }

          if (bContDown==FALSE) {

              Result=FALSE;

              break;

          }

          p+=dwWritten;

          RemSize-=dwWritten;

          SendMessage(hDlgDown,WM_USER+1,(WPARAM)(p-Text),(LPARAM)FileSize);

          while (PeekMessage(&msg, NULL,0,0,PM_REMOVE)) {

              if (!IsDialogMessage(hDlgDown, &msg)) {

                   TranslateMessage(&msg);

                   DispatchMessage(&msg);

              }

          }

     }

 

     InternetCloseHandle(hRemote);

EndUp:

     DgFtpUnConnect();

NetFail:

     EnableWindow(g_hFrameWnd, TRUE);

     DestroyWindow(hDlgDown);

     return Result;

}

 

저장할 파일 경로 Path에 접속정보가 있으므로 ParseFtpInfo 함수로 이 정보를 추출하여 서버에 접속한다. 그리고 편집중인 문서를 업로드하기만 하면 된다. 애초에 파일 자체를 다운로드받지 않았으므로 업로드 대상은 파일이 아니라 파일 속의 데이터이다. 당근은 원격지의 파일 편집을 위해 별도의 임시 파일을 만들지 않는다. 이 함수가 제대로 동작하려면 접속한 FTP 서버에 쓰기 권한을 가지고 있어야 한다.