2 ** openurl.library - universal URL display and browser
5 ** Written by Troels Walsted Hansen <troels@thule.no>
6 ** Placed in the public domain.
9 ** - Alfonso Ranieri <alforan@tin.it>
10 ** - Stefan Kost <ensonic@sonicpulse.de>
12 ** Ported to OS4 by Alexandre Balaban <alexandre@balaban.name>
17 #include <dos/dostags.h>
18 #include <exec/execbase.h>
20 /**************************************************************************/
22 #define FINDPORT_NUM 100 /* how many FindPort() to do while waiting */
23 #define FINDPORT_TIME 10 /* how many seconds to spread those FindPort() over */
24 #define FINDPORT_DTIME ((FINDPORT_TIME * TICKS_PER_SECOND)/FINDPORT_NUM)
32 #define PH_COUNT_BROWSER 2
33 #define PH_COUNT_MAILER 6
34 #define PH_COUNT_FTP 2
36 /**************************************************************************/
39 expandPlaceHolders(UBYTE
*template,struct placeHolder
*ph
,int num
)
44 for (p
= template; *p
; p
++)
46 for (i
= 0; i
<num
; i
++)
48 if ((*p
=='%') && (*(p
+1)== ph
[i
].ph_Char
))
49 length
+= strlen(ph
[i
].ph_String
);
55 if (!(res
= allocVecPooled(length
+1)))
58 for (p
= res
; *template; template++)
60 for (i
= 0; i
<num
; i
++)
61 if ((*template=='%') && (*(template+1)== ph
[i
].ph_Char
))
66 strcpy(p
,ph
[i
].ph_String
);
67 p
+= strlen(ph
[i
].ph_String
);
80 /**************************************************************************/
83 writeToFile(UBYTE
*fileName
,UBYTE
*str
)
87 LONG len
= strlen(str
);
89 if ((fh
= Open(fileName
,MODE_NEWFILE
)))
91 if (Write(fh
,str
,len
)==len
)
100 /**************************************************************************/
103 findRexxPort(struct List
*list
,UBYTE
*name
)
108 /* find a rexx port, allowing a .<number> extension */
112 for (n
= list
->lh_Head
; n
->ln_Succ
; n
= n
->ln_Succ
)
114 if (n
->ln_Name
&& !strncmp(n
->ln_Name
,name
,len
) &&
115 (n
->ln_Name
[len
]=='\0' || (n
->ln_Name
[len
]=='.' && isdigits(&n
->ln_Name
[len
+1]))))
124 /**************************************************************************/
127 waitForRexxPort(UBYTE
*port
)
131 /* (busy) wait for the port to appear */
133 for (i
= 0; i
<FINDPORT_NUM
; i
++)
138 rxport
= findRexxPort(&SysBase
->PortList
,port
);
141 if (rxport
) return(rxport
);
143 if (SetSignal(0,0) & SIGBREAKF_CTRL_C
)
146 Delay(FINDPORT_DTIME
);
152 /**************************************************************************/
155 sendRexxMsg(UBYTE
*rxport
,UBYTE
*rxcmd
)
160 if ((sig
= AllocSignal(-1))>=0)
162 struct Process
*proc
;
163 struct TagItem attrs
[] = {NP_Entry
, (IPTR
)handler
,
165 NP_CodeType
, CODETYPE_PPC
,
166 NP_PPCStackSize
, 8192,
169 NP_Name
, (IPTR
)"OpenURL - Handler",
171 NP_Input
, (IPTR
)NULL
,
172 NP_CloseInput
, FALSE
,
173 NP_Output
, (IPTR
)NULL
,
174 NP_CloseOutput
, FALSE
,
175 NP_Error
, (IPTR
)NULL
,
176 NP_CloseError
, FALSE
,
179 if ((proc
= CreateNewProcTagList(attrs
)))
182 struct startMsg smsg
;
190 memset(&smsg
,0,sizeof(smsg
));
191 INITMESSAGE(&smsg
,&port
,sizeof(smsg
));
195 PutMsg(&proc
->pr_MsgPort
,(struct Message
*)&smsg
);
208 /****************************************************************************/
211 sendToBrowser(UBYTE
*URL
,
212 struct List
*portlist
,
217 UBYTE
*pubScreenName
)
221 struct placeHolder ph
[PH_COUNT_BROWSER
];
222 struct URL_BrowserNode
*bn
;
224 /* set up the placeholder mapping */
226 ph
[0].ph_Char
= 'u'; ph
[0].ph_String
= URL
;
227 ph
[1].ph_Char
= 'p'; ph
[1].ph_String
= pubScreenName
? pubScreenName
: (UBYTE
*)"Workbench";
229 /* try to find one of the browsers in the list */
231 for (bn
= (struct URL_BrowserNode
*)lib_prefs
->up_BrowserList
.mlh_Head
;
232 bn
->ubn_Node
.mln_Succ
;
233 bn
= (struct URL_BrowserNode
*)bn
->ubn_Node
.mln_Succ
)
237 if (bn
->ubn_Flags
& UNF_DISABLED
) continue;
239 port
= findRexxPort(portlist
,bn
->ubn_Port
);
243 /* send uniconify msg */
245 if (show
&& *bn
->ubn_ShowCmd
)
246 sendRexxMsg(port
,bn
->ubn_ShowCmd
);
248 /* send screentofront command */
250 if (toFront
&& *bn
->ubn_ToFrontCmd
)
251 sendRexxMsg(port
,bn
->ubn_ToFrontCmd
);
253 /* try sending openurl msg */
255 if (!(cmd
= expandPlaceHolders(newWindow
? bn
->ubn_OpenURLWCmd
: bn
->ubn_OpenURLCmd
,ph
,PH_COUNT_BROWSER
)))
258 if (!(res
= sendRexxMsg(port
,cmd
)))
267 /* no running browser, launch a new one */
269 if (!launch
) goto done
;
271 for (bn
= (struct URL_BrowserNode
*)lib_prefs
->up_BrowserList
.mlh_Head
;
272 bn
->ubn_Node
.mln_Succ
;
273 bn
= (struct URL_BrowserNode
*)bn
->ubn_Node
.mln_Succ
)
276 UBYTE
*filePart
, c
= '\0';
280 if (bn
->ubn_Flags
& UNF_DISABLED
) continue;
281 if (!*bn
->ubn_Path
) continue;
283 /* compose commandline */
285 if (strstr(bn
->ubn_Path
,"%u")) startOnly
= TRUE
;
286 else startOnly
= FALSE
;
288 if (!(cmd
= expandPlaceHolders(bn
->ubn_Path
,ph
,PH_COUNT_BROWSER
)))
291 filePart
= FilePart(bn
->ubn_Path
);
299 lock
= Lock(bn
->ubn_Path
,ACCESS_READ
);
301 if (filePart
) *filePart
= c
;
303 /* start the browser */
305 error
= SystemTags(cmd
,SYS_Asynch
, TRUE
,
306 SYS_Input
, Open("NIL:",MODE_NEWFILE
),
308 lock
? NP_CurrentDir
: TAG_IGNORE
, lock
,
316 if (lock
) UnLock(lock
);
324 /* send urlopen command */
326 if (!(cmd
= expandPlaceHolders(bn
->ubn_OpenURLCmd
,ph
,PH_COUNT_BROWSER
)))
329 /* wait for the port to appear */
331 if ((rxport
= waitForRexxPort(bn
->ubn_Port
)))
332 res
= sendRexxMsg(rxport
,cmd
);
344 if (cmd
) freeVecPooled(cmd
);
349 /**************************************************************************/
352 sendToFTP(UBYTE
*URL
,
353 struct List
*portlist
,
358 UBYTE
*pubScreenName
)
362 struct placeHolder ph
[PH_COUNT_FTP
];
363 struct URL_FTPNode
*fn
;
365 /* set up the placeholder mapping */
367 ph
[0].ph_Char
= 'u'; /*ph[0].ph_String = URL;*/
368 ph
[1].ph_Char
= 'p'; ph
[1].ph_String
= pubScreenName
? pubScreenName
: (UBYTE
*)"Workbench";
370 /* try to find one of the ftp client in the list */
372 for (fn
= (struct URL_FTPNode
*)lib_prefs
->up_FTPList
.mlh_Head
;
373 fn
->ufn_Node
.mln_Succ
;
374 fn
= (struct URL_FTPNode
*)fn
->ufn_Node
.mln_Succ
)
378 if (fn
->ufn_Flags
& UNF_DISABLED
) continue;
380 port
= findRexxPort(portlist
,fn
->ufn_Port
);
384 /* send uniconify msg */
386 if (show
&& *fn
->ufn_ShowCmd
)
387 sendRexxMsg(port
,fn
->ufn_ShowCmd
);
389 /* send screentofront command */
391 if (toFront
&& *fn
->ufn_ToFrontCmd
)
392 sendRexxMsg(port
,fn
->ufn_ToFrontCmd
);
394 /* try sending openurl msg */
396 if (fn
->ufn_Flags
& UFNF_REMOVEFTP
&& !Strnicmp(URL
,"ftp://",6))
397 ph
[0].ph_String
= URL
+6;
398 else ph
[0].ph_String
= URL
+6;
400 if (!(cmd
= expandPlaceHolders(newWindow
? fn
->ufn_OpenURLWCmd
: fn
->ufn_OpenURLCmd
,ph
,PH_COUNT_FTP
)))
403 if (!(res
= sendRexxMsg(port
,cmd
)))
412 /* no running ftp client, launch a new one */
414 if (!launch
) goto done
;
416 for (fn
= (struct URL_FTPNode
*)lib_prefs
->up_FTPList
.mlh_Head
;
417 fn
->ufn_Node
.mln_Succ
;
418 fn
= (struct URL_FTPNode
*)fn
->ufn_Node
.mln_Succ
)
421 UBYTE
*filePart
, c
= '\0';
425 if (fn
->ufn_Flags
& UNF_DISABLED
) continue;
426 if (!*fn
->ufn_Path
) continue;
428 /* compose commandline */
430 if (strstr(fn
->ufn_Path
,"%u"))
435 if (fn
->ufn_Flags
& UFNF_REMOVEFTP
&& !Strnicmp(URL
,"ftp://",6))
436 ph
[0].ph_String
= URL
+6;
437 else ph
[0].ph_String
= URL
+6;
439 if (!(cmd
= expandPlaceHolders(fn
->ufn_Path
,ph
,PH_COUNT_FTP
)))
442 filePart
= FilePart(fn
->ufn_Path
);
450 lock
= Lock(fn
->ufn_Path
,ACCESS_READ
);
452 if (filePart
) *filePart
= c
;
454 /* start the ftp client */
456 error
= SystemTags(cmd
,SYS_Asynch
, TRUE
,
457 SYS_Input
, Open("NIL:",MODE_NEWFILE
),
459 lock
? NP_CurrentDir
: TAG_IGNORE
, lock
,
467 if (lock
) UnLock(lock
);
475 /* send urlopen command */
477 if (!(cmd
= expandPlaceHolders(fn
->ufn_OpenURLCmd
,ph
,PH_COUNT_FTP
)))
480 /* wait for the port to appear */
482 if ((rxport
= waitForRexxPort(fn
->ufn_Port
)))
483 res
= sendRexxMsg(rxport
,cmd
);
495 if (cmd
) freeVecPooled(cmd
);
499 /**************************************************************************/
501 static WORD trans
[256];
504 sendToMailer(UBYTE
*URL
,
505 struct List
*portlist
,
509 UBYTE
*pubScreenName
)
511 struct placeHolder ph
[PH_COUNT_MAILER
];
512 struct URL_MailerNode
*mn
;
513 UBYTE
*start
, *end
, *data
, *address
= NULL
, *subject
= NULL
, *body
= NULL
,
514 *cmd
= NULL
, **tag
, fileName
[32];
515 ULONG res
= FALSE
, written
= FALSE
;
519 ObtainSemaphore(&lib_sem
);
520 if (!(lib_flags
& BASEFLG_Trans
))
522 for (len
= 0; len
<256; len
++) trans
[len
] = -1;
534 trans
['A'] = trans
['a'] = 10;
535 trans
['B'] = trans
['b'] = 11;
536 trans
['C'] = trans
['c'] = 12;
537 trans
['D'] = trans
['d'] = 13;
538 trans
['E'] = trans
['e'] = 14;
539 trans
['F'] = trans
['f'] = 15;
541 lib_flags
|= BASEFLG_Trans
;
543 ReleaseSemaphore(&lib_sem
);
545 /* parse the URL "mailto:user@host.domain?subject=Subject&body=Body" */
554 /* Use utility.library - Piru */
556 if (!Strnicmp(start
,"mailto:",7))
560 end
= strchr(start
+offset
,'?');
562 else if ((!Strnicmp(start
,"?subject=",9)) || (!Strnicmp(start
,"&subject=",9)))
566 end
= strchr(start
+offset
,'&');
568 else if ((!Strnicmp(start
,"?body=",6)) || (!Strnicmp(start
,"&body=",6)))
572 end
= strchr(start
+offset
,'&');
575 /* if we found some data && we even found it the first time ! */
580 if (end
) len
=end
-data
;
581 else len
=strlen(data
);
583 if (!(*tag
= allocVecPooled(len
+1))) goto done
;
585 strncpy(*tag
,data
,len
);
588 /* decode %XX sequences in urls */
592 if ((data
=strchr(data
,'%')) && (trans
[data
[1]]!=-1) && (trans
[data
[2]]!=-1))
594 *data
=(trans
[data
[1]]<<4)|trans
[data
[2]];
596 memmove(data
,data
+2,strlen(data
+2)+1);
604 if (body
) msprintf(fileName
,"T:OpenURL-MailBody.%08lx",(IPTR
)FindTask(NULL
));
608 strcpy(fileName
,"NIL:");
611 /* set up the placeholder mapping */
613 ph
[0].ph_Char
= 'a'; ph
[0].ph_String
= address
? address
: (UBYTE
*)"";
614 ph
[1].ph_Char
= 's'; ph
[1].ph_String
= subject
? subject
: (UBYTE
*)"";//URL;
615 ph
[2].ph_Char
= 'b'; ph
[2].ph_String
= body
? body
: (UBYTE
*)"";
616 ph
[3].ph_Char
= 'f'; ph
[3].ph_String
= fileName
;
617 ph
[4].ph_Char
= 'u'; ph
[4].ph_String
= URL
;
618 ph
[5].ph_Char
= 'p'; ph
[5].ph_String
= pubScreenName
? pubScreenName
: (UBYTE
*)"Workbench";
620 /* try to find one of the mailers in the list */
622 for (mn
= (struct URL_MailerNode
*)lib_prefs
->up_MailerList
.mlh_Head
;
623 mn
->umn_Node
.mln_Succ
;
624 mn
= (struct URL_MailerNode
*)mn
->umn_Node
.mln_Succ
)
628 if (mn
->umn_Flags
& UNF_DISABLED
) continue;
630 rxport
= findRexxPort(portlist
,mn
->umn_Port
);
634 /* send uniconify msg */
636 if (show
&& *mn
->umn_ShowCmd
)
637 sendRexxMsg(rxport
,mn
->umn_ShowCmd
);
639 /* send screentofront command */
641 if (toFront
&& *mn
->umn_ToFrontCmd
)
642 sendRexxMsg(rxport
,mn
->umn_ToFrontCmd
);
644 /* write to temp file */
646 if (!written
&& strstr(mn
->umn_WriteMailCmd
,"%f"))
647 written
= writeToFile(fileName
,body
);
649 /* try sending writemail msg */
651 if (!(cmd
= expandPlaceHolders(mn
->umn_WriteMailCmd
,ph
,PH_COUNT_MAILER
)))
654 /* now split each message at the ';' and send fragments */
658 while ((*end
) && (*end
!=';'))
661 /* skip data, which is enclosed in "" */
665 while ((*end
) && (*end
!='"')) end
++;
666 if (*end
=='"') end
++;
669 /* are there more commands */
676 if (!(res
= sendRexxMsg(rxport
,start
)))
678 /* send failed, try next mailer */
684 /* cmd processed succesfully, return */
689 /* no running ftp client, launch a new one */
691 if (!launch
) goto done
;
693 for (mn
= (struct URL_MailerNode
*)lib_prefs
->up_MailerList
.mlh_Head
;
694 mn
->umn_Node
.mln_Succ
;
695 mn
= (struct URL_MailerNode
*)mn
->umn_Node
.mln_Succ
)
698 UBYTE
*filePart
, c
= '\0';
702 if (mn
->umn_Flags
& UNF_DISABLED
) continue;
703 if (!*mn
->umn_Path
) continue;
705 /* compose commandline */
707 if (strstr(mn
->umn_Path
,"%a"))
712 if (!written
&& strstr(mn
->umn_Path
,"%f"))
713 written
= writeToFile(fileName
,body
);
715 if (!(cmd
= expandPlaceHolders(mn
->umn_Path
,ph
,PH_COUNT_MAILER
)))
718 filePart
= FilePart(mn
->umn_Path
);
726 lock
= Lock(mn
->umn_Path
,ACCESS_READ
);
728 if (filePart
) *filePart
= c
;
730 /* start the mailer */
732 error
= SystemTags(cmd
,SYS_Asynch
, TRUE
,
733 SYS_Input
, Open("NIL:", MODE_NEWFILE
),
735 lock
? NP_CurrentDir
: TAG_IGNORE
, lock
,
743 if (lock
) UnLock(lock
);
751 /* send write mail command */
753 if (!written
&& strstr(mn
->umn_WriteMailCmd
,"%f"))
754 /*written = */writeToFile(fileName
,body
);
756 if (!(cmd
= expandPlaceHolders(mn
->umn_WriteMailCmd
,ph
,PH_COUNT_MAILER
)))
759 /* wait for the port to appear */
761 if ((rxport
= waitForRexxPort(mn
->umn_Port
)))
766 while ((*end
) && (*end
!=';'))
769 /* skip data, which is enclosed in "" */
773 while ((*end
) && (*end
!='"')) end
++;
774 if (*end
=='"') end
++;
777 /* are there more commands */
783 if (!(res
= sendRexxMsg(rxport
,start
)))
785 /* send failed, try next mailer */
802 if (cmd
) freeVecPooled(cmd
);
803 if (body
) freeVecPooled(body
);
804 if (subject
) freeVecPooled(subject
);
805 if (address
) freeVecPooled(address
);
810 /**************************************************************************/
813 copyList(struct List
*dst
,struct List
*src
,ULONG size
)
815 struct Node
*n
, *new;
817 /* copy src list into dst, and return success */
819 for (n
= src
->lh_Head
; n
->ln_Succ
; n
= n
->ln_Succ
)
821 if (!(new = allocPooled(size
)))
834 /**************************************************************************/
837 freeList(struct List
*list
,ULONG size
)
841 while ((n
= RemHead(list
))) freePooled(n
,size
);
844 /**************************************************************************/
851 if (!*str
) return(TRUE
);
852 else if (!isdigit(*str
)) return(FALSE
);
858 /**************************************************************************/
860 #if !defined(__MORPHOS__) && !defined(__amigaos4__) && !defined(__AROS__)
861 static UWORD fmtfunc
[] = { 0x16c0, 0x4e75 };
863 msprintf(UBYTE
*buf
,UBYTE
*fmt
,...)
865 RawDoFmt(fmt
,&fmt
+1,(APTR
)fmtfunc
,buf
);
867 #elif defined(__amigaos4__)
870 msprintf(UBYTE
*buf
,UBYTE
*fmt
,...)
873 va_startlinear(va
,fmt
);
874 RawDoFmt(fmt
, va_getlinearva(va
,CONST APTR
), (void (*)(void)) 0, buf
);
880 /**************************************************************************/
883 allocPooled(ULONG size
)
887 ObtainSemaphore(&lib_memSem
);
888 mem
= AllocPooled(lib_pool
,size
);
889 ReleaseSemaphore(&lib_memSem
);
894 /****************************************************************************/
897 freePooled(APTR mem
,ULONG size
)
899 ObtainSemaphore(&lib_memSem
);
900 FreePooled(lib_pool
,mem
,size
);
901 ReleaseSemaphore(&lib_memSem
);
904 /****************************************************************************/
907 allocVecPooled(ULONG size
)
911 ObtainSemaphore(&lib_memSem
);
912 if ((mem
= AllocPooled(lib_pool
,size
= size
+sizeof(ULONG
)))) *mem
++ = size
;
913 ReleaseSemaphore(&lib_memSem
);
918 /****************************************************************************/
921 freeVecPooled(APTR mem
)
923 ObtainSemaphore(&lib_memSem
);
924 FreePooled(lib_pool
,(ULONG
*)mem
-1,*((ULONG
*)mem
-1));
925 ReleaseSemaphore(&lib_memSem
);
928 /****************************************************************************/