• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
Aucun tag

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

FFFTPのソースコードです。


Commit MetaInfo

Révision91f406cab5f34e42988386c9078f877783d7e816 (tree)
l'heure2013-02-18 01:18:32
Auteurs_kawamoto <s_kawamoto@user...>
Commiters_kawamoto

Message de Log

Add support for UPnP port mapping (Windows XP or later only).

Change Summary

Modification

Binary files a/FFFTP_Eng_Release/FFFTP.exe and b/FFFTP_Eng_Release/FFFTP.exe differ
Binary files a/Release/FFFTP.exe and b/Release/FFFTP.exe differ
--- a/Resource/FFFTP.rc
+++ b/Resource/FFFTP.rc
@@ -963,6 +963,7 @@ BEGIN
963963 "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,94,196,10
964964 CONTROL "切断時にQUITコマンドを送る(&U)",CONNECT_SENDQUIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,108,173,10
965965 CONTROL "RASの制御を行わない(&R)",CONNECT_NORAS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,122,173,10
966+ CONTROL "非PASVモード時にUPnPを制御する(&U)",CONNECT_UPNP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,136,173,10
966967 END
967968
968969 rasnotify_dlg DIALOG 0, 0, 158, 46
--- a/Resource/resource.h
+++ b/Resource/resource.h
@@ -235,6 +235,7 @@
235235 #define PERM_A_WRITE 1018
236236 #define CONNECT_NORAS 1018
237237 #define PERM_A_EXEC 1019
238+#define CONNECT_UPNP 1019
238239 #define PERM_TEXT 1020
239240 #define PERM_NOW 1021
240241 #define SORT_LFILE_FILE 1022
--- a/Resource_eng/FFFTP-eng.rc
+++ b/Resource_eng/FFFTP-eng.rc
@@ -984,6 +984,8 @@ BEGIN
984984 "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,109,173,10
985985 CONTROL "Do not control dialup (&RAS) connection",CONNECT_NORAS,
986986 "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,122,173,10
987+ CONTROL "Control &UPnP when using non PASV mode",CONNECT_UPNP,
988+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,136,173,10
987989 END
988990
989991 rasnotify_dlg DIALOG 0, 0, 158, 46
--- a/Resource_eng/resource.h
+++ b/Resource_eng/resource.h
@@ -235,6 +235,7 @@
235235 #define PERM_A_WRITE 1018
236236 #define CONNECT_NORAS 1018
237237 #define PERM_A_EXEC 1019
238+#define CONNECT_UPNP 1019
238239 #define PERM_TEXT 1020
239240 #define PERM_NOW 1021
240241 #define SORT_LFILE_FILE 1022
--- a/common.h
+++ b/common.h
@@ -1915,8 +1915,10 @@ void DeleteSocketWin(void);
19151915 // ソケットにデータを付与
19161916 int SetAsyncTableDataIPv4(SOCKET s, struct sockaddr_in* Host, struct sockaddr_in* Socks);
19171917 int SetAsyncTableDataIPv6(SOCKET s, struct sockaddr_in6* Host, struct sockaddr_in6* Socks);
1918+int SetAsyncTableDataMapPort(SOCKET s, int Port);
19181919 int GetAsyncTableDataIPv4(SOCKET s, struct sockaddr_in* Host, struct sockaddr_in* Socks);
19191920 int GetAsyncTableDataIPv6(SOCKET s, struct sockaddr_in6* Host, struct sockaddr_in6* Socks);
1921+int GetAsyncTableDataMapPort(SOCKET s, int* Port);
19201922 // IPv6対応
19211923 //struct hostent *do_gethostbyname(const char *Name, char *Buf, int Len, int *CancelCheckWork);
19221924 struct hostent *do_gethostbynameIPv4(const char *Name, char *Buf, int Len, int *CancelCheckWork);
@@ -1930,6 +1932,12 @@ int do_recv(SOCKET s, char *buf, int len, int flags, int *TimeOut, int *CancelCh
19301932 int do_send(SOCKET s, const char *buf, int len, int flags, int *TimeOutErr, int *CancelCheckWork);
19311933 // 同時接続対応
19321934 void RemoveReceivedData(SOCKET s);
1935+// UPnP対応
1936+int LoadUPnP();
1937+void FreeUPnP();
1938+int IsUPnPLoaded();
1939+int AddPortMapping(char* Adrs, int Port);
1940+int RemovePortMapping(int Port);
19331941 int CheckClosedAndReconnect(void);
19341942 // 同時接続対応
19351943 int CheckClosedAndReconnectTrnSkt(SOCKET *Skt, int *CancelCheckWork);
--- a/connect.c
+++ b/connect.c
@@ -2616,6 +2616,10 @@ SOCKET GetFTPListenSocketIPv4(SOCKET ctrl_skt, int *CancelCheckWork)
26162616 int Len;
26172617 int Fwall;
26182618
2619+ // UPnP対応
2620+ char Adrs[16];
2621+ int Port;
2622+
26192623 // ソケットにデータを付与
26202624 GetAsyncTableDataIPv4(ctrl_skt, &CurSockAddr, &SocksSockAddr);
26212625
@@ -2724,6 +2728,12 @@ SOCKET GetFTPListenSocketIPv4(SOCKET ctrl_skt, int *CancelCheckWork)
27242728
27252729 a = (char *)&saTmpAddr.sin_addr;
27262730 p = (char *)&saCtrlAddr.sin_port;
2731+ // UPnP対応
2732+ if(IsUPnPLoaded() == YES)
2733+ {
2734+ if(AddPortMapping(AddressToStringIPv4(Adrs, &saTmpAddr.sin_addr), ntohs(saCtrlAddr.sin_port)) == FFFTP_SUCCESS)
2735+ SetAsyncTableDataMapPort(listen_skt, ntohs(saCtrlAddr.sin_port));
2736+ }
27272737 }
27282738 else
27292739 {
@@ -2769,6 +2779,12 @@ SOCKET GetFTPListenSocketIPv4(SOCKET ctrl_skt, int *CancelCheckWork)
27692779 // IPv6対応
27702780 // SetTaskMsg(MSGJPN031);
27712781 SetTaskMsg(MSGJPN031, MSGJPN333);
2782+ // UPnP対応
2783+ if(IsUPnPLoaded() == YES)
2784+ {
2785+ if(GetAsyncTableDataMapPort(listen_skt, &Port) == YES)
2786+ RemovePortMapping(Port);
2787+ }
27722788 do_closesocket(listen_skt);
27732789 listen_skt = INVALID_SOCKET;
27742790 }
@@ -2796,6 +2812,8 @@ SOCKET GetFTPListenSocketIPv6(SOCKET ctrl_skt, int *CancelCheckWork)
27962812 int Fwall;
27972813
27982814 char Adrs[40];
2815+ // UPnP対応
2816+ int Port;
27992817
28002818 // ソケットにデータを付与
28012819 GetAsyncTableDataIPv6(ctrl_skt, &CurSockAddr, &SocksSockAddr);
@@ -2867,6 +2885,12 @@ SOCKET GetFTPListenSocketIPv6(SOCKET ctrl_skt, int *CancelCheckWork)
28672885
28682886 a = (char *)&saTmpAddr.sin6_addr;
28692887 p = (char *)&saCtrlAddr.sin6_port;
2888+ // UPnP対応
2889+ if(IsUPnPLoaded() == YES)
2890+ {
2891+ if(AddPortMapping(AddressToStringIPv6(Adrs, &saTmpAddr.sin6_addr), ntohs(saCtrlAddr.sin6_port)) == FFFTP_SUCCESS)
2892+ SetAsyncTableDataMapPort(listen_skt, ntohs(saCtrlAddr.sin6_port));
2893+ }
28702894 }
28712895 else
28722896 {
@@ -2908,6 +2932,12 @@ SOCKET GetFTPListenSocketIPv6(SOCKET ctrl_skt, int *CancelCheckWork)
29082932 (UC(p[0]) << 8) | UC(p[1])) / 100) != FTP_COMPLETE)
29092933 {
29102934 SetTaskMsg(MSGJPN031, MSGJPN334);
2935+ // UPnP対応
2936+ if(IsUPnPLoaded() == YES)
2937+ {
2938+ if(GetAsyncTableDataMapPort(listen_skt, &Port) == YES)
2939+ RemovePortMapping(Port);
2940+ }
29112941 do_closesocket(listen_skt);
29122942 listen_skt = INVALID_SOCKET;
29132943 }
--- a/getput.c
+++ b/getput.c
@@ -1429,6 +1429,8 @@ static int DownloadNonPassive(TRANSPACKET *Pkt, int *CancelCheckWork)
14291429 // struct sockaddr_in saSockAddr1;
14301430 struct sockaddr_in saSockAddrIPv4;
14311431 struct sockaddr_in6 saSockAddrIPv6;
1432+ // UPnP対応
1433+ int Port;
14321434 char Reply[ERR_MSG_LEN+7];
14331435
14341436 if((listen_socket = GetFTPListenSocket(Pkt->ctrl_skt, CancelCheckWork)) != INVALID_SOCKET)
@@ -1460,6 +1462,12 @@ static int DownloadNonPassive(TRANSPACKET *Pkt, int *CancelCheckWork)
14601462
14611463 if(shutdown(listen_socket, 1) != 0)
14621464 ReportWSError("shutdown listen", WSAGetLastError());
1465+ // UPnP対応
1466+ if(IsUPnPLoaded() == YES)
1467+ {
1468+ if(GetAsyncTableDataMapPort(listen_socket, &Port) == YES)
1469+ RemovePortMapping(Port);
1470+ }
14631471 listen_socket = DoClose(listen_socket);
14641472
14651473 if(data_socket == INVALID_SOCKET)
@@ -1506,12 +1514,29 @@ static int DownloadNonPassive(TRANSPACKET *Pkt, int *CancelCheckWork)
15061514 {
15071515 SetErrorMsg(Reply);
15081516 SetTaskMsg(MSGJPN090);
1517+ // UPnP対応
1518+ if(IsUPnPLoaded() == YES)
1519+ {
1520+ if(GetAsyncTableDataMapPort(listen_socket, &Port) == YES)
1521+ RemovePortMapping(Port);
1522+ }
15091523 listen_socket = DoClose(listen_socket);
15101524 iRetCode = 500;
15111525 }
15121526 }
15131527 else
1528+ // バグ修正
1529+// iRetCode = 500;
1530+ {
1531+ // UPnP対応
1532+ if(IsUPnPLoaded() == YES)
1533+ {
1534+ if(GetAsyncTableDataMapPort(listen_socket, &Port) == YES)
1535+ RemovePortMapping(Port);
1536+ }
1537+ listen_socket = DoClose(listen_socket);
15141538 iRetCode = 500;
1539+ }
15151540 }
15161541 else
15171542 {
@@ -2704,6 +2729,8 @@ static int UploadNonPassive(TRANSPACKET *Pkt)
27042729 // struct sockaddr_in saSockAddr1;
27052730 struct sockaddr_in saSockAddrIPv4;
27062731 struct sockaddr_in6 saSockAddrIPv6;
2732+ // UPnP対応
2733+ int Port;
27072734 int Resume;
27082735 char Reply[ERR_MSG_LEN+7];
27092736
@@ -2757,6 +2784,12 @@ static int UploadNonPassive(TRANSPACKET *Pkt)
27572784
27582785 if(shutdown(listen_socket, 1) != 0)
27592786 ReportWSError("shutdown listen", WSAGetLastError());
2787+ // UPnP対応
2788+ if(IsUPnPLoaded() == YES)
2789+ {
2790+ if(GetAsyncTableDataMapPort(listen_socket, &Port) == YES)
2791+ RemovePortMapping(Port);
2792+ }
27602793 listen_socket = DoClose(listen_socket);
27612794
27622795 if(data_socket == INVALID_SOCKET)
@@ -2803,6 +2836,12 @@ static int UploadNonPassive(TRANSPACKET *Pkt)
28032836 {
28042837 SetErrorMsg(Reply);
28052838 SetTaskMsg(MSGJPN108);
2839+ // UPnP対応
2840+ if(IsUPnPLoaded() == YES)
2841+ {
2842+ if(GetAsyncTableDataMapPort(listen_socket, &Port) == YES)
2843+ RemovePortMapping(Port);
2844+ }
28062845 listen_socket = DoClose(listen_socket);
28072846 iRetCode = 500;
28082847 }
--- a/main.c
+++ b/main.c
@@ -256,6 +256,8 @@ int MakeAllDir = YES;
256256 int LocalKanjiCode = KANJI_SJIS;
257257 // 自動切断対策
258258 int NoopEnable = NO;
259+// UPnP対応
260+int UPnPEnabled = NO;
259261 time_t LastDataConnectionTime = 0;
260262
261263
@@ -360,6 +362,10 @@ int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLi
360362
361363 InitCommonControls();
362364
365+ // UPnP対応
366+ CoInitialize(NULL);
367+ LoadUPnP();
368+
363369 // FTPS対応
364370 #ifdef USE_OPENSSL
365371 LoadOpenSSL();
@@ -405,6 +411,9 @@ int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLi
405411 #endif
406412 // SFTP対応
407413 FreePuTTY();
414+ // UPnP対応
415+ FreeUPnP();
416+ CoUninitialize();
408417 OleUninitialize();
409418 return(Ret);
410419 }
--- a/option.c
+++ b/option.c
@@ -178,6 +178,8 @@ extern int DispTimeSeconds;
178178 extern int DispPermissionsNumber;
179179 // ディレクトリ自動作成
180180 extern int MakeAllDir;
181+// UPnP対応
182+extern int UPnPEnabled;
181183
182184
183185 /*----- オプションのプロパティシート ------------------------------------------
@@ -1291,6 +1293,14 @@ static INT_PTR CALLBACK ConnectSettingProc(HWND hDlg, UINT message, WPARAM wPara
12911293 SendDlgItemMessage(hDlg, CONNECT_HIST_PASS, BM_SETCHECK, PassToHist, 0);
12921294 SendDlgItemMessage(hDlg, CONNECT_SENDQUIT, BM_SETCHECK, SendQuit, 0);
12931295 SendDlgItemMessage(hDlg, CONNECT_NORAS, BM_SETCHECK, NoRasControl, 0);
1296+ // UPnP対応
1297+ if(IsUPnPLoaded() == YES)
1298+ SendDlgItemMessage(hDlg, CONNECT_UPNP, BM_SETCHECK, UPnPEnabled, 0);
1299+ else
1300+ {
1301+ SendDlgItemMessage(hDlg, CONNECT_UPNP, BM_SETCHECK, BST_UNCHECKED, 0);
1302+ EnableWindow(GetDlgItem(hDlg, CONNECT_UPNP), FALSE);
1303+ }
12941304 return(TRUE);
12951305
12961306 case WM_NOTIFY:
@@ -1308,6 +1318,9 @@ static INT_PTR CALLBACK ConnectSettingProc(HWND hDlg, UINT message, WPARAM wPara
13081318 PassToHist = SendDlgItemMessage(hDlg, CONNECT_HIST_PASS, BM_GETCHECK, 0, 0);
13091319 SendQuit = SendDlgItemMessage(hDlg, CONNECT_SENDQUIT, BM_GETCHECK, 0, 0);
13101320 NoRasControl = SendDlgItemMessage(hDlg, CONNECT_NORAS, BM_GETCHECK, 0, 0);
1321+ // UPnP対応
1322+ if(IsUPnPLoaded() == YES)
1323+ UPnPEnabled = SendDlgItemMessage(hDlg, CONNECT_UPNP, BM_GETCHECK, 0, 0);
13111324 break;
13121325
13131326 case PSN_RESET :
--- a/registry.c
+++ b/registry.c
@@ -203,6 +203,8 @@ extern int DispPermissionsNumber;
203203 extern int MakeAllDir;
204204 // UTF-8対応
205205 extern int LocalKanjiCode;
206+// UPnP対応
207+extern int UPnPEnabled;
206208
207209 /*----- マスタパスワードの設定 ----------------------------------------------
208210 *
@@ -641,6 +643,8 @@ void SaveRegistry(void)
641643 WriteIntValueToReg(hKey4, "MakeDir", MakeAllDir);
642644 // UTF-8対応
643645 WriteIntValueToReg(hKey4, "Kanji", LocalKanjiCode);
646+ // UPnP対応
647+ WriteIntValueToReg(hKey4, "UPnP", UPnPEnabled);
644648 }
645649 CloseSubKey(hKey4);
646650 }
@@ -1053,6 +1057,8 @@ int LoadRegistry(void)
10531057 ReadIntValueFromReg(hKey4, "MakeDir", &MakeAllDir);
10541058 // UTF-8対応
10551059 ReadIntValueFromReg(hKey4, "Kanji", &LocalKanjiCode);
1060+ // UPnP対応
1061+ ReadIntValueFromReg(hKey4, "UPnP", &UPnPEnabled);
10561062
10571063 CloseSubKey(hKey4);
10581064 }
--- a/socket.c
+++ b/socket.c
@@ -37,6 +37,8 @@
3737 #include <time.h>
3838 #include <windowsx.h>
3939 #include <commctrl.h>
40+// UPnP対応
41+#include <natupnp.h>
4042
4143 #include "common.h"
4244 #include "resource.h"
@@ -71,6 +73,7 @@ typedef struct {
7173 struct sockaddr_in SocksAddrIPv4;
7274 struct sockaddr_in6 HostAddrIPv6;
7375 struct sockaddr_in6 SocksAddrIPv6;
76+ int MapPort;
7477 } ASYNCSIGNAL;
7578
7679
@@ -119,6 +122,9 @@ static ASYNCSIGNALDATABASE SignalDbase[MAX_SIGNAL_ENTRY_DBASE];
119122 // スレッド衝突のバグ修正
120123 static HANDLE hAsyncTblAccMutex;
121124
125+// UPnP対応
126+IUPnPNAT* pUPnPNAT;
127+IStaticPortMappingCollection* pUPnPMap;
122128
123129
124130
@@ -499,6 +505,7 @@ static int RegisterAsyncTable(SOCKET s)
499505 memset(&Signal[Pos].SocksAddrIPv4, 0, sizeof(struct sockaddr_in));
500506 memset(&Signal[Pos].HostAddrIPv6, 0, sizeof(struct sockaddr_in6));
501507 memset(&Signal[Pos].SocksAddrIPv6, 0, sizeof(struct sockaddr_in6));
508+ Signal[Pos].MapPort = 0;
502509 Sts = YES;
503510 break;
504511 }
@@ -699,6 +706,27 @@ int SetAsyncTableDataIPv6(SOCKET s, struct sockaddr_in6* Host, struct sockaddr_i
699706 return(Sts);
700707 }
701708
709+int SetAsyncTableDataMapPort(SOCKET s, int Port)
710+{
711+ int Sts;
712+ int Pos;
713+
714+ WaitForSingleObject(hAsyncTblAccMutex, INFINITE);
715+ Sts = NO;
716+ for(Pos = 0; Pos < MAX_SIGNAL_ENTRY; Pos++)
717+ {
718+ if(Signal[Pos].Socket == s)
719+ {
720+ Signal[Pos].MapPort = Port;
721+ Sts = YES;
722+ break;
723+ }
724+ }
725+ ReleaseMutex(hAsyncTblAccMutex);
726+
727+ return(Sts);
728+}
729+
702730 int GetAsyncTableDataIPv4(SOCKET s, struct sockaddr_in* Host, struct sockaddr_in* Socks)
703731 {
704732 int Sts;
@@ -747,6 +775,27 @@ int GetAsyncTableDataIPv6(SOCKET s, struct sockaddr_in6* Host, struct sockaddr_i
747775 return(Sts);
748776 }
749777
778+int GetAsyncTableDataMapPort(SOCKET s, int* Port)
779+{
780+ int Sts;
781+ int Pos;
782+
783+ WaitForSingleObject(hAsyncTblAccMutex, INFINITE);
784+ Sts = NO;
785+ for(Pos = 0; Pos < MAX_SIGNAL_ENTRY; Pos++)
786+ {
787+ if(Signal[Pos].Socket == s)
788+ {
789+ *Port = Signal[Pos].MapPort;
790+ Sts = YES;
791+ break;
792+ }
793+ }
794+ ReleaseMutex(hAsyncTblAccMutex);
795+
796+ return(Sts);
797+}
798+
750799
751800
752801
@@ -1308,6 +1357,82 @@ void RemoveReceivedData(SOCKET s)
13081357 }
13091358 }
13101359
1360+// UPnP対応
1361+int LoadUPnP()
1362+{
1363+ int Sts;
1364+ Sts = FFFTP_FAIL;
1365+ if(CoCreateInstance(&CLSID_UPnPNAT, NULL, CLSCTX_ALL, &IID_IUPnPNAT, (void**)&pUPnPNAT) == S_OK)
1366+ {
1367+ if(pUPnPNAT->lpVtbl->get_StaticPortMappingCollection(pUPnPNAT, &pUPnPMap) == S_OK)
1368+ Sts = FFFTP_SUCCESS;
1369+ }
1370+ return Sts;
1371+}
1372+
1373+void FreeUPnP()
1374+{
1375+ if(pUPnPMap != NULL)
1376+ pUPnPMap->lpVtbl->Release(pUPnPMap);
1377+ pUPnPMap = NULL;
1378+ if(pUPnPNAT != NULL)
1379+ pUPnPNAT->lpVtbl->Release(pUPnPNAT);
1380+ pUPnPNAT = NULL;
1381+}
1382+
1383+int IsUPnPLoaded()
1384+{
1385+ int Sts;
1386+ Sts = FFFTP_FAIL;
1387+ if(pUPnPNAT != NULL && pUPnPMap != NULL)
1388+ Sts = FFFTP_SUCCESS;
1389+ return Sts;
1390+}
1391+
1392+int AddPortMapping(char* Adrs, int Port)
1393+{
1394+ int Sts;
1395+ WCHAR Tmp1[40];
1396+ BSTR Tmp2;
1397+ BSTR Tmp3;
1398+ BSTR Tmp4;
1399+ IStaticPortMapping* pPortMap;
1400+ Sts = FFFTP_FAIL;
1401+ MtoW(Tmp1, 40, Adrs, -1);
1402+ if((Tmp2 = SysAllocString(Tmp1)) != NULL)
1403+ {
1404+ if((Tmp3 = SysAllocString(L"TCP")) != NULL)
1405+ {
1406+ if((Tmp4 = SysAllocString(L"FFFTP")) != NULL)
1407+ {
1408+ if(pUPnPMap->lpVtbl->Add(pUPnPMap, Port, Tmp3, Port, Tmp2, VARIANT_TRUE, Tmp4, &pPortMap) == S_OK)
1409+ {
1410+ Sts = FFFTP_SUCCESS;
1411+ pPortMap->lpVtbl->Release(pPortMap);
1412+ }
1413+ SysFreeString(Tmp4);
1414+ }
1415+ SysFreeString(Tmp3);
1416+ }
1417+ SysFreeString(Tmp2);
1418+ }
1419+ return Sts;
1420+}
1421+
1422+int RemovePortMapping(int Port)
1423+{
1424+ int Sts;
1425+ BSTR Tmp;
1426+ Sts = FFFTP_FAIL;
1427+ if((Tmp = SysAllocString(L"TCP")) != NULL)
1428+ {
1429+ if(pUPnPMap->lpVtbl->Remove(pUPnPMap, Port, Tmp) == S_OK)
1430+ Sts = FFFTP_SUCCESS;
1431+ SysFreeString(Tmp);
1432+ }
1433+ return Sts;
1434+}
1435+
13111436
13121437 /*-----
13131438 *
--- a/socketwrapper.c
+++ b/socketwrapper.c
@@ -794,6 +794,16 @@ int WSACancelAsyncRequestIPv6(HANDLE hAsyncTaskHandle)
794794 return Result;
795795 }
796796
797+char* AddressToStringIPv4(char* str, void* in)
798+{
799+ char* pResult;
800+ unsigned char* p;
801+ pResult = str;
802+ p = (unsigned char*)in;
803+ sprintf(str, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
804+ return pResult;
805+}
806+
797807 char* AddressToStringIPv6(char* str, void* in6)
798808 {
799809 char* pResult;
--- a/socketwrapper.h
+++ b/socketwrapper.h
@@ -34,6 +34,7 @@ int FTPS_recv(SOCKET s, char * buf, int len, int flags);
3434
3535 HANDLE WSAAsyncGetHostByNameIPv6(HWND hWnd, u_int wMsg, const char * name, char * buf, int buflen, short Family);
3636 int WSACancelAsyncRequestIPv6(HANDLE hAsyncTaskHandle);
37+char* AddressToStringIPv4(char* str, void* in);
3738 char* AddressToStringIPv6(char* str, void* in6);
3839 char* inet6_ntoa(struct in6_addr in6);
3940 struct in6_addr inet6_addr(const char* cp);