1 /*
2 **	@(#) $Id$
3 **
4 **	W3C Web Commander can be found at "http://www.w3.org/WinCom/"
5 **
6 **	Copyright � 1995-1998 World Wide Web Consortium, (Massachusetts
7 **	Institute of Technology, Institut National de Recherche en
8 **	Informatique et en Automatique, Keio University). All Rights
9 **	Reserved. This program is distributed under the W3C's Software
10 **	Intellectual Property License. This program is distributed in the hope
11 **	that it will be useful, but WITHOUT ANY WARRANTY; without even the
12 **	implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13 **	PURPOSE. See W3C License http://www.w3.org/Consortium/Legal/ for more
14 **	details.
15 **
16 **	Request.cpp: implementation of the CRequest class.
17 */
18 
19 #include "stdafx.h"
20 #include "WinCom.h"
21 #include "Request.h"
22 #include "VersionConflict.h"
23 
24 // From libwww
25 #include "WWWLib.h"			      /* Global Library Include file */
26 #include "WWWApp.h"
27 #include "WWWFile.h"
28 
29 #ifdef _DEBUG
30 #undef THIS_FILE
31 static char THIS_FILE[]=__FILE__;
32 #define new DEBUG_NEW
33 #endif
34 
35 #define DEF_LAST_SEGMENT	"index"
36 
37 /////////////////////////////////////////////////////////////////////////////
38 // Libwww filters
39 
40 /*
41 **  Request termination handler
42 */
terminate_handler(HTRequest * request,HTResponse * response,void * param,int status)43 PRIVATE int terminate_handler (HTRequest * request, HTResponse * response,
44 			       void * param, int status)
45 {
46     CRequest * req = (CRequest *) HTRequest_context(request);
47 
48     req->Cleanup();
49 
50     delete req;
51 
52     return HT_OK;
53 }
54 
55 /*
56 **  412 "Precondition failed" handler
57 */
precondition_handler(HTRequest * request,HTResponse * response,void * param,int status)58 PRIVATE int precondition_handler (HTRequest * request, HTResponse * response,
59 			          void * param, int status)
60 {
61     CRequest * req = (CRequest *) HTRequest_context(request);
62     CVersionConflict conflict;
63 
64     req->Cleanup();
65 
66     if (conflict.DoModal() == IDOK) {
67 
68 	if (conflict.m_versionResolution == 0) {
69 	    HTAnchor * source = req->Source();
70 	    HTAnchor * dest = req->Destination();
71 	    CRequest * new_req = new CRequest(req->m_pDoc);
72 	    delete req;
73 
74 	    /* Start a new PUT request without preconditions */
75 	    new_req->PutDocument(source, dest, HT_NO_MATCH);
76 
77 	    /* Stop here */
78 	    return HT_ERROR;
79 
80 	} else if (conflict.m_versionResolution == 1) {
81 	    HTAnchor * address = req->Source();
82 	    CRequest * new_req = new CRequest(req->m_pDoc);
83 	    delete req;
84 
85 	    /* Start a new GET request */
86 	    new_req->GetDocument(address, 2);
87 
88 	    /* Stop here */
89 	    return HT_ERROR;
90 
91 	} else
92 	    return HT_OK;   /* Just finish the request */
93 
94     }
95     return HT_OK;
96 }
97 
98 /*
99 **  Request HEAD checker filter
100 */
check_handler(HTRequest * request,HTResponse * response,void * param,int status)101 PRIVATE int check_handler (HTRequest * request, HTResponse * response,
102 			   void * param, int status)
103 {
104     CRequest * req = (CRequest *) HTRequest_context(request);
105     CVersionConflict conflict;
106 
107     req->Cleanup();
108 
109     /*
110     ** If head request showed that the document doesn't exist
111     ** then just go ahead and PUT it. Otherwise ask for help
112     */
113     if (status==HT_ERROR || status==HT_INTERRUPTED || status==HT_TIMEOUT) {
114 	delete req;
115 	return HT_ERROR;
116     } else if (status==HT_NO_ACCESS || status==HT_NO_PROXY_ACCESS) {
117 	delete req;
118 	return HT_ERROR;
119     } else if (abs(status)/100!=2) {
120 	HTAnchor * source = req->Source();
121 	HTAnchor * dest = req->Destination();
122 	CRequest * new_req = new CRequest(req->m_pDoc);
123 	delete req;
124 
125 	/* Start a new PUT request with a "if-none-match *" precondition */
126 	new_req->PutDocument(source, dest, HT_DONT_MATCH_ANY);
127 
128     } else if (conflict.DoModal() == IDOK) {
129 
130 	if (conflict.m_versionResolution == 0) {
131 	    HTAnchor * source = req->Source();
132 	    HTAnchor * dest = req->Destination();
133 	    CRequest * new_req = new CRequest(req->m_pDoc);
134 	    delete req;
135 
136 	    /* Start a new PUT request without preconditions */
137 	    new_req->PutDocument(source, dest, HT_NO_MATCH);
138 
139 	} else if (conflict.m_versionResolution == 1) {
140 	    HTAnchor * address = req->Source();
141 	    CRequest * new_req = new CRequest(req->m_pDoc);
142 	    delete req;
143 
144 	    /* Start a new GET request  */
145 	    new_req->GetDocument(address, 2);
146         }
147     }
148     return HT_ERROR;
149 }
150 
151 //////////////////////////////////////////////////////////////////////
152 // Construction/Destruction
153 //////////////////////////////////////////////////////////////////////
154 
IMPLEMENT_DYNCREATE(CRequest,CObject)155 IMPLEMENT_DYNCREATE(CRequest, CObject)
156 
157 CRequest::CRequest(CWinComDoc * doc)
158 {
159     ASSERT(doc != NULL);
160     m_pDoc = doc;
161 
162     m_pHTRequest = NULL;
163     m_pSource = NULL;
164     m_pDestination = NULL;
165     m_file = NULL;
166 
167     // @@@ADD TO DOC LIST@@@
168 }
169 
~CRequest()170 CRequest::~CRequest()
171 {
172     // @@@REMOVE FROM DOC LIST@@@
173 }
174 
175 /////////////////////////////////////////////////////////////////////////////
176 // CWinComDoc commands
177 
SetCacheValidation(int mode)178 BOOL CRequest::SetCacheValidation(int mode)
179 {
180     ASSERT(m_pHTRequest != NULL);
181     HTReload reload = HT_CACHE_OK;
182     switch (mode) {
183     case 0:
184         reload = HT_CACHE_OK;
185         break;
186     case 1:
187         reload = HT_CACHE_VALIDATE;
188         break;
189     case 2:
190         reload = HT_CACHE_END_VALIDATE;
191         break;
192     case 3:
193         reload = HT_CACHE_FLUSH;
194         break;
195     default:
196         reload = HT_CACHE_OK;
197     }
198 
199     // Set the cache validation mode for this request
200     HTRequest_setReloadMode(m_pHTRequest, reload);
201 
202     return TRUE;
203 }
204 
GetDocument(HTAnchor * address,int cacheValidation)205 int CRequest::GetDocument (HTAnchor * address, int cacheValidation)
206 {
207     char filebuf[1024];
208     ASSERT(address != NULL);
209     char * uri = HTAnchor_address(address);
210 
211     m_pSource = address;
212 
213     CWinComApp * pApp = (CWinComApp *) AfxGetApp();
214     ASSERT(pApp != NULL);
215 
216     CFileDialog fd(FALSE);
217 
218     /* Find the start filename */
219     {
220 	char * name = NULL;
221 	char * suffix = HTBind_getSuffix(HTAnchor_parent(address));
222         char * uri_path = NULL;
223 	if (uri && (uri_path = HTParse(uri, "", PARSE_PATH|PARSE_PUNCTUATION))) {
224 	    char * last_segment = strrchr(uri_path, '/');
225 	    if (last_segment && *(last_segment+1)) {
226 		StrAllocMCopy(&name, ++last_segment, NULL);
227 	    } else {
228 		StrAllocMCopy(&name, DEF_LAST_SEGMENT,
229 			      suffix ? suffix : "", NULL);
230 	    }
231 	}
232 
233 	strcpy(filebuf, name);
234         fd.m_ofn.lpstrFile = filebuf;
235 
236 	HT_FREE(name);
237 	HT_FREE(suffix);
238     }
239 
240     /* Find the start folder */
241     fd.m_ofn.lpstrInitialDir = pApp->GetIniCWD();
242 
243     if (fd.DoModal() == IDOK) {
244 
245 	m_saveAs = fd.GetPathName();
246 
247 	// Set the initial dir for next time
248 	CString path = m_saveAs;
249 	int idx = path.ReverseFind('\\');
250 	if (idx != -1) path.GetBufferSetLength(idx+1);
251 	pApp->SetIniCWD(path);
252 
253         /* Create a new libwww request object */
254         m_pHTRequest = HTRequest_new();
255 
256 	/* Set the context so that we can find it again */
257 	HTRequest_setContext(m_pHTRequest, this);
258 
259         /* Terminating filters */
260 	InitializeFilters();
261 
262         /* Should we do cache validation? */
263         SetCacheValidation(cacheValidation);
264 
265         /* Progress bar */
266         m_pProgress = new CProgress(this);
267 	m_pProgress->Create(IDD_PROGRESS);
268 	m_pProgress->ShowWindow(SW_SHOW);
269 
270 	/* Start the GET */
271         if (HTLoadToFile (uri, m_pHTRequest, m_saveAs) == NO) {
272             HT_FREE(uri);
273 	    return -1;
274         }
275 
276         HT_FREE(uri);
277         return 0;
278     }
279 
280     HT_FREE(uri);
281     return -1;
282 }
283 
HeadDocument(HTAnchor * address,int cacheValidation)284 int CRequest::HeadDocument (HTAnchor * address, int cacheValidation)
285 {
286     ASSERT(address != NULL);
287 
288     m_pSource = address;
289 
290     /* Create a new libwww request object */
291     m_pHTRequest = HTRequest_new();
292 
293     /* Set the context so that we can find it again */
294     HTRequest_setContext(m_pHTRequest, this);
295 
296     /* Should we do cache validation? */
297     SetCacheValidation(cacheValidation);
298 
299     /* Terminating filters */
300     InitializeFilters();
301 
302     /* Progress bar */
303     m_pProgress = new CProgress(this);
304     m_pProgress->Create(IDD_PROGRESS);
305     m_pProgress->ShowWindow(SW_SHOW);
306 
307     /* Start the HEAD */
308     if (HTHeadAnchor(address, m_pHTRequest) == NO) {
309 	return -1;
310     }
311     return 0;
312 }
313 
DeleteDocument(HTAnchor * address,HTPreconditions preconditions)314 int CRequest::DeleteDocument (HTAnchor * address, HTPreconditions preconditions)
315 {
316     ASSERT(address != NULL);
317 
318     m_pSource = address;
319 
320     /* Create a new libwww request object */
321     m_pHTRequest = HTRequest_new();
322 
323     /* Set the context so that we can find it again */
324     HTRequest_setContext(m_pHTRequest, this);
325 
326     /* Should we use preconditions? */
327     HTRequest_setPreconditions(m_pHTRequest, preconditions);
328 
329     /* Terminating filters */
330     InitializeFilters();
331 
332     /* Progress bar */
333     m_pProgress = new CProgress(this);
334     m_pProgress->Create(IDD_PROGRESS);
335     m_pProgress->ShowWindow(SW_SHOW);
336 
337     /* Start the HEAD */
338     if (HTDeleteAnchor(address, m_pHTRequest) == NO) {
339 	return -1;
340     }
341     return 0;
342 }
343 
PutDocument(HTAnchor * source,HTAnchor * destination,HTPreconditions preconditions)344 int CRequest::PutDocument (HTAnchor * source,
345 			   HTAnchor * destination,
346 			   HTPreconditions preconditions)
347 {
348     ASSERT(source != NULL);
349     ASSERT(destination != NULL);
350 
351     m_pSource = source;
352     m_pDestination = destination;
353 
354     /* Create a new libwww request object */
355     m_pHTRequest = HTRequest_new();
356 
357     /* Set the context so that we can find it again */
358     HTRequest_setContext(m_pHTRequest, this);
359 
360     /* Should we use preconditions? */
361     HTRequest_setPreconditions(m_pHTRequest, preconditions);
362 
363     /* Terminating filters */
364     InitializeFilters();
365 
366     /* Progress bar */
367     m_pProgress = new CProgress(this);
368     m_pProgress->Create(IDD_PROGRESS);
369     m_pProgress->ShowWindow(SW_SHOW);
370 
371     /* Start the PUT */
372     if (HTPutDocumentAnchor(HTAnchor_parent(source), destination, m_pHTRequest) != YES) {
373 	return -1;
374     }
375     return 0;
376 }
377 
PutDocumentWithPrecheck(HTAnchor * source,HTAnchor * destination)378 int CRequest::PutDocumentWithPrecheck (HTAnchor * source,
379 				       HTAnchor * destination)
380 {
381     ASSERT(source != NULL);
382     ASSERT(destination != NULL);
383 
384     m_pSource = source;
385     m_pDestination = destination;
386 
387     /* Create a new libwww request object */
388     m_pHTRequest = HTRequest_new();
389 
390     /* Only use authentication and check AFTER filters */
391     HTRequest_addAfter(m_pHTRequest, HTAuthFilter,	"http://*", NULL, HT_NO_ACCESS, HT_FILTER_MIDDLE, YES);
392     HTRequest_addAfter(m_pHTRequest, HTAuthFilter, 	"http://*", NULL, HT_REAUTH,    HT_FILTER_MIDDLE, YES);
393     HTRequest_addAfter(m_pHTRequest, HTUseProxyFilter,	"http://*", NULL, HT_USE_PROXY, HT_FILTER_MIDDLE, YES);
394     HTRequest_addAfter(m_pHTRequest, check_handler,	NULL,	    NULL, HT_ALL,       HT_FILTER_MIDDLE, YES);
395 
396     /* Set the context so that we can find it again */
397     HTRequest_setContext(m_pHTRequest, this);
398 
399     /* Set cache validation */
400     SetCacheValidation(2);
401 
402     /* Progress bar */
403     m_pProgress = new CProgress(this);
404     m_pProgress->Create(IDD_PROGRESS);
405     m_pProgress->ShowWindow(SW_SHOW);
406 
407     /* Start the HEAD */
408     if (HTHeadAnchor(destination, m_pHTRequest) == NO) {
409 	return -1;
410     }
411     return 0;
412 }
413 
Cancel()414 int CRequest::Cancel()
415 {
416     if (m_pHTRequest) HTRequest_kill(m_pHTRequest);
417     if (m_pProgress) m_pProgress = NULL;
418     return 0;
419 }
420 
Cleanup()421 BOOL CRequest::Cleanup()
422 {
423     if (m_file) {
424 	fclose(m_file);
425 	m_file = NULL;
426     }
427     if (m_pProgress) {
428 	m_pProgress->DestroyWindow();
429 	m_pProgress = NULL;
430     }
431     return TRUE;
432 }
433 
Source()434 HTAnchor * CRequest::Source()
435 {
436     return m_pSource;
437 }
438 
Destination()439 HTAnchor * CRequest::Destination()
440 {
441     return m_pDestination;
442 }
443 
InitializeFilters()444 BOOL CRequest::InitializeFilters()
445 {
446     static BOOL initialized = NO;
447     if (initialized == NO) {
448 
449 	/* Add our own after filter to handle 412 precondition failed */
450         HTNet_addAfter(precondition_handler, NULL, NULL, HT_PRECONDITION_FAILED, HT_FILTER_MIDDLE);
451 
452         /* Add our own after filter to clecn up */
453         HTNet_addAfter(terminate_handler, NULL, NULL, HT_ALL, HT_FILTER_LAST);
454 
455 	initialized = YES;
456 
457 	return TRUE;
458     }
459     return FALSE;
460 }
461 
GetProgressBar()462 CProgressCtrl * CRequest::GetProgressBar()
463 {
464     return &(m_pProgress->m_progress);
465 }
466 
467