1 // Copyright (c) 1996 James Clark
2 // See the file COPYING for copying permission.
3 
4 #include "splib.h"
5 
6 #ifdef SP_WININET
7 
8 #include "WinInetStorage.h"
9 #include "WinInetStorageMessages.h"
10 #include "RewindStorageObject.h"
11 #include "UnivCharsetDesc.h"
12 #include "MessageArg.h"
13 #include "MessageBuilder.h"
14 #include "macros.h"
15 
16 #define STRICT
17 #include <windows.h>
18 #include <wininet.h>
19 
20 #ifdef SP_NAMESPACE
21 namespace SP_NAMESPACE {
22 #endif
23 
24 static UnivCharsetDesc::Range range = { 0, 128, 0 };
25 static CharsetInfo iso646Charset(UnivCharsetDesc(&range, 1));
26 
toAscii(const StringC & buf)27 String<char> toAscii(const StringC &buf)
28 {
29   String<char> s;
30   for (size_t i = 0; i < buf.size(); i++)
31     s += buf[i];
32   s += '\0';
33   return s;
34 }
35 class Win32MessageArg : public MessageArg {
36 public:
Win32MessageArg(DWORD n)37   Win32MessageArg(DWORD n) : n_(n) { }
copy() const38   MessageArg *copy() const { return new Win32MessageArg(*this); }
39   void append(MessageBuilder &) const;
40 private:
41   DWORD n_;
42 };
43 
append(MessageBuilder & builder) const44 void Win32MessageArg::append(MessageBuilder &builder) const
45 {
46   void *msg;
47   if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
48 		      |FORMAT_MESSAGE_ALLOCATE_BUFFER,
49 		      0,
50 		      n_,
51 		      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
52 		      (LPSTR)&msg,
53 		      0,
54 		      0)) {
55     // FIXME interpret common internet messages here
56     builder.appendNumber(n_);
57     return;
58   }
59   String<Char> s;
60   for (char *tem = (char *)msg; *tem; tem++)
61     s += *tem;
62   LocalFree(msg);
63   builder.appendChars(s.data(), s.size());
64 }
65 
66 class WinInetStorageObject : public RewindStorageObject {
67 public:
68   WinInetStorageObject(HINTERNET fd, Boolean mayRewind, const StringC &url);
69   ~WinInetStorageObject();
70   Boolean read(char *buf, size_t bufSize, Messenger &mgr, size_t &nread);
71   Boolean seekToStart(Messenger &);
72 private:
73   WinInetStorageObject(const WinInetStorageObject &); // undefined
74   void operator=(const WinInetStorageObject &); // undefined
75   Boolean eof_;
76   HINTERNET fd_;
77   StringC url_;
78 };
79 
WinInetStorageManager(const char * type)80 WinInetStorageManager::WinInetStorageManager(const char *type)
81 : type_(type), IdStorageManager(&iso646Charset), session_(0)
82 {
83 }
84 
~WinInetStorageManager()85 WinInetStorageManager::~WinInetStorageManager()
86 {
87   if (session_) {
88     InternetCloseHandle(session_);
89     session_ = 0;
90   }
91 }
92 
type() const93 const char *WinInetStorageManager::type() const
94 {
95   return type_;
96 }
97 
initSession()98 Boolean WinInetStorageManager::initSession()
99 {
100   if (!session_) {
101     session_ = InternetOpenA("SP",
102                              INTERNET_OPEN_TYPE_PRECONFIG,
103 			     0,
104 			     0,
105 			     0);
106   }
107   return 1;
108 }
109 
guessIsId(const StringC & id,const CharsetInfo & charset) const110 Boolean WinInetStorageManager::guessIsId(const StringC &id,
111 				     const CharsetInfo &charset) const
112 {
113   if (id.size() < 8)
114     return 0;
115   size_t i = 0;
116   // guess other schemes supported by download protocols
117   for (const char *s = "http://"; *s; s++, i++)
118     if (id[i] != charset.execToDesc(*s)
119 	&& (!islower(*s) || id[i] != charset.execToDesc(toupper(*s))))
120       return 0;
121   return 1;
122 }
123 
makeStorageObject(const StringC & specId,const StringC & baseId,Boolean,Boolean mayRewind,Messenger & mgr,StringC & id)124 StorageObject *WinInetStorageManager::makeStorageObject(const StringC &specId,
125 							const StringC &baseId,
126 							Boolean,
127 							Boolean mayRewind,
128 						        Messenger &mgr,
129 						        StringC &id)
130 {
131   if (!initSession())
132     return 0;
133   id = specId;
134   resolveRelative(baseId, id, 0);
135   String<char> tem(toAscii(id));
136   HINTERNET fd = InternetOpenUrlA(session_, tem.data(), 0, 0, 0, 0);
137   if (!fd) {
138     DWORD err = GetLastError();
139     mgr.message(WinInetStorageMessages::cannotOpen,
140                 StringMessageArg(id),
141 		Win32MessageArg(err));
142     return 0;
143   }
144   // FIXME report an error
145   return new WinInetStorageObject(fd, mayRewind, id);
146 }
147 
resolveRelative(const StringC & baseId,StringC & id,Boolean) const148 Boolean WinInetStorageManager::resolveRelative(const StringC &baseId,
149 					       StringC &id,
150 					       Boolean) const
151 {
152   DWORD bufSize = baseId.size() + id.size() + 1;
153   char *buf = new char[bufSize];
154   String<char> baseIdA (toAscii(baseId));
155   String<char> idA(toAscii(id));
156   if (InternetCombineUrlA(baseIdA.data(),
157 			  idA.data(),
158 			  buf,
159 			  &bufSize,
160 			  0)) {
161     id.resize(0);
162     for (size_t i = 0; i < bufSize; i++)
163       id += buf[i];
164     delete [] buf;
165     return 1;
166   }
167   delete [] buf;
168   return 0;
169 }
170 
transformNeutral(StringC & str,Boolean fold,Messenger &) const171 Boolean WinInetStorageManager::transformNeutral(StringC &str, Boolean fold,
172 						Messenger &) const
173 {
174   if (fold)
175     for (size_t i = 0; i < str.size(); i++) {
176       Char c = str[i];
177       if (c <= (unsigned char)-1)
178 	str[i] = tolower(str[i]);
179     }
180   return 1;
181 }
182 
183 
WinInetStorageObject(HINTERNET fd,Boolean mayRewind,const StringC & url)184 WinInetStorageObject::WinInetStorageObject(HINTERNET fd,
185 					   Boolean mayRewind,
186 					   const StringC &url)
187 : RewindStorageObject(mayRewind, 0), fd_(fd), url_(url), eof_(0)
188 {
189 }
190 
~WinInetStorageObject()191 WinInetStorageObject::~WinInetStorageObject()
192 {
193   if (fd_ != 0) {
194     (void)InternetCloseHandle(fd_);
195     fd_ = 0;
196   }
197 }
198 
read(char * buf,size_t bufSize,Messenger & mgr,size_t & nread)199 Boolean WinInetStorageObject::read(char *buf, size_t bufSize, Messenger &mgr,
200 				   size_t &nread)
201 {
202   if (readSaved(buf, bufSize, nread))
203     return 1;
204   if (fd_ == 0 || eof_)
205     return 0;
206   DWORD n;
207   if (!InternetReadFile(fd_, buf, bufSize, &n)) {
208     DWORD err = GetLastError();
209     mgr.message(WinInetStorageMessages::readFailed,
210                 StringMessageArg(url_),
211 		Win32MessageArg(err));
212     return 0;
213   }
214   if (n) {
215     nread = n;
216     return 1;
217   }
218   eof_ = 1;
219   InternetCloseHandle(fd_);
220   fd_ = 0;
221   return 0;
222 }
223 
seekToStart(Messenger &)224 Boolean WinInetStorageObject::seekToStart(Messenger &)
225 {
226   CANNOT_HAPPEN();
227   return 0;
228 }
229 
230 #ifdef SP_NAMESPACE
231 }
232 #endif
233 
234 #endif /* SP_WININET */
235