MakeNSISW now uses WinInet when checking for updates
git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6604 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
parent
e58680c996
commit
873e860f57
20 changed files with 144 additions and 1650 deletions
|
@ -195,6 +195,9 @@ Version History
|
||||||
2.3.2
|
2.3.2
|
||||||
- The size gripper can be used to resize the window
|
- The size gripper can be used to resize the window
|
||||||
|
|
||||||
|
2.3.3
|
||||||
|
- Update check switched from JNetLib to WinInet
|
||||||
|
|
||||||
|
|
||||||
Copyright Information
|
Copyright Information
|
||||||
---------------------
|
---------------------
|
||||||
|
|
|
@ -6,10 +6,6 @@ files = Split("""
|
||||||
utils.cpp
|
utils.cpp
|
||||||
version.cpp
|
version.cpp
|
||||||
update.cpp
|
update.cpp
|
||||||
jnetlib/asyncdns.cpp
|
|
||||||
jnetlib/connection.cpp
|
|
||||||
jnetlib/httpget.cpp
|
|
||||||
jnetlib/util.cpp
|
|
||||||
""")
|
""")
|
||||||
|
|
||||||
res = Split("""
|
res = Split("""
|
||||||
|
@ -36,7 +32,7 @@ libs = Split("""
|
||||||
shlwapi
|
shlwapi
|
||||||
comdlg32
|
comdlg32
|
||||||
comctl32
|
comctl32
|
||||||
wsock32
|
wininet
|
||||||
""")
|
""")
|
||||||
|
|
||||||
docs = Split("""
|
docs = Split("""
|
||||||
|
@ -53,7 +49,7 @@ BuildUtil(
|
||||||
res = res,
|
res = res,
|
||||||
resources = resources,
|
resources = resources,
|
||||||
entry = None,
|
entry = None,
|
||||||
defines = ['RELEASE=2.3.2'],
|
defines = ['RELEASE=2.3.3'],
|
||||||
docs = docs,
|
docs = docs,
|
||||||
root_util = True
|
root_util = True
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
/*
|
|
||||||
** JNetLib
|
|
||||||
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
|
||||||
** Author: Justin Frankel
|
|
||||||
** File: asyncdns.cpp - JNL portable asynchronous DNS implementation
|
|
||||||
** License: zlib
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Reviewed for Unicode support by Jim Park -- 08/16/2007
|
|
||||||
// Note: For Unicode Support, all string functions must explicitly use
|
|
||||||
// ANSI versions if UNICODE is defined.
|
|
||||||
|
|
||||||
#include "netinc.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "asyncdns.h"
|
|
||||||
|
|
||||||
JNL_AsyncDNS::JNL_AsyncDNS(int max_cache_entries)
|
|
||||||
{
|
|
||||||
m_thread_kill=1;
|
|
||||||
m_thread=0;
|
|
||||||
m_addr=0;
|
|
||||||
m_hostname[0]=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNL_AsyncDNS::~JNL_AsyncDNS()
|
|
||||||
{
|
|
||||||
m_thread_kill=1;
|
|
||||||
|
|
||||||
if (m_thread)
|
|
||||||
{
|
|
||||||
WaitForSingleObject(m_thread,INFINITE);
|
|
||||||
CloseHandle(m_thread);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD WINAPI JNL_AsyncDNS::_threadfunc(LPVOID _d)
|
|
||||||
{
|
|
||||||
JNL_AsyncDNS *_this=(JNL_AsyncDNS*)_d;
|
|
||||||
int nowinsock=JNL::open_socketlib();
|
|
||||||
struct hostent *hostentry;
|
|
||||||
hostentry=::gethostbyname(_this->m_hostname);
|
|
||||||
if (hostentry)
|
|
||||||
{
|
|
||||||
_this->m_addr=*((int*)hostentry->h_addr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_this->m_addr=INADDR_NONE;
|
|
||||||
if (!nowinsock) JNL::close_socketlib();
|
|
||||||
_this->m_thread_kill=1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JNL_AsyncDNS::resolve(char *hostname, unsigned long *addr)
|
|
||||||
{
|
|
||||||
// return 0 on success, 1 on wait, -1 on unresolvable
|
|
||||||
unsigned long ip=inet_addr(hostname);
|
|
||||||
if (ip != INADDR_NONE)
|
|
||||||
{
|
|
||||||
*addr=ip;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lstrcmpiA(m_hostname,hostname)) m_addr=0;
|
|
||||||
else if (m_addr == INADDR_NONE) return -1;
|
|
||||||
else if (m_addr)
|
|
||||||
{
|
|
||||||
*addr=m_addr;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
lstrcpyA(m_hostname,hostname);
|
|
||||||
|
|
||||||
if (m_thread_kill)
|
|
||||||
{
|
|
||||||
DWORD id;
|
|
||||||
if (m_thread) return -1;
|
|
||||||
m_thread_kill=0;
|
|
||||||
m_thread=CreateThread(NULL,0,_threadfunc,(LPVOID)this,0,&id);
|
|
||||||
if (!m_thread) return -1;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
** JNetLib
|
|
||||||
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
|
||||||
** Author: Justin Frankel
|
|
||||||
** File: asyncdns.h - JNL portable asynchronous DNS interface
|
|
||||||
** License: zlib
|
|
||||||
**
|
|
||||||
** Usage:
|
|
||||||
** 1. Create JNL_AsyncDNS object, optionally with the number of cache entries.
|
|
||||||
** 2. call resolve() to resolve a hostname into an address. The return value of
|
|
||||||
** resolve is 0 on success (host successfully resolved), 1 on wait (meaning
|
|
||||||
** try calling resolve() with the same hostname in a few hundred milliseconds
|
|
||||||
** or so), or -1 on error (i.e. the host can't resolve).
|
|
||||||
** 4. enjoy.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Reviewed for Unicode support by Jim Park -- 08/16/2007
|
|
||||||
// Note: Inet host name is strictly ANSI, no UNICODE for now.
|
|
||||||
|
|
||||||
#ifndef _ASYNCDNS_H_
|
|
||||||
#define _ASYNCDNS_H_
|
|
||||||
|
|
||||||
class JNL_AsyncDNS
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JNL_AsyncDNS(int max_cache_entries=64);
|
|
||||||
~JNL_AsyncDNS();
|
|
||||||
|
|
||||||
int resolve(char *hostname, unsigned long *addr); // return 0 on success, 1 on wait, -1 on unresolvable
|
|
||||||
|
|
||||||
private:
|
|
||||||
char m_hostname[256];
|
|
||||||
unsigned long m_addr;
|
|
||||||
|
|
||||||
volatile int m_thread_kill;
|
|
||||||
HANDLE m_thread;
|
|
||||||
static DWORD WINAPI _threadfunc(LPVOID _d);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //_ASYNCDNS_H_
|
|
|
@ -1,449 +0,0 @@
|
||||||
/*
|
|
||||||
** JNetLib
|
|
||||||
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
|
||||||
** Author: Justin Frankel
|
|
||||||
** File: connection.cpp - JNL TCP connection implementation
|
|
||||||
** License: zlib
|
|
||||||
**
|
|
||||||
** Reviewed for Unicode support by Jim Park -- 08/17/2007
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "netinc.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "connection.h"
|
|
||||||
|
|
||||||
|
|
||||||
JNL_Connection::JNL_Connection(JNL_AsyncDNS *dns, int sendbufsize, int recvbufsize)
|
|
||||||
{
|
|
||||||
m_errorstr="";
|
|
||||||
if (dns == JNL_CONNECTION_AUTODNS)
|
|
||||||
{
|
|
||||||
m_dns=new JNL_AsyncDNS();
|
|
||||||
m_dns_owned=1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_dns=dns;
|
|
||||||
m_dns_owned=0;
|
|
||||||
}
|
|
||||||
m_recv_buffer_len=recvbufsize;
|
|
||||||
m_send_buffer_len=sendbufsize;
|
|
||||||
m_recv_buffer=(char*)malloc(m_recv_buffer_len);
|
|
||||||
m_send_buffer=(char*)malloc(m_send_buffer_len);
|
|
||||||
m_socket=INVALID_SOCKET;
|
|
||||||
memset(m_recv_buffer,0,recvbufsize);
|
|
||||||
memset(m_send_buffer,0,sendbufsize);
|
|
||||||
m_remote_port=0;
|
|
||||||
m_state=STATE_NOCONNECTION;
|
|
||||||
m_recv_len=m_recv_pos=0;
|
|
||||||
m_send_len=m_send_pos=0;
|
|
||||||
m_host[0]=0;
|
|
||||||
memset(&m_saddr,0,sizeof(m_saddr));
|
|
||||||
}
|
|
||||||
|
|
||||||
void JNL_Connection::connect(PORTABLE_SOCKET s, struct sockaddr_in *loc)
|
|
||||||
{
|
|
||||||
close(1);
|
|
||||||
m_socket=s;
|
|
||||||
m_remote_port=0;
|
|
||||||
m_dns=NULL;
|
|
||||||
if (loc) m_saddr=*loc;
|
|
||||||
else memset(&m_saddr,0,sizeof(m_saddr));
|
|
||||||
if (m_socket != INVALID_SOCKET)
|
|
||||||
{
|
|
||||||
SET_SOCK_BLOCK(m_socket,0);
|
|
||||||
m_state=STATE_CONNECTED;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_errorstr="invalid socket passed to connect";
|
|
||||||
m_state=STATE_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JNL_Connection::connect(char *hostname, int port)
|
|
||||||
{
|
|
||||||
close(1);
|
|
||||||
m_remote_port=(short)port;
|
|
||||||
m_socket=::socket(AF_INET,SOCK_STREAM,0);
|
|
||||||
if (m_socket==INVALID_SOCKET)
|
|
||||||
{
|
|
||||||
m_errorstr="creating socket";
|
|
||||||
m_state=STATE_ERROR;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SET_SOCK_BLOCK(m_socket,0);
|
|
||||||
strncpy(m_host,hostname,sizeof(m_host)-1);
|
|
||||||
m_host[sizeof(m_host)-1]=0;
|
|
||||||
memset(&m_saddr,0,sizeof(m_saddr));
|
|
||||||
if (!m_host[0])
|
|
||||||
{
|
|
||||||
m_errorstr="empty hostname";
|
|
||||||
m_state=STATE_ERROR;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_state=STATE_RESOLVING;
|
|
||||||
m_saddr.sin_family=AF_INET;
|
|
||||||
m_saddr.sin_port=htons((unsigned short)port);
|
|
||||||
m_saddr.sin_addr.s_addr=inet_addr(hostname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JNL_Connection::~JNL_Connection()
|
|
||||||
{
|
|
||||||
if (m_socket != INVALID_SOCKET)
|
|
||||||
{
|
|
||||||
::shutdown(m_socket, SHUT_RDWR);
|
|
||||||
::closesocket(m_socket);
|
|
||||||
m_socket=INVALID_SOCKET;
|
|
||||||
}
|
|
||||||
free(m_recv_buffer);
|
|
||||||
free(m_send_buffer);
|
|
||||||
if (m_dns_owned)
|
|
||||||
{
|
|
||||||
delete m_dns;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JNL_Connection::run(int max_send_bytes, int max_recv_bytes, int *bytes_sent, int *bytes_rcvd)
|
|
||||||
{
|
|
||||||
int bytes_allowed_to_send=(max_send_bytes<0)?m_send_buffer_len:max_send_bytes;
|
|
||||||
int bytes_allowed_to_recv=(max_recv_bytes<0)?m_recv_buffer_len:max_recv_bytes;
|
|
||||||
|
|
||||||
if (bytes_sent) *bytes_sent=0;
|
|
||||||
if (bytes_rcvd) *bytes_rcvd=0;
|
|
||||||
|
|
||||||
switch (m_state)
|
|
||||||
{
|
|
||||||
case STATE_RESOLVING:
|
|
||||||
if (m_saddr.sin_addr.s_addr == INADDR_NONE)
|
|
||||||
{
|
|
||||||
int a=m_dns?m_dns->resolve(m_host,(unsigned long int *)&m_saddr.sin_addr.s_addr):-1;
|
|
||||||
if (!a) { m_state=STATE_CONNECTING; }
|
|
||||||
else if (a == 1)
|
|
||||||
{
|
|
||||||
m_state=STATE_RESOLVING;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_errorstr="resolving hostname";
|
|
||||||
m_state=STATE_ERROR;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!::connect(m_socket,(struct sockaddr *)&m_saddr,16))
|
|
||||||
{
|
|
||||||
m_state=STATE_CONNECTED;
|
|
||||||
}
|
|
||||||
else if (ERRNO!=EINPROGRESS)
|
|
||||||
{
|
|
||||||
m_errorstr="connecting to host";
|
|
||||||
m_state=STATE_ERROR;
|
|
||||||
}
|
|
||||||
else { m_state=STATE_CONNECTING; }
|
|
||||||
break;
|
|
||||||
case STATE_CONNECTING:
|
|
||||||
{
|
|
||||||
fd_set f[3];
|
|
||||||
FD_ZERO(&f[0]);
|
|
||||||
FD_ZERO(&f[1]);
|
|
||||||
FD_ZERO(&f[2]);
|
|
||||||
FD_SET(m_socket,&f[0]);
|
|
||||||
FD_SET(m_socket,&f[1]);
|
|
||||||
FD_SET(m_socket,&f[2]);
|
|
||||||
struct timeval tv;
|
|
||||||
memset(&tv,0,sizeof(tv));
|
|
||||||
if (select((int)(m_socket+1),&f[0],&f[1],&f[2],&tv)==-1)
|
|
||||||
{
|
|
||||||
m_errorstr="connecting to host (calling select())";
|
|
||||||
m_state=STATE_ERROR;
|
|
||||||
}
|
|
||||||
else if (FD_ISSET(m_socket,&f[1]))
|
|
||||||
{
|
|
||||||
m_state=STATE_CONNECTED;
|
|
||||||
}
|
|
||||||
else if (FD_ISSET(m_socket,&f[2]))
|
|
||||||
{
|
|
||||||
m_errorstr="connecting to host";
|
|
||||||
m_state=STATE_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case STATE_CONNECTED:
|
|
||||||
case STATE_CLOSING:
|
|
||||||
if (m_send_len>0 && bytes_allowed_to_send>0)
|
|
||||||
{
|
|
||||||
int len=m_send_buffer_len-m_send_pos;
|
|
||||||
if (len > m_send_len) len=m_send_len;
|
|
||||||
if (len > bytes_allowed_to_send) len=bytes_allowed_to_send;
|
|
||||||
if (len > 0)
|
|
||||||
{
|
|
||||||
int res=::send(m_socket,m_send_buffer+m_send_pos,len,0);
|
|
||||||
if (res==-1 && ERRNO != EWOULDBLOCK)
|
|
||||||
{
|
|
||||||
// m_state=STATE_CLOSED;
|
|
||||||
// return;
|
|
||||||
}
|
|
||||||
if (res>0)
|
|
||||||
{
|
|
||||||
bytes_allowed_to_send-=res;
|
|
||||||
if (bytes_sent) *bytes_sent+=res;
|
|
||||||
m_send_pos+=res;
|
|
||||||
m_send_len-=res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m_send_pos>=m_send_buffer_len)
|
|
||||||
{
|
|
||||||
m_send_pos=0;
|
|
||||||
if (m_send_len>0)
|
|
||||||
{
|
|
||||||
len=m_send_buffer_len-m_send_pos;
|
|
||||||
if (len > m_send_len) len=m_send_len;
|
|
||||||
if (len > bytes_allowed_to_send) len=bytes_allowed_to_send;
|
|
||||||
int res=::send(m_socket,m_send_buffer+m_send_pos,len,0);
|
|
||||||
if (res==-1 && ERRNO != EWOULDBLOCK)
|
|
||||||
{
|
|
||||||
// m_state=STATE_CLOSED;
|
|
||||||
}
|
|
||||||
if (res>0)
|
|
||||||
{
|
|
||||||
bytes_allowed_to_send-=res;
|
|
||||||
if (bytes_sent) *bytes_sent+=res;
|
|
||||||
m_send_pos+=res;
|
|
||||||
m_send_len-=res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m_recv_len<m_recv_buffer_len)
|
|
||||||
{
|
|
||||||
int len=m_recv_buffer_len-m_recv_pos;
|
|
||||||
if (len > m_recv_buffer_len-m_recv_len) len=m_recv_buffer_len-m_recv_len;
|
|
||||||
if (len > bytes_allowed_to_recv) len=bytes_allowed_to_recv;
|
|
||||||
if (len>0)
|
|
||||||
{
|
|
||||||
int res=::recv(m_socket,m_recv_buffer+m_recv_pos,len,0);
|
|
||||||
if (res == 0 || (res < 0 && ERRNO != EWOULDBLOCK))
|
|
||||||
{
|
|
||||||
m_state=STATE_CLOSED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (res > 0)
|
|
||||||
{
|
|
||||||
bytes_allowed_to_recv-=res;
|
|
||||||
if (bytes_rcvd) *bytes_rcvd+=res;
|
|
||||||
m_recv_pos+=res;
|
|
||||||
m_recv_len+=res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m_recv_pos >= m_recv_buffer_len)
|
|
||||||
{
|
|
||||||
m_recv_pos=0;
|
|
||||||
if (m_recv_len < m_recv_buffer_len)
|
|
||||||
{
|
|
||||||
len=m_recv_buffer_len-m_recv_len;
|
|
||||||
if (len > bytes_allowed_to_recv) len=bytes_allowed_to_recv;
|
|
||||||
if (len > 0)
|
|
||||||
{
|
|
||||||
int res=::recv(m_socket,m_recv_buffer+m_recv_pos,len,0);
|
|
||||||
if (res == 0 || (res < 0 && ERRNO != EWOULDBLOCK))
|
|
||||||
{
|
|
||||||
m_state=STATE_CLOSED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (res > 0)
|
|
||||||
{
|
|
||||||
bytes_allowed_to_recv-=res;
|
|
||||||
if (bytes_rcvd) *bytes_rcvd+=res;
|
|
||||||
m_recv_pos+=res;
|
|
||||||
m_recv_len+=res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m_state == STATE_CLOSING)
|
|
||||||
{
|
|
||||||
if (m_send_len < 1) m_state = STATE_CLOSED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JNL_Connection::close(int quick)
|
|
||||||
{
|
|
||||||
if (quick || m_state == STATE_RESOLVING || m_state == STATE_CONNECTING)
|
|
||||||
{
|
|
||||||
m_state=STATE_CLOSED;
|
|
||||||
if (m_socket != INVALID_SOCKET)
|
|
||||||
{
|
|
||||||
::shutdown(m_socket, SHUT_RDWR);
|
|
||||||
::closesocket(m_socket);
|
|
||||||
}
|
|
||||||
m_socket=INVALID_SOCKET;
|
|
||||||
memset(m_recv_buffer,0,m_recv_buffer_len);
|
|
||||||
memset(m_send_buffer,0,m_send_buffer_len);
|
|
||||||
m_remote_port=0;
|
|
||||||
m_recv_len=m_recv_pos=0;
|
|
||||||
m_send_len=m_send_pos=0;
|
|
||||||
m_host[0]=0;
|
|
||||||
memset(&m_saddr,0,sizeof(m_saddr));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (m_state == STATE_CONNECTED) m_state=STATE_CLOSING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int JNL_Connection::send_bytes_in_queue(void)
|
|
||||||
{
|
|
||||||
return m_send_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JNL_Connection::send_bytes_available(void)
|
|
||||||
{
|
|
||||||
return m_send_buffer_len-m_send_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JNL_Connection::send(char *data, int length)
|
|
||||||
{
|
|
||||||
if (length > send_bytes_available())
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int write_pos=m_send_pos+m_send_len;
|
|
||||||
if (write_pos >= m_send_buffer_len)
|
|
||||||
{
|
|
||||||
write_pos-=m_send_buffer_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int len=m_send_buffer_len-write_pos;
|
|
||||||
if (len > length)
|
|
||||||
{
|
|
||||||
len=length;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(m_send_buffer+write_pos,data,len);
|
|
||||||
if (length > len)
|
|
||||||
{
|
|
||||||
memcpy(m_send_buffer,data+len,length-len);
|
|
||||||
}
|
|
||||||
m_send_len+=length;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JNL_Connection::send_string(char *line)
|
|
||||||
{
|
|
||||||
return send(line,strlen(line));
|
|
||||||
}
|
|
||||||
|
|
||||||
int JNL_Connection::recv_bytes_available(void)
|
|
||||||
{
|
|
||||||
return m_recv_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JNL_Connection::peek_bytes(char *data, int maxlength)
|
|
||||||
{
|
|
||||||
if (maxlength > m_recv_len)
|
|
||||||
{
|
|
||||||
maxlength=m_recv_len;
|
|
||||||
}
|
|
||||||
int read_pos=m_recv_pos-m_recv_len;
|
|
||||||
if (read_pos < 0)
|
|
||||||
{
|
|
||||||
read_pos += m_recv_buffer_len;
|
|
||||||
}
|
|
||||||
int len=m_recv_buffer_len-read_pos;
|
|
||||||
if (len > maxlength)
|
|
||||||
{
|
|
||||||
len=maxlength;
|
|
||||||
}
|
|
||||||
memcpy(data,m_recv_buffer+read_pos,len);
|
|
||||||
if (len < maxlength)
|
|
||||||
{
|
|
||||||
memcpy(data+len,m_recv_buffer,maxlength-len);
|
|
||||||
}
|
|
||||||
|
|
||||||
return maxlength;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JNL_Connection::recv_bytes(char *data, int maxlength)
|
|
||||||
{
|
|
||||||
|
|
||||||
int ml=peek_bytes(data,maxlength);
|
|
||||||
m_recv_len-=ml;
|
|
||||||
return ml;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JNL_Connection::getbfromrecv(int pos, int remove)
|
|
||||||
{
|
|
||||||
int read_pos=m_recv_pos-m_recv_len + pos;
|
|
||||||
if (pos < 0 || pos > m_recv_len) return -1;
|
|
||||||
if (read_pos < 0)
|
|
||||||
{
|
|
||||||
read_pos += m_recv_buffer_len;
|
|
||||||
}
|
|
||||||
if (read_pos >= m_recv_buffer_len)
|
|
||||||
{
|
|
||||||
read_pos-=m_recv_buffer_len;
|
|
||||||
}
|
|
||||||
if (remove) m_recv_len--;
|
|
||||||
return m_recv_buffer[read_pos];
|
|
||||||
}
|
|
||||||
|
|
||||||
int JNL_Connection::recv_lines_available(void)
|
|
||||||
{
|
|
||||||
int l=recv_bytes_available();
|
|
||||||
int lcount=0;
|
|
||||||
int lastch=0;
|
|
||||||
int pos;
|
|
||||||
for (pos=0; pos < l; pos ++)
|
|
||||||
{
|
|
||||||
int t=getbfromrecv(pos,0);
|
|
||||||
if (t == -1) return lcount;
|
|
||||||
if ((t=='\r' || t=='\n') &&(
|
|
||||||
(lastch != '\r' && lastch != '\n') || lastch==t
|
|
||||||
)) lcount++;
|
|
||||||
lastch=t;
|
|
||||||
}
|
|
||||||
return lcount;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JNL_Connection::recv_line(char *line, int maxlength)
|
|
||||||
{
|
|
||||||
if (maxlength > m_recv_len) maxlength=m_recv_len;
|
|
||||||
while (maxlength--)
|
|
||||||
{
|
|
||||||
int t=getbfromrecv(0,1);
|
|
||||||
if (t == -1)
|
|
||||||
{
|
|
||||||
*line=0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (t == '\r' || t == '\n')
|
|
||||||
{
|
|
||||||
int r=getbfromrecv(0,0);
|
|
||||||
if ((r == '\r' || r == '\n') && r != t) getbfromrecv(0,1);
|
|
||||||
*line=0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*line++=(char)t;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long JNL_Connection::get_interface(void)
|
|
||||||
{
|
|
||||||
if (m_socket==INVALID_SOCKET) return 0;
|
|
||||||
struct sockaddr_in sin;
|
|
||||||
memset(&sin,0,sizeof(sin));
|
|
||||||
socklen_t len=16;
|
|
||||||
if (::getsockname(m_socket,(struct sockaddr *)&sin,&len)) return 0;
|
|
||||||
return (unsigned long) sin.sin_addr.s_addr;
|
|
||||||
}
|
|
|
@ -1,138 +0,0 @@
|
||||||
/*
|
|
||||||
** JNetLib
|
|
||||||
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
|
||||||
** Author: Justin Frankel
|
|
||||||
** File: connection.h - JNL TCP connection interface
|
|
||||||
** License: zlib
|
|
||||||
**
|
|
||||||
** Usage:
|
|
||||||
** 1. Create a JNL_Connection object, optionally specifying a JNL_AsyncDNS
|
|
||||||
** object to use (or NULL for none, or JNL_CONNECTION_AUTODNS for auto),
|
|
||||||
** and the send and receive buffer sizes.
|
|
||||||
** 2. Call connect() to have it connect to a host/port (the hostname will be
|
|
||||||
** resolved if possible).
|
|
||||||
** 3. call run() with the maximum send/recv amounts, and optionally parameters
|
|
||||||
** so you can tell how much has been send/received. You want to do this a lot, while:
|
|
||||||
** 4. check get_state() to check the state of the connection. The states are:
|
|
||||||
** JNL_Connection::STATE_ERROR
|
|
||||||
** - an error has occurred on the connection. the connection has closed,
|
|
||||||
** and you can no longer write to the socket (there still might be
|
|
||||||
** data in the receive buffer - use recv_bytes_available()).
|
|
||||||
** JNL_Connection::STATE_NOCONNECTION
|
|
||||||
** - no connection has been made yet. call connect() already! :)
|
|
||||||
** JNL_Connection::STATE_RESOLVING
|
|
||||||
** - the connection is still waiting for a JNL_AsycnDNS to resolve the
|
|
||||||
** host.
|
|
||||||
** JNL_Connection::STATE_CONNECTING
|
|
||||||
** - the asynchronous call to connect() is still running.
|
|
||||||
** JNL_Connection::STATE_CONNECTED
|
|
||||||
** - the connection has connected, all is well.
|
|
||||||
** JNL_Connection::STATE_CLOSING
|
|
||||||
** - the connection is closing. This happens after a call to close,
|
|
||||||
** without the quick parameter set. This means that the connection
|
|
||||||
** will close once the data in the send buffer is sent (data could
|
|
||||||
** still be being received when it would be closed). After it is
|
|
||||||
** closed, the state will transition to:
|
|
||||||
** JNL_Connection::STATE_CLOSED
|
|
||||||
** - the connection has closed, generally without error. There still
|
|
||||||
** might be data in the receieve buffer, use recv_bytes_available().
|
|
||||||
** 5. Use send() and send_string() to send data. You can use
|
|
||||||
** send_bytes_in_queue() to see how much has yet to go out, or
|
|
||||||
** send_bytes_available() to see how much you can write. If you use send()
|
|
||||||
** or send_string() and not enough room is available, both functions will
|
|
||||||
** return error ( < 0)
|
|
||||||
** 6. Use recv() and recv_line() to get data. If you want to see how much data
|
|
||||||
** there is, use recv_bytes_available() and recv_lines_available(). If you
|
|
||||||
** call recv() and not enough data is available, recv() will return how much
|
|
||||||
** data was actually read. See comments at the function defs.
|
|
||||||
**
|
|
||||||
** 7. To close, call close(1) for a quick close, or close() for a close that will
|
|
||||||
** make the socket close after sending all the data sent.
|
|
||||||
**
|
|
||||||
** 8. delete ye' ol' object.
|
|
||||||
**
|
|
||||||
** Reviewed for Unicode Support by Jim Park -- 08/17/2007
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _CONNECTION_H_
|
|
||||||
#define _CONNECTION_H_
|
|
||||||
|
|
||||||
#include "asyncdns.h"
|
|
||||||
#include "netinc.h"
|
|
||||||
|
|
||||||
#define JNL_CONNECTION_AUTODNS ((JNL_AsyncDNS*)-1)
|
|
||||||
|
|
||||||
class JNL_Connection
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
STATE_ERROR,
|
|
||||||
STATE_NOCONNECTION,
|
|
||||||
STATE_RESOLVING,
|
|
||||||
STATE_CONNECTING,
|
|
||||||
STATE_CONNECTED,
|
|
||||||
STATE_CLOSING,
|
|
||||||
STATE_CLOSED
|
|
||||||
} state;
|
|
||||||
|
|
||||||
JNL_Connection(JNL_AsyncDNS *dns=JNL_CONNECTION_AUTODNS, int sendbufsize=8192, int recvbufsize=8192);
|
|
||||||
~JNL_Connection();
|
|
||||||
|
|
||||||
void connect(char *hostname, int port);
|
|
||||||
void connect(PORTABLE_SOCKET sock, struct sockaddr_in *loc=NULL); // used by the listen object, usually not needed by users.
|
|
||||||
|
|
||||||
void run(int max_send_bytes=-1, int max_recv_bytes=-1, int *bytes_sent=NULL, int *bytes_rcvd=NULL);
|
|
||||||
int get_state() { return m_state; }
|
|
||||||
const char *get_errstr() { return m_errorstr; }
|
|
||||||
|
|
||||||
void close(int quick=0);
|
|
||||||
void flush_send(void) { m_send_len=m_send_pos=0; }
|
|
||||||
|
|
||||||
int send_bytes_in_queue(void);
|
|
||||||
int send_bytes_available(void);
|
|
||||||
int send(char *data, int length); // returns -1 if not enough room
|
|
||||||
int send_string(char *line); // returns -1 if not enough room
|
|
||||||
|
|
||||||
|
|
||||||
int recv_bytes_available(void);
|
|
||||||
int recv_bytes(char *data, int maxlength); // returns actual bytes read
|
|
||||||
unsigned int recv_int(void);
|
|
||||||
int recv_lines_available(void);
|
|
||||||
int recv_line(char *line, int maxlength); // returns 0 if the line was terminated with a \r or \n, 1 if not.
|
|
||||||
// (i.e. if you specify maxlength=10, and the line is 12 bytes long
|
|
||||||
// it will return 1. or if there is no \r or \n and that's all the data
|
|
||||||
// the connection has.)
|
|
||||||
int peek_bytes(char *data, int maxlength); // returns bytes peeked
|
|
||||||
|
|
||||||
unsigned long get_interface(void); // this returns the interface the connection is on
|
|
||||||
unsigned long get_remote(void) { return m_saddr.sin_addr.s_addr; } // remote host ip.
|
|
||||||
short get_remote_port(void) { return m_remote_port; } // this returns the remote port of connection
|
|
||||||
|
|
||||||
protected:
|
|
||||||
PORTABLE_SOCKET m_socket;
|
|
||||||
short m_remote_port;
|
|
||||||
char *m_recv_buffer;
|
|
||||||
char *m_send_buffer;
|
|
||||||
int m_recv_buffer_len;
|
|
||||||
int m_send_buffer_len;
|
|
||||||
|
|
||||||
int m_recv_pos;
|
|
||||||
int m_recv_len;
|
|
||||||
int m_send_pos;
|
|
||||||
int m_send_len;
|
|
||||||
|
|
||||||
struct sockaddr_in m_saddr;
|
|
||||||
char m_host[256];
|
|
||||||
|
|
||||||
JNL_AsyncDNS *m_dns;
|
|
||||||
int m_dns_owned;
|
|
||||||
|
|
||||||
state m_state;
|
|
||||||
const char *m_errorstr;
|
|
||||||
|
|
||||||
int getbfromrecv(int pos, int remove); // used by recv_line*
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // _Connection_H_
|
|
|
@ -1,480 +0,0 @@
|
||||||
/*
|
|
||||||
** JNetLib
|
|
||||||
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
|
||||||
** Author: Justin Frankel
|
|
||||||
** File: httpget.cpp - JNL HTTP GET implementation
|
|
||||||
** License: zlib
|
|
||||||
**
|
|
||||||
** Reviewed for Unicode Support by Jim Park -- 08/17/2007
|
|
||||||
** Note: The functions that work on char's should be explicitely set to use the
|
|
||||||
** ANSI versions. Some of the functions like wprintf() are #defined to be
|
|
||||||
** the wide-char versions when _UNICODE is defined. So these must be explictly
|
|
||||||
** set to use the ANSI versions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "netinc.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "httpget.h"
|
|
||||||
|
|
||||||
void *operator new( size_t num_bytes ){return GlobalAlloc(GPTR,num_bytes);}
|
|
||||||
void operator delete( void *p ) { if (p) GlobalFree(p); }
|
|
||||||
|
|
||||||
JNL_HTTPGet::JNL_HTTPGet(JNL_AsyncDNS *dns, int recvbufsize, char *proxy)
|
|
||||||
{
|
|
||||||
m_recvbufsize=recvbufsize;
|
|
||||||
m_dns=dns;
|
|
||||||
m_con=NULL;
|
|
||||||
m_http_proxylpinfo=0;
|
|
||||||
m_http_proxyhost=0;
|
|
||||||
m_http_proxyport=0;
|
|
||||||
if (proxy && *proxy)
|
|
||||||
{
|
|
||||||
char *p=(char*)malloc(strlen(proxy)+1);
|
|
||||||
if (p)
|
|
||||||
{
|
|
||||||
char *r=NULL;
|
|
||||||
strcpy(p,proxy);
|
|
||||||
do_parse_url(p,&m_http_proxyhost,&m_http_proxyport,&r,&m_http_proxylpinfo);
|
|
||||||
free(r);
|
|
||||||
free(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_sendheaders=NULL;
|
|
||||||
reinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void JNL_HTTPGet::reinit()
|
|
||||||
{
|
|
||||||
m_errstr=0;
|
|
||||||
m_recvheaders=NULL;
|
|
||||||
m_recvheaders_size=0;
|
|
||||||
m_http_state=0;
|
|
||||||
m_http_port=0;
|
|
||||||
m_http_url=0;
|
|
||||||
m_reply=0;
|
|
||||||
m_http_host=m_http_lpinfo=m_http_request=NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void JNL_HTTPGet::deinit()
|
|
||||||
{
|
|
||||||
delete m_con;
|
|
||||||
free(m_recvheaders);
|
|
||||||
|
|
||||||
free(m_http_url);
|
|
||||||
free(m_http_host);
|
|
||||||
free(m_http_lpinfo);
|
|
||||||
free(m_http_request);
|
|
||||||
free(m_errstr);
|
|
||||||
free(m_reply);
|
|
||||||
reinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
JNL_HTTPGet::~JNL_HTTPGet()
|
|
||||||
{
|
|
||||||
deinit();
|
|
||||||
free(m_sendheaders);
|
|
||||||
free(m_http_proxylpinfo);
|
|
||||||
free(m_http_proxyhost);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void JNL_HTTPGet::addheader(const char *header)
|
|
||||||
{
|
|
||||||
//if (strstr(header,"\r") || strstr(header,"\n")) return;
|
|
||||||
if (!m_sendheaders)
|
|
||||||
{
|
|
||||||
m_sendheaders=(char*)malloc(strlen(header)+3);
|
|
||||||
if (m_sendheaders)
|
|
||||||
{
|
|
||||||
strcpy(m_sendheaders,header);
|
|
||||||
strcat(m_sendheaders,"\r\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
char *t=(char*)malloc(strlen(header)+strlen(m_sendheaders)+1+2);
|
|
||||||
if (t)
|
|
||||||
{
|
|
||||||
strcpy(t,m_sendheaders);
|
|
||||||
strcat(t,header);
|
|
||||||
strcat(t,"\r\n");
|
|
||||||
free(m_sendheaders);
|
|
||||||
m_sendheaders=t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JNL_HTTPGet::do_encode_mimestr(char *in, char *out)
|
|
||||||
{
|
|
||||||
char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
||||||
int shift = 0;
|
|
||||||
int accum = 0;
|
|
||||||
|
|
||||||
while (*in)
|
|
||||||
{
|
|
||||||
if (*in)
|
|
||||||
{
|
|
||||||
accum <<= 8;
|
|
||||||
shift += 8;
|
|
||||||
accum |= *in++;
|
|
||||||
}
|
|
||||||
while ( shift >= 6 )
|
|
||||||
{
|
|
||||||
shift -= 6;
|
|
||||||
*out++ = alphabet[(accum >> shift) & 0x3F];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (shift == 4)
|
|
||||||
{
|
|
||||||
*out++ = alphabet[(accum & 0xF)<<2];
|
|
||||||
*out++='=';
|
|
||||||
}
|
|
||||||
else if (shift == 2)
|
|
||||||
{
|
|
||||||
*out++ = alphabet[(accum & 0x3)<<4];
|
|
||||||
*out++='=';
|
|
||||||
*out++='=';
|
|
||||||
}
|
|
||||||
|
|
||||||
*out++=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void JNL_HTTPGet::connect(const char *url)
|
|
||||||
{
|
|
||||||
deinit();
|
|
||||||
m_http_url=(char*)malloc(strlen(url)+1);
|
|
||||||
strcpy(m_http_url,url);
|
|
||||||
do_parse_url(m_http_url,&m_http_host,&m_http_port,&m_http_request, &m_http_lpinfo);
|
|
||||||
strcpy(m_http_url,url);
|
|
||||||
if (!m_http_host || !m_http_host[0] || !m_http_port)
|
|
||||||
{
|
|
||||||
m_http_state=-1;
|
|
||||||
seterrstr("invalid URL");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sendbufferlen=0;
|
|
||||||
|
|
||||||
if (!m_http_proxyhost || !m_http_proxyhost[0])
|
|
||||||
{
|
|
||||||
sendbufferlen += 4 /* GET */ + strlen(m_http_request) + 9 /* HTTP/1.0 */ + 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sendbufferlen += 4 /* GET */ + strlen(m_http_url) + 9 /* HTTP/1.0 */ + 2;
|
|
||||||
if (m_http_proxylpinfo&&m_http_proxylpinfo[0])
|
|
||||||
{
|
|
||||||
sendbufferlen+=58+strlen(m_http_proxylpinfo)*2; // being safe here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sendbufferlen += 5 /* Host: */ + strlen(m_http_host) + 2;
|
|
||||||
|
|
||||||
if (m_http_lpinfo&&m_http_lpinfo[0])
|
|
||||||
{
|
|
||||||
sendbufferlen+=46+strlen(m_http_lpinfo)*2; // being safe here
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_sendheaders) sendbufferlen+=strlen(m_sendheaders);
|
|
||||||
|
|
||||||
char *str=(char*)malloc(sendbufferlen+1024);
|
|
||||||
if (!str)
|
|
||||||
{
|
|
||||||
seterrstr("error allocating memory");
|
|
||||||
m_http_state=-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_http_proxyhost || !m_http_proxyhost[0])
|
|
||||||
{
|
|
||||||
wsprintfA(str,"GET %s HTTP/1.0\r\n",m_http_request);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wsprintfA(str,"GET %s HTTP/1.0\r\n",m_http_url);
|
|
||||||
}
|
|
||||||
|
|
||||||
wsprintfA(str+strlen(str),"Host: %s\r\n",m_http_host);
|
|
||||||
|
|
||||||
if (m_http_lpinfo&&m_http_lpinfo[0])
|
|
||||||
{
|
|
||||||
strcat(str,"Authorization: Basic ");
|
|
||||||
do_encode_mimestr(m_http_lpinfo,str+strlen(str));
|
|
||||||
strcat(str,"\r\n");
|
|
||||||
}
|
|
||||||
if (m_http_proxylpinfo&&m_http_proxylpinfo[0])
|
|
||||||
{
|
|
||||||
strcat(str,"Proxy-Authorization: Basic ");
|
|
||||||
do_encode_mimestr(m_http_proxylpinfo,str+strlen(str));
|
|
||||||
strcat(str,"\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_sendheaders) strcat(str,m_sendheaders);
|
|
||||||
strcat(str,"\r\n");
|
|
||||||
|
|
||||||
int a=m_recvbufsize;
|
|
||||||
if (a < 4096) a=4096;
|
|
||||||
m_con=new JNL_Connection(m_dns,strlen(str)+4,a);
|
|
||||||
if (m_con)
|
|
||||||
{
|
|
||||||
if (!m_http_proxyhost || !m_http_proxyhost[0])
|
|
||||||
{
|
|
||||||
m_con->connect(m_http_host,m_http_port);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_con->connect(m_http_proxyhost,m_http_proxyport);
|
|
||||||
}
|
|
||||||
m_con->send_string(str);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_http_state=-1;
|
|
||||||
seterrstr("could not create connection object");
|
|
||||||
}
|
|
||||||
free(str);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int my_strnicmp(const char *b1, const char *b2, int l)
|
|
||||||
{
|
|
||||||
while (l-- && *b1 && *b2)
|
|
||||||
{
|
|
||||||
char bb1=*b1++;
|
|
||||||
char bb2=*b2++;
|
|
||||||
if (bb1>='a' && bb1 <= 'z') bb1+='A'-'a';
|
|
||||||
if (bb2>='a' && bb2 <= 'z') bb2+='A'-'a';
|
|
||||||
if (bb1 != bb2) return bb1-bb2;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *_strstr(char *i, const char *s)
|
|
||||||
{
|
|
||||||
if (strlen(i)>=strlen(s)) while (i[strlen(s)-1])
|
|
||||||
{
|
|
||||||
int l=strlen(s)+1;
|
|
||||||
char *ii=i;
|
|
||||||
const char *is=s;
|
|
||||||
while (--l>0)
|
|
||||||
{
|
|
||||||
if (*ii != *is) break;
|
|
||||||
ii++;
|
|
||||||
is++;
|
|
||||||
}
|
|
||||||
if (l==0) return i;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define strstr _strstr
|
|
||||||
|
|
||||||
void JNL_HTTPGet::do_parse_url(char *url, char **host, int *port, char **req, char **lp)
|
|
||||||
{
|
|
||||||
char *p,*np;
|
|
||||||
free(*host); *host=0;
|
|
||||||
free(*req); *req=0;
|
|
||||||
free(*lp); *lp=0;
|
|
||||||
|
|
||||||
if (strstr(url,"://")) np=p=strstr(url,"://")+3;
|
|
||||||
else np=p=url;
|
|
||||||
while (*np != '/' && *np) np++;
|
|
||||||
if (*np)
|
|
||||||
{
|
|
||||||
*req=(char*)malloc(strlen(np)+1);
|
|
||||||
if (*req) strcpy(*req,np);
|
|
||||||
*np++=0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*req=(char*)malloc(2);
|
|
||||||
if (*req) strcpy(*req,"/");
|
|
||||||
}
|
|
||||||
|
|
||||||
np=p;
|
|
||||||
while (*np != '@' && *np) np++;
|
|
||||||
if (*np)
|
|
||||||
{
|
|
||||||
*np++=0;
|
|
||||||
*lp=(char*)malloc(strlen(p)+1);
|
|
||||||
if (*lp) strcpy(*lp,p);
|
|
||||||
p=np;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*lp=(char*)malloc(1);
|
|
||||||
if (*lp) strcpy(*lp,"");
|
|
||||||
}
|
|
||||||
np=p;
|
|
||||||
while (*np != ':' && *np) np++;
|
|
||||||
if (*np)
|
|
||||||
{
|
|
||||||
*np++=0;
|
|
||||||
*port=my_atoi(np);
|
|
||||||
} else *port=80;
|
|
||||||
*host=(char*)malloc(strlen(p)+1);
|
|
||||||
if (*host) strcpy(*host,p);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const char *JNL_HTTPGet::getallheaders()
|
|
||||||
{ // double null terminated, null delimited list
|
|
||||||
if (m_recvheaders) return m_recvheaders;
|
|
||||||
else return "\0\0";
|
|
||||||
}
|
|
||||||
|
|
||||||
char *JNL_HTTPGet::getheader(const char *headername)
|
|
||||||
{
|
|
||||||
char *ret=NULL;
|
|
||||||
if (strlen(headername)<1||!m_recvheaders) return NULL;
|
|
||||||
char *p=m_recvheaders;
|
|
||||||
while (*p)
|
|
||||||
{
|
|
||||||
if (!my_strnicmp(headername,p,strlen(headername)))
|
|
||||||
{
|
|
||||||
ret=p+strlen(headername);
|
|
||||||
while (*ret == ' ') ret++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
p+=strlen(p)+1;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JNL_HTTPGet::run()
|
|
||||||
{
|
|
||||||
int cnt=0;
|
|
||||||
if (m_http_state==-1||!m_con) return -1; // error
|
|
||||||
|
|
||||||
|
|
||||||
run_again:
|
|
||||||
static char main_buf[4096];
|
|
||||||
char *buf = main_buf;
|
|
||||||
m_con->run();
|
|
||||||
|
|
||||||
if (m_con->get_state()==JNL_Connection::STATE_ERROR)
|
|
||||||
{
|
|
||||||
seterrstr(m_con->get_errstr());
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (m_con->get_state()==JNL_Connection::STATE_CLOSED) return 1;
|
|
||||||
|
|
||||||
if (m_http_state==0) // connected, waiting for reply
|
|
||||||
{
|
|
||||||
if (m_con->recv_lines_available()>0)
|
|
||||||
{
|
|
||||||
m_con->recv_line(buf,4095);
|
|
||||||
buf[4095]=0;
|
|
||||||
m_reply=(char*)malloc(strlen(buf)+1);
|
|
||||||
strcpy(m_reply,buf);
|
|
||||||
|
|
||||||
if (strstr(buf,"200")) m_http_state=2; // proceed to read headers normally
|
|
||||||
else if (strstr(buf,"301") || strstr(buf,"302"))
|
|
||||||
{
|
|
||||||
m_http_state=1; // redirect city
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
seterrstr(buf);
|
|
||||||
m_http_state=-1;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
cnt=0;
|
|
||||||
}
|
|
||||||
else if (!cnt++) goto run_again;
|
|
||||||
}
|
|
||||||
if (m_http_state == 1) // redirect
|
|
||||||
{
|
|
||||||
while (m_con->recv_lines_available() > 0)
|
|
||||||
{
|
|
||||||
m_con->recv_line(buf,4096);
|
|
||||||
if (!buf[0])
|
|
||||||
{
|
|
||||||
m_http_state=-1;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!my_strnicmp(buf,"Location:",9))
|
|
||||||
{
|
|
||||||
char *p=buf+9; while (*p== ' ') p++;
|
|
||||||
if (*p)
|
|
||||||
{
|
|
||||||
connect(p);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m_http_state==2)
|
|
||||||
{
|
|
||||||
if (!cnt++ && m_con->recv_lines_available() < 1) goto run_again;
|
|
||||||
while (m_con->recv_lines_available() > 0)
|
|
||||||
{
|
|
||||||
m_con->recv_line(buf,4096);
|
|
||||||
if (!buf[0]) { m_http_state=3; break; }
|
|
||||||
if (!m_recvheaders)
|
|
||||||
{
|
|
||||||
m_recvheaders_size=strlen(buf)+1;
|
|
||||||
m_recvheaders=(char*)malloc(m_recvheaders_size+1);
|
|
||||||
if (m_recvheaders)
|
|
||||||
{
|
|
||||||
strcpy(m_recvheaders,buf);
|
|
||||||
m_recvheaders[m_recvheaders_size]=0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int oldsize=m_recvheaders_size;
|
|
||||||
m_recvheaders_size+=strlen(buf)+1;
|
|
||||||
char *n=(char*)malloc(m_recvheaders_size+1);
|
|
||||||
if (n)
|
|
||||||
{
|
|
||||||
memcpy(n,m_recvheaders,oldsize);
|
|
||||||
strcpy(n+oldsize,buf);
|
|
||||||
n[m_recvheaders_size]=0;
|
|
||||||
free(m_recvheaders);
|
|
||||||
m_recvheaders=n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m_http_state==3)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JNL_HTTPGet::get_status() // returns 0 if connecting, 1 if reading headers,
|
|
||||||
// 2 if reading content, -1 if error.
|
|
||||||
{
|
|
||||||
if (m_http_state < 0) return -1;
|
|
||||||
if (m_http_state < 2) return 0;
|
|
||||||
if (m_http_state == 2) return 1;
|
|
||||||
if (m_http_state == 3) return 2;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JNL_HTTPGet::getreplycode()// returns 0 if none yet, otherwise returns http reply code.
|
|
||||||
{
|
|
||||||
if (!m_reply) return 0;
|
|
||||||
char *p=m_reply;
|
|
||||||
while (*p && *p != ' ') p++; // skip over HTTP/x.x
|
|
||||||
if (!*p) return 0;
|
|
||||||
return my_atoi(++p);
|
|
||||||
}
|
|
||||||
|
|
||||||
int JNL_HTTPGet::bytes_available()
|
|
||||||
{
|
|
||||||
if (m_con && m_http_state==3) return m_con->recv_bytes_available();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int JNL_HTTPGet::get_bytes(char *buf, int len)
|
|
||||||
{
|
|
||||||
if (m_con && m_http_state==3) return m_con->recv_bytes(buf,len);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int JNL_HTTPGet::peek_bytes(char *buf, int len)
|
|
||||||
{
|
|
||||||
if (m_con && m_http_state==3) return m_con->peek_bytes(buf,len);
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,116 +0,0 @@
|
||||||
/*
|
|
||||||
** JNetLib
|
|
||||||
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
|
||||||
** Author: Justin Frankel
|
|
||||||
** File: httpget.h - JNL interface for doing HTTP GETs.
|
|
||||||
** License: zlib
|
|
||||||
**
|
|
||||||
** Usage:
|
|
||||||
** 1. Create a JNL_HTTPGet object, optionally specifying a JNL_AsyncDNS
|
|
||||||
** object to use (or NULL for none, or JNL_CONNECTION_AUTODNS for auto),
|
|
||||||
** and the receive buffer size, and a string specifying proxy (or NULL
|
|
||||||
** for none). See note on proxy string below.
|
|
||||||
** 2. call addheader() to add whatever headers you want. It is recommended to
|
|
||||||
** add at least the following two:
|
|
||||||
** addheader("User-Agent:MyApp (Mozilla)");
|
|
||||||
*/// addheader("Accept:*/*");
|
|
||||||
/* ( the comment weirdness is there so I Can do the star-slash :)
|
|
||||||
** 3. Call connect() with the URL you wish to GET (see URL string note below)
|
|
||||||
** 4. Call run() once in a while, checking to see if it returns -1
|
|
||||||
** (if it does return -1, call geterrorstr() to see what the error is).
|
|
||||||
** (if it returns 1, no big deal, the connection has closed).
|
|
||||||
** 5. While you're at it, you can call bytes_available() to see if any data
|
|
||||||
** from the http stream is available, or getheader() to see if any headers
|
|
||||||
** are available, or getreply() to see the HTTP reply, or getallheaders()
|
|
||||||
** to get a double null terminated, null delimited list of headers returned.
|
|
||||||
** 6. If you want to read from the stream, call get_bytes (which returns how much
|
|
||||||
** was actually read).
|
|
||||||
** 7. content_length() is a helper function that uses getheader() to check the
|
|
||||||
** content-length header.
|
|
||||||
** 8. Delete ye' ol' object when done.
|
|
||||||
**
|
|
||||||
** Proxy String:
|
|
||||||
** should be in the format of host:port, or user@host:port, or
|
|
||||||
** user:password@host:port. if port is not specified, 80 is assumed.
|
|
||||||
** URL String:
|
|
||||||
** should be in the format of http://user:pass@host:port/requestwhatever
|
|
||||||
** note that user, pass, port, and /requestwhatever are all optional :)
|
|
||||||
** note that also, http:// is really not important. if you do poo://
|
|
||||||
** or even leave out the http:// altogether, it will still work.
|
|
||||||
**
|
|
||||||
** Reviewed for Unicode Support by Jim Park -- 08/17/2007
|
|
||||||
** Note: The functions that work on char's should be explicitely set to use the
|
|
||||||
** ANSI versions. Some of the functions like wprintf() are #defined to be
|
|
||||||
** the wide-char versions when _UNICODE is defined. So these must be explictly
|
|
||||||
** set to use the ANSI versions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _HTTPGET_H_
|
|
||||||
#define _HTTPGET_H_
|
|
||||||
|
|
||||||
#include "connection.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
class JNL_HTTPGet
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JNL_HTTPGet(JNL_AsyncDNS *dns=JNL_CONNECTION_AUTODNS, int recvbufsize=16384, char *proxy=NULL);
|
|
||||||
~JNL_HTTPGet();
|
|
||||||
|
|
||||||
void addheader(const char *header);
|
|
||||||
|
|
||||||
void connect(const char *url);
|
|
||||||
|
|
||||||
int run(); // returns: 0 if all is OK. -1 if error (call geterrorstr()). 1 if connection closed.
|
|
||||||
|
|
||||||
int get_status(); // returns 0 if connecting, 1 if reading headers,
|
|
||||||
// 2 if reading content, -1 if error.
|
|
||||||
|
|
||||||
const char *getallheaders(); // double null terminated, null delimited list
|
|
||||||
char *getheader(const char *headername);
|
|
||||||
char *getreply() { return m_reply; }
|
|
||||||
int getreplycode(); // returns 0 if none yet, otherwise returns http reply code.
|
|
||||||
|
|
||||||
char *geterrorstr() { return m_errstr;}
|
|
||||||
|
|
||||||
int bytes_available();
|
|
||||||
int get_bytes(char *buf, int len);
|
|
||||||
int peek_bytes(char *buf, int len);
|
|
||||||
|
|
||||||
int content_length() { char *p=getheader("content-length:"); if (p) return my_atoi(p); return 0; }
|
|
||||||
|
|
||||||
JNL_Connection *get_con() { return m_con; }
|
|
||||||
|
|
||||||
public:
|
|
||||||
void reinit();
|
|
||||||
void deinit();
|
|
||||||
void seterrstr(const char *str) { if (m_errstr) free(m_errstr); m_errstr=(char*)malloc(strlen(str)+1); strcpy(m_errstr,str); }
|
|
||||||
|
|
||||||
void do_parse_url(char *url, char **host, int *port, char **req, char **lp);
|
|
||||||
void do_encode_mimestr(char *in, char *out);
|
|
||||||
|
|
||||||
JNL_AsyncDNS *m_dns;
|
|
||||||
JNL_Connection *m_con;
|
|
||||||
int m_recvbufsize;
|
|
||||||
|
|
||||||
int m_http_state;
|
|
||||||
|
|
||||||
int m_http_port;
|
|
||||||
char *m_http_url;
|
|
||||||
char *m_http_host;
|
|
||||||
char *m_http_lpinfo;
|
|
||||||
char *m_http_request;
|
|
||||||
|
|
||||||
char *m_http_proxylpinfo;
|
|
||||||
char *m_http_proxyhost;
|
|
||||||
int m_http_proxyport;
|
|
||||||
|
|
||||||
char *m_sendheaders;
|
|
||||||
char *m_recvheaders;
|
|
||||||
int m_recvheaders_size;
|
|
||||||
char *m_reply;
|
|
||||||
|
|
||||||
char *m_errstr;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // _HTTPGET_H_
|
|
|
@ -1,94 +0,0 @@
|
||||||
/*
|
|
||||||
** JNetLib
|
|
||||||
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
|
||||||
** Author: Justin Frankel
|
|
||||||
** File: netinc.h - network includes and portability defines (used internally)
|
|
||||||
** License: zlib
|
|
||||||
**
|
|
||||||
** Reviewed for Unicode Support by Jim Park -- 08/17/2007
|
|
||||||
** Note: The functions that work on char's should be explicitely set to use the
|
|
||||||
** ANSI versions. Some of the functions like lstrcpy() are #defined to be
|
|
||||||
** the wide-char versions when _UNICODE is defined. So these must be explictly
|
|
||||||
** set to use the ANSI versions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _NETINC_H_
|
|
||||||
#define _NETINC_H_
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <time.h>
|
|
||||||
#define strcasecmp(x,y) stricmp(x,y)
|
|
||||||
#define ERRNO (WSAGetLastError())
|
|
||||||
#define PORTABLE_SOCKET SOCKET
|
|
||||||
#define SET_SOCK_BLOCK(s,block) { unsigned long __i=block?0:1; ioctlsocket(s,FIONBIO,&__i); }
|
|
||||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
|
||||||
#define EINPROGRESS WSAEWOULDBLOCK
|
|
||||||
typedef int socklen_t;
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#ifndef THREAD_SAFE
|
|
||||||
#define THREAD_SAFE
|
|
||||||
#endif
|
|
||||||
#ifndef _REENTRANT
|
|
||||||
#define _REENTRANT
|
|
||||||
#endif
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define ERRNO errno
|
|
||||||
#define PORTABLE_SOCKET int
|
|
||||||
#define closesocket(s) close(s)
|
|
||||||
#define SET_SOCK_BLOCK(s,block) { int __flags; if ((__flags = fcntl(s, F_GETFL, 0)) != -1) { if (!block) __flags |= O_NONBLOCK; else __flags &= ~O_NONBLOCK; fcntl(s, F_SETFL, __flags); } }
|
|
||||||
|
|
||||||
#define stricmp(x,y) strcasecmp(x,y)
|
|
||||||
#define strnicmp(x,y,z) strncasecmp(x,y,z)
|
|
||||||
#define wsprintf sprintf
|
|
||||||
|
|
||||||
#endif // !_WIN32
|
|
||||||
|
|
||||||
#ifndef INADDR_NONE
|
|
||||||
#define INADDR_NONE 0xffffffff
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef INADDR_ANY
|
|
||||||
#define INADDR_ANY 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SHUT_RDWR
|
|
||||||
#define SHUT_RDWR 2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef INVALID_SOCKET
|
|
||||||
#define INVALID_SOCKET -1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern void mini_memset(void *,char,int);
|
|
||||||
extern void mini_memcpy(void *,void*,int);
|
|
||||||
#define memset mini_memset
|
|
||||||
#define memcpy mini_memcpy
|
|
||||||
#define strcpy lstrcpyA
|
|
||||||
#define strncpy lstrcpynA
|
|
||||||
#define strcat lstrcatA
|
|
||||||
#define strlen lstrlenA
|
|
||||||
#define malloc(x) GlobalAlloc(GPTR,(x))
|
|
||||||
#define free(x) { if (x) GlobalFree(x); }
|
|
||||||
|
|
||||||
#endif //_NETINC_H_
|
|
|
@ -1,70 +0,0 @@
|
||||||
/*
|
|
||||||
** JNetLib
|
|
||||||
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
|
||||||
** Author: Justin Frankel
|
|
||||||
** File: util.cpp - JNL implementation of basic network utilities
|
|
||||||
** License: zlib
|
|
||||||
**
|
|
||||||
** Reviewed for Unicode Support by Jim Park -- 08/17/2007
|
|
||||||
** Note: The functions that work on char's should be explicitely set to use the
|
|
||||||
** ANSI versions. Some of the functions like wprintf() are #defined to be
|
|
||||||
** the wide-char versions when _UNICODE is defined. So these must be explictly
|
|
||||||
** set to use the ANSI versions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "netinc.h"
|
|
||||||
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
int JNL::open_socketlib()
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
WSADATA wsaData;
|
|
||||||
if (WSAStartup(MAKEWORD(1, 1), &wsaData)) return 1;
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
void JNL::close_socketlib()
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
WSACleanup();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
unsigned long JNL::ipstr_to_addr(const char *cp)
|
|
||||||
{
|
|
||||||
return ::inet_addr(cp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JNL::addr_to_ipstr(unsigned long addr, char *host, int maxhostlen)
|
|
||||||
{
|
|
||||||
struct in_addr a; a.s_addr=addr;
|
|
||||||
char *p=::inet_ntoa(a); strncpy(host,p?p:"",maxhostlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
int my_atoi(char *s)
|
|
||||||
{
|
|
||||||
int sign=0;
|
|
||||||
int v=0;
|
|
||||||
if (*s == '-') { s++; sign++; }
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
int c=*s++ - '0';
|
|
||||||
if (c < 0 || c > 9) break;
|
|
||||||
v*=10;
|
|
||||||
v+=c;
|
|
||||||
}
|
|
||||||
if (sign) return -(int) v;
|
|
||||||
return (int)v;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mini_memset(void *o,char i,int l)
|
|
||||||
{
|
|
||||||
char *oo=(char*)o;
|
|
||||||
while (l-- > 0) *oo++=i;
|
|
||||||
}
|
|
||||||
void mini_memcpy(void *o,void*i,int l)
|
|
||||||
{
|
|
||||||
char *oo=(char*)o;
|
|
||||||
char *ii=(char*)i;
|
|
||||||
while (l-- > 0) *oo++=*ii++;
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
/*
|
|
||||||
** JNetLib
|
|
||||||
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
|
||||||
** Author: Justin Frankel
|
|
||||||
** File: util.h - JNL interface for basic network utilities
|
|
||||||
** License: zlib
|
|
||||||
**
|
|
||||||
** routines you may be interested in:
|
|
||||||
** JNL::open_socketlib();
|
|
||||||
** opens the socket library. Call this once before using any network
|
|
||||||
** code. If you create a new thread, call this again. Only really an
|
|
||||||
** issue for Win32 support, but use it anyway for portability/
|
|
||||||
**
|
|
||||||
** JNL::close_Socketlib();
|
|
||||||
** closes the socketlib. Call this when you're done with the network,
|
|
||||||
** after all your JNetLib objects have been destroyed.
|
|
||||||
**
|
|
||||||
** unsigned long JNL::ipstr_to_addr(const char *cp);
|
|
||||||
** gives you the integer representation of a ip address in dotted
|
|
||||||
** decimal form.
|
|
||||||
**
|
|
||||||
** JNL::addr_to_ipstr(unsigned long addr, char *host, int maxhostlen);
|
|
||||||
** gives you the dotted decimal notation of an integer ip address.
|
|
||||||
**
|
|
||||||
** Reviewed for Unicode Support by Jim Park -- 08/17/2007
|
|
||||||
** Note: The functions that work on char's should be explicitely set to use the
|
|
||||||
** ANSI versions. Some of the functions like wprintf() are #defined to be
|
|
||||||
** the wide-char versions when _UNICODE is defined. So these must be explictly
|
|
||||||
** set to use the ANSI versions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _UTIL_H_
|
|
||||||
#define _UTIL_H_
|
|
||||||
|
|
||||||
class JNL
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static int open_socketlib();
|
|
||||||
static void close_socketlib();
|
|
||||||
static unsigned long ipstr_to_addr(const char *cp);
|
|
||||||
static void addr_to_ipstr(unsigned long addr, char *host, int maxhostlen);
|
|
||||||
};
|
|
||||||
|
|
||||||
int my_atoi(char *p);
|
|
||||||
|
|
||||||
#endif //_UTIL_H_
|
|
|
@ -91,7 +91,6 @@ int WINAPI _tWinMain(HINSTANCE hInst,HINSTANCE hOldInst,LPTSTR CmdLineParams,int
|
||||||
if (g_sdata.sigint_event) CloseHandle(g_sdata.sigint_event);
|
if (g_sdata.sigint_event) CloseHandle(g_sdata.sigint_event);
|
||||||
if (g_sdata.sigint_event_legacy) CloseHandle(g_sdata.sigint_event_legacy);
|
if (g_sdata.sigint_event_legacy) CloseHandle(g_sdata.sigint_event_legacy);
|
||||||
FreeLibrary(hRichEditDLL);
|
FreeLibrary(hRichEditDLL);
|
||||||
FinalizeUpdate();
|
|
||||||
return (int) msg.wParam;
|
return (int) msg.wParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -526,17 +525,15 @@ INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam
|
||||||
}
|
}
|
||||||
case IDM_NSISHOME:
|
case IDM_NSISHOME:
|
||||||
{
|
{
|
||||||
ShellExecuteA(g_sdata.hwnd,"open",NSIS_URL,NULL,NULL,SW_SHOWNORMAL);
|
return OpenUrlInDefaultBrowser(g_sdata.hwnd, NSIS_URL);
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
case IDM_FORUM:
|
case IDM_FORUM:
|
||||||
{
|
{
|
||||||
ShellExecuteA(g_sdata.hwnd,"open",NSIS_FOR,NULL,NULL,SW_SHOWNORMAL);
|
return OpenUrlInDefaultBrowser(g_sdata.hwnd, NSIS_FORUM_URL);
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
case IDM_NSISUPDATE:
|
case IDM_NSISUPDATE:
|
||||||
{
|
{
|
||||||
Update();
|
CheckForUpdate();
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
case IDM_SELECTALL:
|
case IDM_SELECTALL:
|
||||||
|
|
|
@ -34,8 +34,8 @@
|
||||||
|
|
||||||
// Defines
|
// Defines
|
||||||
#define NSIS_URL "http://nsis.sourceforge.net/"
|
#define NSIS_URL "http://nsis.sourceforge.net/"
|
||||||
#define NSIS_FOR "http://forums.winamp.com/forumdisplay.php?forumid=65"
|
#define NSIS_FORUM_URL "http://forums.winamp.com/forumdisplay.php?forumid=65"
|
||||||
#define NSIS_UPDATE "http://nsis.sourceforge.net/update.php?version="
|
#define NSIS_UC_URL "http://nsis.sourceforge.net/update.php?version="
|
||||||
#define NSIS_DL_URL "http://nsis.sourceforge.net/download/"
|
#define NSIS_DL_URL "http://nsis.sourceforge.net/download/"
|
||||||
#define USAGE _T("Usage:\r\n\r\n - File | Load Script...\r\n - Drag the .nsi file into this window\r\n - Right click the .nsi file and choose \"Compile NSIS Script\"")
|
#define USAGE _T("Usage:\r\n\r\n - File | Load Script...\r\n - Drag the .nsi file into this window\r\n - Right click the .nsi file and choose \"Compile NSIS Script\"")
|
||||||
#define COPYRIGHT _T("Copyright (C) 2002 Robert Rainwater")
|
#define COPYRIGHT _T("Copyright (C) 2002 Robert Rainwater")
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
#define DOCPATH "http://nsis.sourceforge.net/Docs/"
|
#define DOCPATH "http://nsis.sourceforge.net/Docs/"
|
||||||
#define LOCALDOCS _T("\\NSIS.chm")
|
#define LOCALDOCS _T("\\NSIS.chm")
|
||||||
#define ERRBOXTITLE 0 //_T("Error")
|
#define ERRBOXTITLE 0 //_T("Error")
|
||||||
#define NSISERROR _T("Unable to intialize MakeNSIS. Please verify that makensis.exe is in the same directory as makensisw.exe.")
|
#define NSISERROR _T("Unable to intialize MakeNSIS. Please verify that makensis.exe is in the same directory as makensisw.exe.")
|
||||||
#define DLGERROR _T("Unable to intialize MakeNSISW.")
|
#define DLGERROR _T("Unable to intialize MakeNSISW.")
|
||||||
#define SYMBOLSERROR _T("Symbol cannot contain whitespace characters")
|
#define SYMBOLSERROR _T("Symbol cannot contain whitespace characters")
|
||||||
#define MULTIDROPERROR _T("Dropping more than one script at a time is not supported")
|
#define MULTIDROPERROR _T("Dropping more than one script at a time is not supported")
|
||||||
|
@ -157,7 +157,7 @@ int compressor_strings[] = {IDS_SCRIPT,
|
||||||
|
|
||||||
extern const TCHAR* NSISW_VERSION;
|
extern const TCHAR* NSISW_VERSION;
|
||||||
|
|
||||||
DWORD WINAPI MakeNSISProc(LPVOID TreadParam);
|
DWORD WINAPI MakeNSISProc(LPVOID TreadParam);
|
||||||
INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||||
BOOL CALLBACK DialogResize(HWND hWnd, LPARAM /* unused*/);
|
BOOL CALLBACK DialogResize(HWND hWnd, LPARAM /* unused*/);
|
||||||
INT_PTR CALLBACK AboutProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
|
INT_PTR CALLBACK AboutProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
|
@ -117,7 +117,7 @@ BEGIN
|
||||||
MENUITEM "", -1, MFT_SEPARATOR
|
MENUITEM "", -1, MFT_SEPARATOR
|
||||||
MENUITEM "NSIS &Homepage", IDM_NSISHOME
|
MENUITEM "NSIS &Homepage", IDM_NSISHOME
|
||||||
MENUITEM "NSIS &Forum", IDM_FORUM
|
MENUITEM "NSIS &Forum", IDM_FORUM
|
||||||
MENUITEM "NSIS &Update", IDM_NSISUPDATE
|
MENUITEM "Check for &Updates", IDM_NSISUPDATE
|
||||||
MENUITEM "", -1, MFT_SEPARATOR
|
MENUITEM "", -1, MFT_SEPARATOR
|
||||||
MENUITEM "&About MakeNSISW", IDM_ABOUT
|
MENUITEM "&About MakeNSISW", IDM_ABOUT
|
||||||
END
|
END
|
||||||
|
|
|
@ -2,136 +2,146 @@
|
||||||
|
|
||||||
#include "makensisw.h"
|
#include "makensisw.h"
|
||||||
#include "update.h"
|
#include "update.h"
|
||||||
|
#include "utils.h" // OpenUrlInDefaultBrowser
|
||||||
|
|
||||||
#include "jnetlib/httpget.h"
|
#define mbtitle "NSIS Update"
|
||||||
|
|
||||||
static BOOL update_initialized = FALSE;
|
static LPSTR InetGetErrorStringAllocA(DWORD ec)
|
||||||
|
{
|
||||||
static JNL_AsyncDNS *g_dns = NULL;
|
LPSTR buf;
|
||||||
|
DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||||
void InitializeUpdate() {
|
if (FormatMessageA(flags|FORMAT_MESSAGE_FROM_SYSTEM, 0, ec, 0, (LPSTR) &buf, 0, 0))
|
||||||
if (update_initialized)
|
return buf;
|
||||||
return;
|
HMODULE hMod = GetModuleHandle(TEXT("WinInet"));
|
||||||
|
if (hMod && FormatMessageA(flags|FORMAT_MESSAGE_FROM_HMODULE, hMod, ec, 0, (LPSTR) &buf, 0, 0))
|
||||||
update_initialized = TRUE;
|
return buf;
|
||||||
JNL::open_socketlib();
|
#if 0 // We are not using WinHttp* functions
|
||||||
g_dns = new JNL_AsyncDNS();
|
hMod = GetModuleHandle(TEXT("WinHTTP"));
|
||||||
|
if (hMod && FormatMessageA(flags|FORMAT_MESSAGE_FROM_HMODULE, hMod, ec, 0, (LPSTR) &buf, 0, 0))
|
||||||
|
return buf;
|
||||||
|
#endif
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FinalizeUpdate() {
|
static void InetWorkOnline(HINTERNET hInet)
|
||||||
if (!update_initialized)
|
{
|
||||||
return;
|
//msdn.microsoft.com/library/default.asp?url=/workshop/components/offline/offline.asp#Supporting Offline Browsing in Applications and Components
|
||||||
|
DWORD cbio = sizeof(DWORD), op32;
|
||||||
delete g_dns;
|
if (InternetQueryOption(hInet, INTERNET_OPTION_CONNECTED_STATE, &op32, &cbio))
|
||||||
JNL::close_socketlib();
|
|
||||||
}
|
|
||||||
|
|
||||||
int getProxyInfo(char *out) {
|
|
||||||
DWORD v=0;
|
|
||||||
HKEY hKey;
|
|
||||||
if (RegOpenKeyExA(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",0,KEY_READ,&hKey) == ERROR_SUCCESS) {
|
|
||||||
DWORD l = 4;
|
|
||||||
DWORD t;
|
|
||||||
if (RegQueryValueExA(hKey,"ProxyEnable",NULL,&t,(unsigned char *)&v,&l) == ERROR_SUCCESS && t == REG_DWORD) {
|
|
||||||
l=8192;
|
|
||||||
if (RegQueryValueExA(hKey,"ProxyServer",NULL,&t,(unsigned char *)out,&l ) != ERROR_SUCCESS || t != REG_SZ) {
|
|
||||||
v=0;
|
|
||||||
*out=0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else v=0;
|
|
||||||
out[8192-1]=0;
|
|
||||||
RegCloseKey(hKey);
|
|
||||||
}
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD CALLBACK UpdateThread(LPVOID v) {
|
|
||||||
#define RSZ 30
|
|
||||||
int len;
|
|
||||||
char response[RSZ], *r;
|
|
||||||
char url[300];
|
|
||||||
BOOL error = FALSE;
|
|
||||||
static char pbuf[8192];
|
|
||||||
char *p=NULL;
|
|
||||||
*response = 0;
|
|
||||||
|
|
||||||
if (getProxyInfo(pbuf))
|
|
||||||
{
|
{
|
||||||
p=strstr(pbuf,"http=");
|
if (INTERNET_STATE_DISCONNECTED_BY_USER & op32)
|
||||||
if (!p) p=pbuf;
|
{
|
||||||
else {
|
INTERNET_CONNECTED_INFO ci = { INTERNET_STATE_CONNECTED, 0 };
|
||||||
p+=5;
|
InternetSetOption(hInet, INTERNET_OPTION_CONNECTED_STATE, &ci, sizeof(ci));
|
||||||
}
|
}
|
||||||
char *tp=strstr(p,";");
|
|
||||||
if (tp) *tp=0;
|
|
||||||
char *p2=strstr(p,"=");
|
|
||||||
if (p2) p=0; // we found the wrong proxy
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
InitializeUpdate();
|
static DWORD InetSynchronousReadFile(HINTERNET hConn, void*Buffer, DWORD cbBuffer, DWORD*pcbReceived)
|
||||||
|
{
|
||||||
|
*pcbReceived = 0;
|
||||||
|
for (DWORD cbio;;)
|
||||||
|
{
|
||||||
|
if (!cbBuffer)
|
||||||
|
break;
|
||||||
|
if (!InternetReadFile(hConn, Buffer, cbBuffer, &cbio))
|
||||||
|
return GetLastError();
|
||||||
|
if (!cbio)
|
||||||
|
break; // EOF, we are done.
|
||||||
|
Buffer = ((char*)Buffer) + cbio, cbBuffer -= cbio;
|
||||||
|
(*pcbReceived) += cbio;
|
||||||
|
}
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
JNL_HTTPGet *get = new JNL_HTTPGet(g_dns,8192,(p&&p[0])?p:NULL);
|
static DWORD CALLBACK UpdateCheckWebrequestThread(LPVOID ThreadParam)
|
||||||
lstrcpyA(url,NSIS_UPDATE);
|
{
|
||||||
lstrcatA(url,g_sdata.brandingv);
|
char buf[300];
|
||||||
|
wsprintfA(buf, "%s%s", NSIS_UC_URL, g_sdata.brandingv);
|
||||||
|
|
||||||
lstrcpyA(response,"");
|
InternetAttemptConnect(0);
|
||||||
get->addheader("User-Agent: MakeNSISw (jnetlib)");
|
UINT mbicon = MB_ICONINFORMATION;
|
||||||
get->addheader("Accept:*/*");
|
LPCSTR msg = NULL;
|
||||||
get->connect(url);
|
HINTERNET hInet = InternetOpenA("MakeNSISw (WinInet)", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
|
||||||
while (1) {
|
DWORD gle = GetLastError();
|
||||||
int st=get->run();
|
if (hInet)
|
||||||
if (st<0) { error = TRUE; break; }//error
|
{
|
||||||
if (get->get_status()==2) {
|
InetWorkOnline(hInet);
|
||||||
while( (len=get->bytes_available()) ) {
|
|
||||||
char b[RSZ];
|
// Note: InternetOpenUrlW does not handle the http headers in the same way, be careful if you stop forcing the A version
|
||||||
if (len>RSZ) len=RSZ;
|
static const CHAR httpheaders[] = "Accept:*/*\r\n";
|
||||||
if (lstrlenA(response)+len>RSZ) break;
|
DWORD connflags = INTERNET_FLAG_NO_UI|INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS;
|
||||||
len=get->get_bytes(b,len);
|
connflags |= INTERNET_FLAG_NO_CACHE_WRITE|INTERNET_FLAG_NO_COOKIES;
|
||||||
b[len]=0;
|
connflags |= INTERNET_FLAG_PRAGMA_NOCACHE|INTERNET_FLAG_RELOAD;
|
||||||
lstrcatA(response,b);
|
//if ((32|buf[4]) == 's') connflags |= INTERNET_FLAG_SECURE;
|
||||||
|
HINTERNET hConn = InternetOpenUrlA(hInet, buf, httpheaders, -1, connflags, 0);
|
||||||
|
gle = GetLastError();
|
||||||
|
if (hConn)
|
||||||
|
{
|
||||||
|
char response[30];
|
||||||
|
DWORD cbRecv;
|
||||||
|
gle = InetSynchronousReadFile(hConn, response, sizeof(response), &cbRecv);
|
||||||
|
if (!gle)
|
||||||
|
{
|
||||||
|
response[cbRecv] = '\0';
|
||||||
|
switch(response[0])
|
||||||
|
{
|
||||||
|
case '0':
|
||||||
|
msg = "There is no update available for NSIS at this time.";
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
if (cbRecv > 2 && '|' == response[1])
|
||||||
|
{
|
||||||
|
const char *reltypestr = '1' == response[0] ? "it" : "this preview release";
|
||||||
|
wsprintfA(buf, "NSIS %.50s is now available. Would you like to download %s now?", response+2, reltypestr);
|
||||||
|
mbicon = MB_ICONQUESTION, msg = buf;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// fall through
|
||||||
|
default:
|
||||||
|
gle = ERROR_INVALID_DATA;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
InternetCloseHandle(hConn);
|
||||||
}
|
}
|
||||||
if (st==1) break; //closed
|
InternetCloseHandle(hInet);
|
||||||
}
|
}
|
||||||
r = response;
|
|
||||||
while (r&&*r) {
|
HWND hwndOwner = (HWND) ThreadParam;
|
||||||
if (*r=='\n') { *r = 0; break; }
|
// Hopefully we don't end up with a race where our main window has been closed
|
||||||
r++;
|
// and the HWND has been reused just as this thread completes its work
|
||||||
}
|
if (IsWindow(hwndOwner))
|
||||||
if (error) {
|
{
|
||||||
char buf[1000];
|
if (!msg)
|
||||||
wsprintfA(buf, "There was a problem checking for an update. Please try again later.\n\nError: %s",get->geterrorstr());
|
{
|
||||||
MessageBoxA(g_sdata.hwnd,buf,"NSIS Update",MB_OK|MB_ICONINFORMATION);
|
LPSTR dynbuf = InetGetErrorStringAllocA(gle);
|
||||||
}
|
wsprintfA(buf, "There was a problem checking for updates, please try again later.\n\nError: %u %.200s", gle, dynbuf ? dynbuf : "");
|
||||||
else if (*response=='1'&&lstrlenA(response)>2) {
|
mbicon = MB_ICONSTOP, msg = buf;
|
||||||
char buf[200];
|
LocalFree(dynbuf);
|
||||||
wsprintfA(buf, "NSIS %s is now available. Would you like to download it now?",response+2);
|
|
||||||
if (MessageBoxA(g_sdata.hwnd,buf,"NSIS Update",MB_YESNO|MB_ICONINFORMATION)==IDYES) {
|
|
||||||
ShellExecuteA(g_sdata.hwnd,"open",NSIS_DL_URL,NULL,NULL,SW_SHOWNORMAL);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (*response=='2'&&lstrlenA(response)>2) {
|
UINT mbtype = MB_ICONQUESTION == mbicon ? MB_YESNO : MB_OK;
|
||||||
char buf[200];
|
int mbret = MessageBoxA(hwndOwner, msg, mbtitle, mbtype|mbicon);
|
||||||
wsprintfA(buf,"NSIS %s is now available. Would you like to download this preview release now?",response+2);
|
if (mbret == IDYES && mbtype == MB_YESNO)
|
||||||
if (MessageBoxA(g_sdata.hwnd,buf,"NSIS Update",MB_YESNO|MB_ICONINFORMATION)==IDYES) {
|
{
|
||||||
ShellExecuteA(g_sdata.hwnd,"open",NSIS_DL_URL,NULL,NULL,SW_SHOWNORMAL);
|
OpenUrlInDefaultBrowser(hwndOwner, NSIS_DL_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EnableMenuItem(g_sdata.menu, IDM_NSISUPDATE, MF_ENABLED);
|
||||||
}
|
}
|
||||||
else MessageBoxA(g_sdata.hwnd,"There is no update available for NSIS at this time.","NSIS Update",MB_OK|MB_ICONINFORMATION);
|
|
||||||
delete get;
|
|
||||||
EnableMenuItem(g_sdata.menu,IDM_NSISUPDATE,MF_ENABLED);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update() {
|
void CheckForUpdate()
|
||||||
if (strstr(g_sdata.brandingv,"cvs"))
|
{
|
||||||
|
if (strstr(g_sdata.brandingv, "cvs"))
|
||||||
{
|
{
|
||||||
MessageBoxA(g_sdata.hwnd,"Cannot check for new version of nightly builds. To update, download a new nightly build.","NSIS Update",MB_OK|MB_ICONSTOP);
|
MessageBoxA(g_sdata.hwnd, "Cannot check for new version of nightly builds. To update, download a new nightly build.", mbtitle, MB_OK|MB_ICONSTOP);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EnableMenuItem(g_sdata.menu,IDM_NSISUPDATE,MF_GRAYED);
|
EnableMenuItem(g_sdata.menu, IDM_NSISUPDATE, MF_GRAYED);
|
||||||
DWORD tid;
|
DWORD tid;
|
||||||
CloseHandle(CreateThread(NULL,0,UpdateThread,NULL,0,&tid));
|
CloseHandle(CreateThread(NULL, 0, UpdateCheckWebrequestThread, (LPVOID) g_sdata.hwnd, 0, &tid));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1 @@
|
||||||
/* Reviewed for Unicode support by Jim Park -- 08/18/2007 */
|
void CheckForUpdate(); /* Check for newer version on server and show a message to the user. */
|
||||||
|
|
||||||
/* Initialize update objects. */
|
|
||||||
void InitializeUpdate();
|
|
||||||
|
|
||||||
/* Check for newer version on server and show a message to the user. */
|
|
||||||
void Update();
|
|
||||||
|
|
||||||
/* Finalize update objects. */
|
|
||||||
void FinalizeUpdate();
|
|
||||||
|
|
|
@ -989,6 +989,11 @@ bool FileExists(const TCHAR *fname)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OpenUrlInDefaultBrowser(HWND hwnd, LPCSTR Url)
|
||||||
|
{
|
||||||
|
return (int)(INT_PTR) ShellExecuteA(hwnd, NULL , Url, NULL, NULL, SW_SHOWNORMAL) > 32;
|
||||||
|
}
|
||||||
|
|
||||||
HMENU FindSubMenu(HMENU hMenu, UINT uId)
|
HMENU FindSubMenu(HMENU hMenu, UINT uId)
|
||||||
{
|
{
|
||||||
MENUITEMINFO mii;
|
MENUITEMINFO mii;
|
||||||
|
|
|
@ -76,6 +76,7 @@ void LoadMRUFile(int position);
|
||||||
void ClearMRUList();
|
void ClearMRUList();
|
||||||
|
|
||||||
bool FileExists(const TCHAR *fname);
|
bool FileExists(const TCHAR *fname);
|
||||||
|
bool OpenUrlInDefaultBrowser(HWND hwnd, LPCSTR Url);
|
||||||
|
|
||||||
HMENU FindSubMenu(HMENU hMenu, UINT uId);
|
HMENU FindSubMenu(HMENU hMenu, UINT uId);
|
||||||
HFONT CreateFont(int Height, int Weight, DWORD PitchAndFamily, LPCTSTR Face);
|
HFONT CreateFont(int Height, int Weight, DWORD PitchAndFamily, LPCTSTR Face);
|
||||||
|
|
|
@ -41,6 +41,10 @@
|
||||||
** Reviewed for Unicode support by Jim Park -- 08/24/2004
|
** Reviewed for Unicode support by Jim Park -- 08/24/2004
|
||||||
** Everything remains ANSI. Made sure all TCHAR style functions were
|
** Everything remains ANSI. Made sure all TCHAR style functions were
|
||||||
** changed to strictly ANSI.
|
** changed to strictly ANSI.
|
||||||
|
**
|
||||||
|
** Notes:
|
||||||
|
** We used to have a fork of JNetLib in MakeNSISw that was slightly different,
|
||||||
|
** you can see it @ http://sf.net/p/nsis/code/6603/tree/NSIS/trunk/Contrib/Makensisw/jnetlib/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _HTTPGET_H_
|
#ifndef _HTTPGET_H_
|
||||||
|
|
|
@ -14,6 +14,8 @@ Released on ? ?th, 201?
|
||||||
|
|
||||||
\b !system and !execute now provide a empty StdIn pipe to work around bugs in some Windows utilities
|
\b !system and !execute now provide a empty StdIn pipe to work around bugs in some Windows utilities
|
||||||
|
|
||||||
|
\b MakeNSISW now uses WinInet when checking for updates
|
||||||
|
|
||||||
\H{v3.0b2} 3.0 Beta 2
|
\H{v3.0b2} 3.0 Beta 2
|
||||||
|
|
||||||
Released on August 4th, 2015
|
Released on August 4th, 2015
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue