DBA Data[Home] [Help]

PACKAGE BODY: APPS.WFA_HTML

Source


1 package body WFA_HTML as
2 /* $Header: wfhtmb.pls 120.5.12010000.7 2009/12/09 18:47:45 vshanmug ship $ */
3 
4 -- Bug# 2236250 exception to handle invalid number
5 invalid_number exception;
6 pragma EXCEPTION_INIT(invalid_number, -6502);
7 
8 
9 g_priority  varchar2(2000);
10 g_newline   varchar2(1)    := wf_core.newLine;
11 g_wfInstall varchar2(15)   := wf_core.translate('WF_INSTALL');
12 g_webAgent  varchar2(2000) := wf_core.translate('WF_WEB_AGENT');
13 
14 --
15 -- Error (PRIVATE)
16 --   Print a page with an error message.
17 --   Errors are retrieved from these sources in order:
18 --     1. wf_core errors
19 --     2. Oracle errors
20 --     3. Unspecified INTERNAL error
21 --
22 procedure Error
23 as
24 
25 begin
26      null;
27 end Error;
28 
29 
30 --
31 --
32 -- Login
33 --   Generate login page.
34 -- IN
35 --   message - optional login message
36 -- NOTE
37 --   This page is only used to enable access when no external security
38 --   is installed.  Normally users are authenticated by the chosen
39 --   security system (IC, WebServer native, etc) and can then access
40 --   the Workflow Notification pages (Worklist, Detail) directly.
41 --
42 procedure Login(
43   message in varchar2,
44   i_direct in varchar2)
45 as
46 
47 c_language    VARCHAR2(80);
48 
49 begin
50 
51   -- Get the global language preference since we don't know who the
52   -- user is yet...
53   c_language := NVL(wf_pref.get_pref ('-WF_DEFAULT-', 'LANGUAGE'), 'AMERICAN');
54   c_language := ''''||c_language||'''';
55   dbms_session.set_nls('NLS_LANGUAGE'   , c_language);
56 
57   -- Set the language to the default language for the system
58 
59   htp.htmlOpen;
60   htp.headOpen;
61   htp.title(wf_core.translate('WFA_LOGIN_REQUEST'));
62    wfa_html.create_help_function('wf/links/log.htm?LOGIN');
63   htp.headClose;
64   wfa_sec.Header(background_only=>FALSE, inc_lov_applet=>FALSE);
65 
66   htp.p('<FORM NAME="WFA_LOGIN" ACTION="wfa_html.Viewer" TARGET="_top" METHOD="POST">');
67 
68 -- bug 1838410
69    if (i_direct is not null) then
70        htp.formHidden('i_direct', i_direct);
71    end if;
72 
73 
74   if (message is not null) then
75     htp.header(4, wf_core.translate(message));
76     htp.br;
77   end if;
78 
79   htp.br;
80   htp.tableOpen(calign=>'CENTER', cattributes=>'summary=""');
81   htp.tableRowOpen;
82   htp.tableData('<LABEL FOR="i_user_id">' ||
83                 wf_core.translate('USER_ID') ||
84                 '</LABEL>', 'Right',
85                 cattributes=>'id=""');
86   htp.tableData(htf.formText('User_ID', 25, cattributes=>'id="i_user_id"'),
87                 'Left', cattributes=>'id=""');
88   htp.tableRowClose;
89 
90   htp.tableRowOpen;
91   htp.tableData('<LABEL FOR="i_password">' ||
92                 wf_core.translate('PASSWORD') ||
93                 '</LABEL>', 'Right',
94                 cattributes=>'id=""');
95   htp.tableData(htf.formPassword('Password', 25,
96                                  cattributes=>'id="i_password"'), 'Left',
97                 cattributes=>'id=""');
98   htp.tableRowClose;
99 
100   htp.tableClose;
101   htp.centerClose;
102   htp.br;
103 
104   htp.formClose;
105 
106   htp.tableopen (calign=>'CENTER', cattributes=>'summary=""');
107   htp.tableRowOpen;
108 
109   htp.p('<TD id="">');
110 
111   wfa_html.create_reg_button ('javascript:document.WFA_LOGIN.submit()',
112                               wf_core.translate ('LOGIN'),
113                               wfa_html.image_loc,
114                               'FNDJLFOK.gif',
115                               wf_core.translate ('LOGIN'));
116 
117   htp.p('</TD>');
118 
119   htp.tableRowClose;
120   htp.tableClose;
121 
122   wfa_sec.Footer;
123   htp.htmlClose;
124 exception
125   when others then
126     rollback;
127     wf_core.context('Wfa_Html', 'Login');
128     wfa_html.Error;
129 end Login;
130 
131 --
132 -- Viewer
133 --   Validate user from Login page, then show worklist.
134 -- IN
135 --   user_id  - user name
136 --   password - user password
137 -- NOTE
138 --   This page is only used to enable access when no external security
139 --   is installed.  Normally users are authenticated by the chosen
140 --   security system (IC, WebServer native, etc) and can then access
141 --   the Workflow Notification pages (Worklist, Detail) directly.
142 --
143 procedure Viewer(
144   user_id  in varchar2,
145   password in varchar2,
146   i_direct in varchar2)
147 as
148   s0          varchar2(320);   -- dummy
149   username    varchar2(320);
150   realname    varchar2(360);
151 
152 begin
153   -- Validate the user
154   if (user_id is null) then
155      -- No username entered
156      wfa_html.Login('WFA_ENTER_ID');
157      return;
158   end if;
159   username := upper(user_id);
160 
161   begin
162     wfa_sec.CreateSession(username, password);
163   exception
164     when others then
165       if (wf_core.error_name='WFSEC_USER_PASSWORD') then
166         -- Bad username or password
167         wf_core.clear;
168         wfa_html.Login('WFA_ILLEGAL_IDP');
169         return;
170       end if;
171       -- Raise any other error message
172       raise;
173   end;
174 
175 if (i_direct is null) then
176 
177   -- Go to home page
178   Wfa_Html.Home;
179 
180 else
181   -- Fix for bug 1838410
182   -- Instead of navigating to the home page, we will go directly to the URL
183   -- specified in i_direct and the user will now be authenticated.  We are
184   -- calling the function within a frame.
185   -- Example: E-mail notifications with send_accesskey=N.
186 
187   htp.p('<HTML>');
188   htp.p('<HEAD>');
189   htp.p('<TITLE>');
190   htp.p('</TITLE>');
191   htp.p('</HEAD>');
192   htp.p('<FRAMESET ROWS="100%, *">');
193   htp.p('<FRAME NAME="DirectLogin" MARGINHEIGHT=10 MARGINWIDTH=10 NORESIZE' ||
194     ' src="'||owa_util.get_owa_service_path || i_direct || '">');
195   htp.p('</FRAMESET>');
196   htp.p('</HTML>');
197 
198   end if;
199 
200 exception
201   when others then
202     rollback;
203     wf_core.context('Wfa_Html', 'Viewer', user_id, password);
204     wfa_html.Error;
205 end Viewer;
206 
207 
208 --
209 -- Find
210 --   Filter page to find notifications of user
211 --
212 procedure Find
213 is
214 begin
215            null;
216 end Find;
217 
218 --
219 -- GetPriorityBounds
220 --   Get the upper bound and lower bound of certain priority
221 -- IN
222 --   priority - Value of priority
223 --              Valid values are HIGH, NORMAL, LOW and *
224 -- IN OUT
225 --   low      - lower bound of numeric priority value
226 --   up       - upper bound of numeric priority value
227 -- RETURNS
228 --   TRUE     - successfully return the boundaries
229 --   FALSE    - failed to translate
230 --
231 function GetPriorityBounds(
232   priority in     varchar2,
233   low      in out nocopy pls_integer,
234   up       in out nocopy pls_integer)
235 return boolean
236 as
237 --  minint   pls_integer := 0;
238 --  maxint   pls_integer := 2147483647;  /* 2^31 - 1 */
239 
240 --
241 -- Priority Range should be 1 - 99
242 -- For supporting some possible out of range value in the past,
243 -- we set the range a bit higher
244 --
245   minint   pls_integer := 0;
246   maxint   pls_integer := 1000000;
247 begin
248   if    (priority = '*') then
249     low  := minint;
250     up   := maxint;
251   elsif (priority = 'HIGH') then
252     low  := minint;
253     up   :=  33;
254   elsif (priority = 'NORMAL') then
255     low  :=  34;
256     up   :=  66;
257   elsif (priority = 'LOW') then
258     low  :=  67;
259     up   := maxint;
260   else
261     low  :=  -1;
262     up   :=  -1;
263     return FALSE;
264   end if;
265   return TRUE;
266 end GetPriorityBounds;
267 
268 --
269 -- GetPriorityIcon
270 --   Get the icon of certain numeric priority
271 -- IN
272 --   priority - Value of priority
273 --              Valid values are minint - maxint
274 --              defined in GetPriorityBounds
275 --
276 -- RETURNS
277 --   Icon  - location of an icon
278 --
279 function GetPriorityIcon(
280   priority in     pls_integer)
281 return varchar2
282 as
283 begin
284   if    (priority < 34) /* HIGH   */ then
285     WFA_HTML.g_priority := WF_CORE.Translate('WFJSP_HIGH_PRIORITY');
286     return(wfa_html.image_loc||'high.gif');
287   elsif (priority > 66) /* LOW    */ then
288     WFA_HTML.g_priority := WF_CORE.Translate('WFJSP_LOW_PRIORITY');
289     return(wfa_html.image_loc||'low.gif');
290   else                  /* NORMAL */
291     return null;
292   end if;
293 end GetPriorityIcon;
294 
295 --
296 -- WorkList
297 --   Construct the worklist (summary page) for user.
298 -- IN
299 --   orderkey - Key to order by (default PRIORITY)
300 --              Valid values are PRIORITY, MESSAGE_TYPE, SUBJECT, BEGIN_DATE,
301 --              DUE_DATE, END_DATE, STATUS.
302 --   status - Status to query (default OPEN)
303 --            Valid values are OPEN, CLOSED, CANCELED, ERROR, *.
304 --   user - User to query notifications for.  If null query user currently
305 --          logged in.
306 --          Note: Only a user in role WF_ADMIN_ROLE can query a user other
307 --          than the current user.
308 --   fromlogin - flag to indicate if coming from apps login screen,
309 --             - if non-zero, force an exception
310 --            - so that cookie value is not being used
311 --
312 procedure WorkList(
313   nid      in number,
314   orderkey in varchar2,
315   status in varchar2,
316   owner in varchar2 ,
317   display_owner in varchar2,
318   user in varchar2,
319   display_user in varchar2,
320   fromuser in varchar2,
321   display_fromuser in varchar2,
322   ittype in varchar2,
323   msubject in varchar2,
324   beg_sent in varchar2,
325   end_sent in varchar2,
326   beg_due in varchar2,
327   end_due in varchar2,
328   priority in varchar2,
329   delegatedto in varchar2,
330   display_delegatedto in varchar2,
331   delegated_by_me in number,
332   resetcookie in number,
333   clearbanner in varchar2,
334   fromfindscreen in number,
335   fromlogin in number)
336 as
337 begin
338   null;
339 end Worklist;
340 
341 --
342 -- Authenticate (PRIVATE)
343 --   Verify user is allowed access to this notification
344 -- IN
345 --   nid - notification id
346 --   nkey - notification access key (if disconnected)
347 -- RETURNS
348 --   Current user name
349 --
350 function Authenticate(
351   nid in number,
352   nkey in varchar2)
353 return varchar2
354 is
355   usercolon pls_integer;
356   rolecolon pls_integer;
357   origcolon pls_integer;
358   username varchar2(320);
359   recipient varchar2(320);
360   orig_recipient varchar2(320);
361   dummy pls_integer;
362   admin_role varchar2(320);
363   slash pls_integer;
364   wfsession varchar2(240);
365 
366   uos   varchar2(320);
367   uosid number;
368   ros   varchar2(320);
369   rosid number;
370   oos   varchar2(320);
371   oosid number;
372 begin
373   if (nkey is null) then
374     -- No nkey passed, means must be connected.  Get current user.
375     Wfa_Sec.GetSession(username);
376 
377     -- Get recipient and original recipient of this notification
378     begin
379       select RECIPIENT_ROLE, ORIGINAL_RECIPIENT
380       into recipient, orig_recipient
381       from WF_NOTIFICATIONS WN
382       where WN.NOTIFICATION_ID = nid;
383     exception
384       when no_data_found then
385         Wf_Core.Token('NID', nid);
386         Wf_Core.Raise('WFNTF_NID');
387     end;
388 
389     -- Verify this notification was sent to this user
390     -- Note that username could be the in the recipient role
391     -- or in the original recipient role.
392     begin
393       usercolon := instr(username, ':');
394       rolecolon := instr(recipient, ':');
395       origcolon := instr(orig_recipient, ':');
396 
397       if (usercolon = 0) then
398         -- very costly sql statement, return the first row we find.
399         select ORIG_SYSTEM, ORIG_SYSTEM_ID
400           into uos, uosid
401           from WF_USERS
402          where NAME = username
403            and ORIG_SYSTEM not in ('HZ_PARTY','CUST_CONT')
404            and rownum < 2;
405       else
406          uos   := substr(username, 1, usercolon-1);
407          uosid := to_number(substr(username, usercolon+1));
408       end if;
409 
410       if (rolecolon = 0) then
411         -- when recipient = username, user is participate in the role of
412         -- the same name, they will have the same orig system and orig
413         -- system id.
414         if (recipient = username) then
415           ros   := uos;
416           rosid := uosid;
417         else
418           Wf_Directory.GetRoleOrigSysInfo(recipient,ros,rosid);
419         end if;
420       else
421         ros   := substr(recipient, 1, rolecolon-1);
422         rosid := to_number(substr(recipient, rolecolon+1));
423       end if;
424 
425       if (origcolon = 0) then
426         -- similarly, don't bother to requery the orig_system and
427         -- orig_system_id if original recipient matches recipient or username.
428         if (orig_recipient = recipient) then
429           oos   := ros;
430           oosid := rosid;
431         elsif (orig_recipient = username) then
432           oos   := uos;
433           oosid := uosid;
434         else
435           Wf_Directory.GetRoleOrigSysInfo(orig_recipient,oos,oosid);
436         end if;
437       else
438         oos   := substr(orig_recipient, 1, origcolon-1);
439         oosid := to_number(substr(orig_recipient, origcolon+1));
440       end if;
441 
442       -- rewritten the sql from an or join to union all.
443       -- reduced the query time from >25 sec to <0.5 sec.
444       select 1
445         into dummy
446         from sys.dual
447        where exists (
448          select null
449            from WF_USER_ROLES
450           where USER_ORIG_SYSTEM = uos
451             and USER_ORIG_SYSTEM_ID = uosid
452             and USER_NAME = username
453             and ROLE_ORIG_SYSTEM = ros
454             and ROLE_ORIG_SYSTEM_ID = rosid
455             and ROLE_NAME = recipient
456         union all
457          select null
458            from WF_USER_ROLES
459           where USER_ORIG_SYSTEM = uos
460             and USER_ORIG_SYSTEM_ID = uosid
461             and USER_NAME = username
462             and ROLE_ORIG_SYSTEM = oos
463             and ROLE_ORIG_SYSTEM_ID = oosid
464             and ROLE_NAME = orig_recipient
465         );
466 
467     exception
468       when no_data_found then
469         -- Check if current user has WF_ADMIN_ROLE privileges.
470         -- If so, allow access anyway.
471         admin_role := wf_core.translate('WF_ADMIN_ROLE');
472         if (admin_role <> '*' and
473             not Wf_Directory.IsPerformer(username, admin_role)) then
474           Wf_Core.Token('USER', username);
475           Wf_Core.Token('NID', to_char(nid));
476           Wf_Core.Raise('WFNTF_ACCESS_USER');
477         end if;
478     end;
479   else
480     -- Nkey passed, means this must be disconnected (mailed html).
481     -- Check the passed access key against the notification key.
482 
483     -- Construct wfsession-style access key as <nid>/<accesskey>.
484     -- First strip <nid> from nkey if present (only for backward
485     -- compatibility, current version only passes <accesskey>),
486     -- then construct full key with current nid.
487     -- Note: Key is reconstructed here instead of passing full
488     -- <nid>/<accesskey> directly to check that the key being passed
489     -- is really for this notification.
490     slash := instr(nkey, '/');
491     if (slash <> 0) then
492       wfsession := to_char(nid)||'/'||substr(nkey, slash+1);
493     else
494       wfsession := to_char(nid)||'/'||nkey;
495     end if;
496 
497     username := Wf_Notification.AccessCheck(wfsession);
498     if (username is null) then
499       wf_core.raise('WFNTF_ACCESS_KEY');
500     end if;
501   end if;
502 
503   return(username);
504 
505 exception
506   when others then
507     wf_core.context('Wfa_Html', 'Authenticate', to_char(nid), nkey);
508     raise;
509 end Authenticate;
510 
511 --
512 -- DetailFrame
513 --   generate Detail notification screen
514 -- IN
515 --   nid - notification id
516 --   nkey - notification access key (for mailed html only)
517 --   agent - web agent (OBSOLETE - for back compatibility only)
518 --   showforms - show form attributes
519 --
520 procedure DetailFrame(
521   nid in varchar2,
522   nkey in varchar2,
523   agent in varchar2,
524   showforms in varchar2)
525 as
526 begin
527   -- bug 7314545
528   null;
529 end DetailFrame;
530 
531 --
532 -- ResponseFrame
533 --   generate response frame contents
534 -- IN
535 --   nid - notification id
536 --   nkey - notification access key (for mailed html only)
537 --   agent - web agent (OBSOLETE - for back compatibility only)
538 --   showforms - show form attributes
539 --
540 procedure ResponseFrame(
541   nid in varchar2,
542   nkey in varchar2,
543   agent in varchar2,
544   showforms in varchar2)
545 as
546 begin
547   -- bug 7314545
548   null;
549 end ResponseFrame;
550 
551 --
552 -- ForwardFrame
553 --   generate forward frame contents
554 -- IN
555 --   nid - notification id
556 --   nkey - notification access key (for mailed html only)
557 --
558 procedure ForwardFrame(
559   nid in varchar2,
560   nkey in varchar2)
561 as
562 begin
563   -- bug 7314545
564   null;
565 end ForwardFrame;
566 
567 --
568 -- AttributeInfo
569 --   Generate page with details about a response attribute
570 -- IN
571 --   nid - notification id
572 --   name - attribute name
573 --
574 procedure AttributeInfo(
575   nid in varchar2,
576   name in varchar2)
577 is
578 begin
579   -- bug 7314545
580   null;
581 end AttributeInfo;
582 
583 --
584 -- RespFrameSize (RPIVATE)
585 --   Calculate size of response frame using heuristic
586 -- IN
587 --   nid - notification id
588 -- RETURNS
589 --   Size of response frame in pixels
590 --
591 function RespFrameSize(
592   nid in number)
593 return number
594 is
595   respcnt       pls_integer;
596   longcnt       pls_integer;
597   urlcnt        pls_integer;
598   respsize      pls_integer;
599 
600 begin
601   -- Approximate size of response frame using heuristic:
602   -- The rule of thumb being :
603   -- 1. Each non-result response counts as 40 pixels
604   --    + url and multiline fields count twice
605   --    + 1 for result button line
606   -- 2. Frame must be in range 100 - 250 pixels
607   -- 3. If there is a url respond attributet then go for the max size
608 
609   -- Count of multiline response fields
610   select count(1)
611   into urlcnt
612   from WF_MESSAGE_ATTRIBUTES MA,
613        WF_NOTIFICATIONS N
614   where N.NOTIFICATION_ID = nid
615   and MA.MESSAGE_NAME = N.MESSAGE_NAME
616   and MA.MESSAGE_TYPE = N.MESSAGE_TYPE
617   and MA.SUBTYPE = 'RESPOND'
618   and MA.TYPE = 'URL';
619 
620   if (urlcnt = 1) then
621     respsize := 250;
622   else
623 
624     -- Count of all response fields
625     select count(1)
626     into respcnt
627     from WF_NOTIFICATION_ATTRIBUTES NA,
628          WF_MESSAGE_ATTRIBUTES MA,
629          WF_NOTIFICATIONS N
630     where N.NOTIFICATION_ID = nid
631     and NA.NOTIFICATION_ID = N.NOTIFICATION_ID
632     and MA.MESSAGE_NAME = N.MESSAGE_NAME
633     and MA.MESSAGE_TYPE = N.MESSAGE_TYPE
634     and MA.NAME = NA.NAME
635     and MA.SUBTYPE = 'RESPOND'
636     and MA.TYPE <> 'FORM'
637     and MA.NAME <> 'RESULT';
638 
639     -- Count of multiline response fields
640     select count(1)
641     into longcnt
642     from WF_NOTIFICATION_ATTRIBUTES NA,
643          WF_MESSAGE_ATTRIBUTES MA,
644          WF_NOTIFICATIONS N
645     where N.NOTIFICATION_ID = nid
646     and NA.NOTIFICATION_ID = N.NOTIFICATION_ID
647     and MA.MESSAGE_NAME = N.MESSAGE_NAME
648     and MA.MESSAGE_TYPE = N.MESSAGE_TYPE
649     and MA.NAME = NA.NAME
650     and MA.SUBTYPE = 'RESPOND'
651     and MA.TYPE = 'VARCHAR2'
652     and decode(MA.TYPE, 'VARCHAR2', nvl(to_number(MA.FORMAT), 2000), 0) > 80;
653 
654 
655     respsize := (respcnt + longcnt + 1) * 40;
656     if (respsize < 100) then
657       respsize := 100;
658     elsif (respsize > 250) then
659       respsize := 250;
660     end if;
661   end if;
662 
663   return(respsize);
664 
665 exception
666   when others then
667     wf_core.context('Wfa_Html', 'RespFrameSize', to_char(nid));
668     raise;
669 end RespFrameSize;
670 
671 --
672 -- Detail (PROCEDURE)
673 --   generate detail screen
674 -- IN
675 --   nid - notification id
676 -- NOTE
677 --   Detail is overloaded.
678 --   This version is used by the Web notifications page.
679 --
680 procedure Detail(
681   nid in varchar2)
682 is
683 begin
684   -- bug 7314545
685   null;
686 end Detail;
687 
688 --
689 -- Detail (FUNCTION)
690 --   return standalone detail screen text
691 -- IN
692 --   nid - notification id
693 --   nkey - notification key
694 --   agent - web agent URL root
695 -- NOTE
696 --   Detail is overloaded.
697 --   This produces the version used by the mailer.
698 function Detail(
699     nid   in number,
700     nkey  in varchar2,
701     agent in varchar2)
702 return varchar2
703 as
704   username  varchar2(320);
705   status    varchar2(8);
706   realname  varchar2(360);
707   s0        varchar2(240);
708   result    varchar2(32000);
709   respsize  pls_integer;
710   key       varchar2(255);
711   n_sig_policy varchar2(100);
712 begin
713 
714   Wf_Mail.GetSignaturePolicy(nid, n_sig_policy);
715 
716   if (wf_mail.send_accesskey and n_sig_policy not in ('PSIG_ONLY')) then
717      key := nkey;
718 
719   -- Authenticate the user has access
720   username := Wfa_Html.Authenticate(nid, nkey);
721 
722   -- Get notification recipient and status
723   Wf_Notification.GetInfo(nid, username, s0, s0, s0, s0, status);
724   Wf_Directory.GetRoleInfo(username, realname, s0, s0, s0, s0);
725 
726   -- Set title
727   result := htf.htmlOpen ||g_newLine;
728   result := result || htf.headOpen||g_newLine;
729   if (status = 'OPEN') then
730     result := result ||
731         htf.title(wf_core.translate('WFA_DTITLE')||' '||realname)||
732                   g_newLine;
733   else
734     result := result ||
735         htf.title(wf_core.translate('WFA_CDTITLE')||' '||realname)||
736                   g_newLine;
737   end if;
738 
739 --tr: dont execute the help function
740 --it calls htp procs which causes session to hang
741 --  wfa_html.create_help_function('wf/links/det.htm?DETNOT');
742 
743   result := result || htf.headClose||g_newLine;
744 
745   -- Calculate size of response frame
746   respsize := RespFrameSize(nid);
747 
748   -- Open frameset.
749   -- NOTE: Do NOT set the focus here, because it is not supported on
750   -- all platforms, and it is unknown at this point what browser will
751   -- be used to display the html returned to the mailer.
752   result := result||'<FRAMESET ROWS="*,'||to_char(respsize)||'" TITLE="' ||
753           WF_CORE.Translate('WFA_DTITLE_TBAR') || '" LONGDESC="' ||
754           agent ||
755          'wfa_html.LongDesc?p_token=WFA_DTITLE_TBAR">'||
756             g_newLine;
757   result := result ||
758       '<FRAME NAME="top" MARGINHEIGHT=10 MARGINWIDTH=10 ' ||
759       'src="'||agent||'/wfa_html.DetailFrame?nid='||to_char(nid)||
760       '&'||'nkey='||key||'" TITLE="' ||
761           WF_CORE.Translate('WFA_DTITLE_TBAR') || '" LONGDESC="' ||
762           agent ||
763          'wfa_html.LongDesc?p_token=WFA_DTITLE_TBAR">'||g_newLine;
764   result := result ||
765     '<FRAME NAME="bottom" MARGINHEIGHT=10 MARGINWIDTH=10 ' ||
766     'src="'||agent||'/wfa_html.ResponseFrame?nid='||to_char(nid)||
767     '&'||'nkey='||key||'" TITLE="' ||
768           WF_CORE.Translate('WFA_DTITLE_TBAR') || '" LONGDESC="' ||
769           agent ||
770          'wfa_html.LongDesc?p_token=WFA_DTITLE_TBAR">'||g_newLine;
771   result := result || '</FRAMESET>'||g_newLine;
772   result := result || htf.htmlClose;
773 
774   else
775   -- Send_accesskey is set to N so we will generate a DirectLogin call.
776   -- We do not need to authenticate the user, since the user will have
777   -- to authenticate to view the notification.  After authentication,
778   -- DirectLogin will redirect to the Detail (Web-interface) procedure so
779   -- we will then confirm that the user logged in can also view the
780   -- notification.
781   key := NULL;
782 
783   result := htf.htmlOpen ||g_newLine;
784   result := result || htf.headOpen||g_newLine;
785   result := result ||
786         htf.title(wf_core.translate('WFA_LOGIN_REQUEST'))||
787                   g_newLine;
788   result := result || htf.headClose||g_newLine;
789 
790   result := result||'<FRAMESET ROWS="100%, *">'||g_newLine;
791 
792   result := result ||
793     '<FRAME NAME="DirectLogin" MARGINHEIGHT=10 MARGINWIDTH=10 NORESIZE' ||
794     ' src="'||agent || '/' || wfa_sec.DirectLogin(nid) || '">'||g_newLine;
795   result := result || '</FRAMESET>'||g_newLine;
796   result := result || htf.htmlClose;
797 end if;
798 
799   return(result);
800 exception
801   when others then
802     wf_core.context('Wfa_Html', 'Detail', to_char(nid), nkey, agent);
803     raise;
804 end Detail;
805 
806 --
807 -- Detail2 (FUNCTION)
808 --   return standalone detail screen text
809 -- IN
810 --   nid - notification id
811 --   nkey - notification key
812 --   agent - web agent URL root
813 -- NOTE
814 --   Detail is overloaded.
815 --   This produces the version used by the mailer.
816 function Detail2(
817     nid   in number,
818     nkey  in varchar2,
819     agent in varchar2)
820 return varchar2
821 as
822   username  varchar2(320);
823   status    varchar2(8);
824   realname  varchar2(360);
825   s0        varchar2(240);
826   result    varchar2(32000);
827   n_sig_policy varchar2(100);
828   url       varchar2(4000);
829   l_function_id number;
830 begin
831 
832   Wf_Mail.GetSignaturePolicy(nid, n_sig_policy);
833 
834   -- Authenticate the user has access
835   username := Wfa_Html.Authenticate(nid, nkey);
836 
837   -- Get notification recipient and status
838   Wf_Notification.GetInfo(nid, username, s0, s0, s0, s0, status);
839   Wf_Directory.GetRoleInfo(username, realname, s0, s0, s0, s0);
840 
841   -- Set title
842   result := htf.htmlOpen ||g_newLine;
843   result := result || htf.headOpen||g_newLine;
844   if (status = 'OPEN') then
845     result := result ||
846         htf.title(wf_core.translate('WFA_DTITLE')||' '||realname)||
847                   g_newLine;
848   else
849     result := result ||
850         htf.title(wf_core.translate('WFA_CDTITLE')||' '||realname)||
851                   g_newLine;
852   end if;
853 
854   result := result || htf.headClose||g_newLine;
855 
856   -- Open frameset.
857   -- NOTE: Do NOT set the focus here, because it is not supported on
858   -- all platforms, and it is unknown at this point what browser will
859   -- be used to display the html returned to the mailer.
860   if g_wfInstall='EMBEDDED' then
861     result := result || htf.bodyOpen || g_newLine;
862     result := result || '<SCRIPT LANGUAGE="JavaScript">' || g_newLine;
863     result := result || '<!--' || g_newLine;
864 
865     url := wf_mail.Get_Ntf_Function_URL(nid => nid,
866                                         n_key => nkey,
867                                         n_sig_policy => n_sig_policy,
868                                         n_override_agent => agent);
869 
870     result := result || 'self.location = '''||url||''';' || g_newLine;
871     result := result || '//-->' || g_newLine || '</SCRIPT>' || g_newLine;
872     result := result || htf.bodyClose || g_newLine || htf.htmlClose;
873   else
874     -- While the call is within standalone, continue to
875     -- operate as before.
876     if (agent is null) then
877        result := wfa_html.detail(nid, nkey, g_webAgent);
878     else
879        result := wfa_html.detail(nid, nkey, agent);
880     end if;
881   end if;
882 
883   return(result);
884 exception
885   when others then
886     wf_core.context('Wfa_Html', 'Detail', to_char(nid), nkey, agent);
887     raise;
888 end Detail2;
889 
890 
891 -- DetailLink
892 --   display standalone detail screen text
893 -- IN
894 --   nid - notification id
895 --   nkey - notification key
896 --   agent - web agent URL root
897 -- NOTE
898 --   Detaillink called function Detail above.
899 --   This produces the version used by the mailer.
900 procedure DetailLink(
901     nid   in number,
902     nkey  in varchar2,
903     agent in varchar2)
904 is
905 begin
906   -- bug 7314545
907   null;
908 exception
909   when others then
910     wf_core.context('Wfa_Html', 'DetailLink', to_char(nid), nkey, agent);
911     raise;
912 end DetailLink;
913 
914 
915 -- SubmitForward
916 --   Submit notification forward
917 -- IN
918 --   h_nid - notification id
919 --   forwardee - new recipient field
920 --   display_forwardee - display name for the new recipient
921 --   comments - forwarding comments field
922 --   fmode - reassign mode can be:
923 --           transfer - transferring responsibility
924 --           delegate - delegate responsibility
925 --   submit - submit forward button
926 --   cancel - cancel forward button
927 --   nkey - access key for mailed html
928 procedure SubmitForward(
929   h_nid               in varchar2,
930   forwardee           in varchar2,
931   display_forwardee   in varchar2,
932   comments            in varchar2,
933   fmode               in varchar2,
934   submit              in varchar2,
935   cancel              in varchar2,
936   nkey                in varchar2)
937 is
938 begin
939   -- bug 7314545
940   null;
941 end SubmitForward;
942 
943 -- SubmitResponse
944 --   Submit notification response
945 -- IN
946 --   h_nid - notification id
947 --   h_fnames - array of field names
948 --   h_fvalues - array of field values
949 --   h_fdocnames - array of documentnames - a throwaway value from form
950 --   h_counter - number of fields passed in fnames and fvalues
951 --   submit - submit response button
952 --   forward - forward button
953 --   nkey - access key for mailed html
954 procedure SubmitResponse(
955   h_nid        in varchar2,
956   h_fnames     in Name_Array,
957   h_fvalues    in Value_Array,
958   h_fdocnames  in Value_Array,
959   h_counter    in varchar2,
960   submit       in varchar2,
961   forward      in varchar2,
962   nkey         in varchar2)
963 as
964 begin
965   -- bug 7314545
966   null;
967 end SubmitResponse;
968 
969 -- GotoURL
970 --   GotoURL let you open an url in a specify place.  This is very useful
971 --   when you need to go from a child frame to the full browser window,
972 --   for instnace.
973 --   So far, this is the only way to break away from a child frame.
974 -- IN
975 --   url - Fully qualified universal resouce location
976 --   location - Where you want to open it.  Samples of values are
977 --              _blank  - unnamed window
978 --              _self   - the current frame
979 --              _parent - the parent frame of the current one
980 --              _top    - the full Web browser window
981 --              "myWin" - name of the new window
982 --
983 procedure GotoURL(
984   url in varchar2,
985   location in varchar2,
986   attributes in varchar2
987 )
988 is
989 begin
990   -- bug 7314545
991   null;
992 end GotoURL;
993 
994 -- SubmitSelectedResponse
995 --   Submit selected notification response
996 -- IN
997 --   nids - notification ids
998 --   close - submit response button
999 --   forward - forward button
1000 --   showto - display the TO column
1001 --   nkey - access key for mailed html
1002 procedure SubmitSelectedResponse(
1003   nids         in Name_Array,
1004   close        in varchar2,
1005   forward      in varchar2,
1006   showto       in varchar2,
1007   nkey         in varchar2)
1008 as
1009 begin
1010   null;
1011 end SubmitSelectedResponse;
1012 
1013 
1014 -- ForwardNids
1015 --   Forward for each notification ids
1016 --   Forward can be Delegating or Transferring
1017 --   Delegating is for notification only.
1018 --   Transferring is reassign the whole responsibility to other
1019 -- IN
1020 --   h_nids -    hidden notification ids
1021 --   forwardee - forwardee role specified
1022 --   comments -  comments included
1023 --   fmode -     reassign mode can be:
1024 --               transfer -  transferring responsibility
1025 --               delegate -  delegate responsibility
1026 --   cancel -    cancel button
1027 procedure ForwardNids(
1028   h_nids               in Name_Array,
1029   forwardee            in varchar2,
1030   display_forwardee    in varchar2,
1031   comments             in varchar2,
1032   fmode                in varchar2,
1033   submit               in varchar2,
1034   cancel               in varchar2,
1035   nkey                 in varchar2)
1036 as
1037   username   varchar2(320);
1038   x          pls_integer;
1039   nid        pls_integer;
1040   l_forwardee varchar2(320);
1041 
1042 begin
1043   -- There is always a dummy nid passed in.  We will handle it here.
1044   -- Make sure subsequent index start at 2 not 1.
1045   if (to_number(h_nids.count) = 1) then
1046     wf_core.raise('WFNTF_NO_SELECT');
1047   end if;
1048 
1049   -- Fully resolve forwardee name
1050   l_forwardee := forwardee;
1051   wfa_html.validate_display_name (display_forwardee, l_forwardee);
1052 
1053   -- Otherwise, for each notification, delegate or transfer
1054   for x in 2..h_nids.count loop
1055     -- Authenticate user
1056     nid := to_number(h_nids(x));
1057     username := Wfa_Html.Authenticate(nid, nkey);
1058 
1059     -- Delegating to forwardee with comments
1060     if (fmode = 'DELEGATE') then
1061       if (comments is not null) then
1062 -- ### implement this in next release
1063 --      Wf_Notification.Forward(nid, upper(l_forwardee), comments, username);
1064         Wf_Notification.Forward(nid, upper(l_forwardee), comments);
1065       else
1066 -- ### implement this in next release
1067 --      Wf_Notification.Forward(nid, upper(l_forwardee), '', username);
1068         Wf_Notification.Forward(nid, upper(l_forwardee));
1069       end if;
1070     elsif (fmode = 'TRANSFER') then
1071       -- Transferring to fowardee with comments
1072 
1073       if (comments is not null) then
1074 -- ### implement this in next release
1075 --      Wf_Notification.Transfer(nid, upper(l_forwardee), comments, username);
1076         Wf_Notification.Transfer(nid, upper(l_forwardee), comments);
1077       else
1078 -- ### implement this in next release
1079 --      Wf_Notification.Transfer(nid, upper(l_forwardee), '', username);
1080         Wf_Notification.Transfer(nid, upper(l_forwardee));
1081       end if;
1082     end if;
1083   end loop;
1084 
1085   -- Back to the worklist
1086   <<worklist>>
1087   Wfa_Html.WorkList;
1088   return;
1089   exception
1090     when others then
1091       rollback;
1092       wfa_html.Error;
1093       return;
1094 end ForwardNids;
1095 
1096 /*===========================================================================
1097   PROCEDURE NAME:       create_help_function
1098 
1099   DESCRIPTION:
1100                         Create the java script function to support the Help
1101                         Icon from the header
1102 
1103    Note:  The help file parameter must include the subdirectory under
1104           /OA_DOC/lang/ and the actual file name which will either be
1105           wf or wfnew.
1106       ie  p_help_file = 'wf/notif16.htm'
1107           p_help_file = 'wfnew/wfnew48.htm'
1108 ============================================================================*/
1109 procedure create_help_function (
1110 
1111  p_help_file IN VARCHAR2
1112 
1113 ) IS
1114 
1115 install_type VARCHAR2(80);
1116 l_help_target VARCHAR2(240) := NULL;
1117 l_lang       VARCHAR2(2000);
1118 help_prefix  VARCHAR2(2000);
1119 
1120 BEGIN
1121 
1122   BEGIN
1123 
1124   /*
1125   ** Get the language environment variable
1126   ** for this user.
1127   */
1128   SELECT USERENV('LANG')
1129   INTO l_lang
1130   FROM DUAL;
1131 
1132   EXCEPTION
1133   WHEN OTHERS THEN
1134      l_lang := 'US';
1135   END;
1136 
1137   /*
1138   ** Check the installation type.  If it is workflow standalone
1139   ** then use the file prefix method of getting to the help
1140   ** content.  Otherwise use the fnd function method to get and
1141   ** display the help content.
1142   */
1143   install_type := wf_core.translate('WF_INSTALL');
1144 
1145   if (install_type = 'STANDALONE') THEN
1146 
1147      help_prefix := '/OA_DOC/';
1148 
1149      htp.p('<!-- Copyright ' || '&' || '#169; 1997 Oracle Corporation, All rights reserved. -->');
1150      htp.p('<SCRIPT LANGUAGE="JavaScript">
1151      <!-- hide the script''s contents from feeble browsers');
1152 
1153      htp.p('function help_window(){
1154         help_win = window.open('||''''||help_prefix||
1155                 'US/' || p_help_file ||''''||
1156             ', "help_win","resizable=yes,scrollbars=yes,toolbar=yes,width=600,height=500");
1157         help_win = window.open('||''''||help_prefix||
1158                'US/' || p_help_file ||''''||
1159             ', "help_win","resizable=yes,scrollbars=yes,toolbar=yes,width=600,height=500")
1160 }
1161 ');
1162 
1163      htp.p('<!-- done hiding from old browsers --></SCRIPT>');
1164 
1165      htp.p('<NOSCRIPT>');
1166      htp.p(WF_CORE.Translate('WFA_NOSCRIPT'));
1167      htp.p('</NOSCRIPT>');
1168 
1169   else
1170 
1171      /*
1172      ** If you're going against apps then strip out everything
1173      ** except the target name
1174      */
1175      IF (INSTR(p_help_file, '?') > 0) THEN
1176 
1177          l_help_target := substrb(p_help_file, INSTR(p_help_file, '?') + 1);
1178 
1179      ELSE
1180 
1181          l_help_target := p_help_file;
1182 
1183      END IF;
1184 
1185      wfa_sec.create_help_syntax (l_help_target, l_lang);
1186 
1187   end if;
1188 
1189 exception
1190   when others then
1191     Wf_Core.Context('wfa_html', 'create_help_function',
1192        p_help_file);
1193     wfa_html.Error;
1194 
1195 END create_help_function;
1196 
1197 /*===========================================================================
1198   FUNCTION NAME:        conv_special_url_chars
1199 
1200   DESCRIPTION:
1201                         Convert all of the ASCII special characters that are
1202                         disallowed as a part of a URL.  The encoding requires
1203                         that we convert the special characters to HEX for
1204                         any characters in a URL string that is built
1205                         manually outside a form get/post.
1206                         This API now also converts multibyte characters
1207                         into their HEX equivalent.
1208 
1209   NOTE:                 This api allows double-encoding.
1210 
1211 ============================================================================*/
1212 FUNCTION conv_special_url_chars (p_url_token IN VARCHAR2) RETURN VARCHAR2
1213 IS
1214  c_unreserved constant varchar2(72) :=
1215    '-_.!*''()~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
1216  c_reserved    constant varchar2(72) := '%">^{}<[]`|/#?&=$:;+';
1217  l_tmp         varchar2(32767) := '';
1218  l_onechar     varchar2(4);
1219  l_byte_len    integer;
1220  i             integer;
1221  l_str         varchar2(48);
1222 
1223 BEGIN
1224  if p_url_token is NULL then
1225     return NULL;
1226  end if;
1227  for i in 1 .. length(p_url_token) loop
1228    l_onechar := substr(p_url_token,i,1);
1229    --Extracting out each character to be replaced.
1230    if instr(c_unreserved, l_onechar) > 0 then
1231      --Check if  it is part of the ASCII unreserved
1232      --excluded from encoding just append to the URL
1233      --string
1234      l_tmp := l_tmp || l_onechar;
1235 
1236    elsif l_onechar = ' ' then
1237      --Space encoded as '%20'
1238      l_tmp := l_tmp || '%20';
1239 
1240    elsif instr(c_reserved,l_onechar) >0 then
1241      --If it is any of the reserved characters in ascii
1242      --replace with equivalent HEX
1243      l_onechar := REPLACE(
1244                   REPLACE(
1245                   REPLACE(
1246                   REPLACE(
1247                   REPLACE(
1248                   REPLACE(
1249                   REPLACE(
1250                   REPLACE(
1251                   REPLACE(
1252                   REPLACE(
1253                   REPLACE(
1254                   REPLACE(
1255                   REPLACE(
1256                   REPLACE(
1257                   REPLACE(
1258                   REPLACE(
1259                   REPLACE(
1260                   REPLACE(
1261                   REPLACE(
1262                   REPLACE(
1263                   REPLACE(
1264                   REPLACE(l_onechar,
1265                   '%','%25'),
1266                   ' ','%20'),
1267                   '"','%22'),
1268                   '>','%3E'),
1269                   '^','%5E'),
1270                   '{','%7B'),
1271                   '}','%7D'),
1272                   '<','%3C'),
1273                   '[','%5B'),
1274                   ']','%5D'),
1275                   '`','%60'),
1276                   '|','%7C'),
1277                   '/','%2F'),
1278                   '#','%23'),
1279                   '?','%3F'),
1280                   '&','%26'),
1281                   '=','%3D'),
1282                   '$','%24'),
1283                   ':','%3A'),
1284                   ';','%3B'),
1285                   '+','%2B'),
1286                   '''','%27');
1287      l_tmp := l_tmp || l_onechar;
1288    else
1289      --For multibyte
1290      -- 1. Obtain length for each character
1291      -- 2. ascii(l_char)decimal representation in the database
1292      --    character set
1293      -- 3. Change it to the format model :
1294      --    to_char(ascii(l_onechar),'FM0X')
1295      -- 4. Add to the already encoded string.
1296      --    characters
1297      l_byte_len := lengthb(l_onechar);
1298      if l_byte_len = 1 then
1299        l_tmp := l_tmp || '%' ||
1300         substr(to_char(ascii(l_onechar),'FM0X'),1,2);
1301      elsif l_byte_len = 2 then
1302        l_str := to_char(ascii(l_onechar),'FM0XXX');
1303        l_tmp := l_tmp
1304             || '%' || substr(l_str,1,2)
1305             || '%' || substr(l_str,3,2);
1306      elsif l_byte_len = 3 then
1307        l_str := to_char(ascii(l_onechar),'FM0XXXXX');
1308        l_tmp := l_tmp
1309                 || '%' || substr(l_str,1,2)
1310                 || '%' || substr(l_str,3,2)
1311                 || '%' || substr(l_str,5,2);
1312      elsif l_byte_len = 4 then
1313        l_str := to_char(ascii(l_onechar),'FM0XXXXXXX');
1314        l_tmp := l_tmp
1315                 || '%' || substr(l_str,1,2)
1316                 || '%' || substr(l_str,3,2)
1317                 || '%' || substr(l_str,5,2)
1318                 || '%' || substr(l_str,7,2);
1319      else            -- maximum precision
1320        wf_core.raise('WFENG_PRECESSION_EXCEED');
1321      end if;
1322    end if;
1323  end loop;
1324  return l_tmp;
1325 exception
1326   when others then
1327     Wf_Core.Context('wfa_html', 'conv_special_url_chars',
1328        p_url_token);
1329     wfa_html.Error;
1330 END conv_special_url_chars;
1331 
1332 /*===========================================================================
1333   FUNCTION NAME:        encode_url (PRIVATE)
1334 
1335   DESCRIPTION:
1336                         Convert all of the ASCII special characters that are
1337                         disallowed as a part of a URL.  The encoding requires
1338                         that we convert the special characters to HEX for
1339                         any characters in a URL string that is built
1340                         manually outside a form get/post.
1341                         This API now also converts multibyte characters
1342                         into their HEX equivalent.
1343 
1344                         URL encoding was documented in RFC 1738.
1345                         We have put some "unsafe" characters in the encode
1346                         list for purpose of encoding them.
1347                         We took "~" out from this list, because some downstream
1348                         consumer (ICX) was looking for "~".
1349 
1350   NOTE:                 This private api does not allow double-encoding.
1351 ============================================================================*/
1352 FUNCTION encode_url (p_url_token IN VARCHAR2) RETURN VARCHAR2
1353 IS
1354  c_noencode    constant varchar2(72) :=
1355    '-_.!*''()~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
1356  c_encode      constant varchar2(72) := '">^{}<[]`|/#?&=$:;+';
1357  c_hex         constant varchar2(72) := 'ABCDEFabcdef0123456789';
1358  l_tmp         varchar2(32767);
1359  l_onechar     varchar2(4);
1360  l_byte_len    integer;
1361  i             integer;
1362  l_str         varchar2(48);
1363 
1364 BEGIN
1365  if p_url_token is NULL then
1366     return NULL;
1367  end if;
1368  for i in 1 .. length(p_url_token) loop
1369    l_onechar := substr(p_url_token,i,1);
1370    --Extracting out each character to be replaced.
1371    if instr(c_noencode, l_onechar) > 0 then
1372      --If it is part of the ASCII excluded from encoding,
1373      --just append to the URL string
1374      l_tmp := l_tmp || l_onechar;
1375 
1376    elsif l_onechar = ' ' then
1377      --Space encoded as '%20'
1378      l_tmp := l_tmp || '%20';
1379 
1380    elsif l_onechar = '%' then
1381      --Do not reencode if it has already been encoded
1382      --Check next two characters to see if they belong to hex number
1383      if (instr(c_hex, substr(p_url_token,i+1,1)) > 0 and
1384          instr(c_hex, substr(p_url_token,i+2,1)) > 0) then
1385        l_tmp := l_tmp || '%';
1386      else
1387        l_tmp := l_tmp || '%25';
1388      end if;
1389 
1390    elsif instr(c_encode,l_onechar) >0 then
1391      --If it is any of the to be encoded characters in ascii
1392      --replace with equivalent HEX
1393      l_onechar := REPLACE(
1394                   REPLACE(
1395                   REPLACE(
1396                   REPLACE(
1397                   REPLACE(
1398                   REPLACE(
1399                   REPLACE(
1400                   REPLACE(
1401                   REPLACE(
1402                   REPLACE(
1403                   REPLACE(
1404                   REPLACE(
1405                   REPLACE(
1406                   REPLACE(
1407                   REPLACE(
1408                   REPLACE(
1409                   REPLACE(
1410                   REPLACE(
1411                   REPLACE(
1412                   REPLACE(l_onechar,
1413                   '"','%22'),
1414                   '>','%3E'),
1415                   '^','%5E'),
1416                   '{','%7B'),
1417                   '}','%7D'),
1418                   '<','%3C'),
1419                   '[','%5B'),
1420                   ']','%5D'),
1421                   '`','%60'),
1422                   '|','%7C'),
1423                   '/','%2F'),
1424                   '#','%23'),
1425                   '?','%3F'),
1426                   '&','%26'),
1427                   '=','%3D'),
1428                   '$','%24'),
1429                   ':','%3A'),
1430                   ';','%3B'),
1431                   '+','%2B'),
1432                   '''','%27');
1433      l_tmp := l_tmp || l_onechar;
1434    else
1435      --For multibyte
1436      -- 1. Obtain length for each character
1437      -- 2. ascii(l_char)decimal representation in the database
1438      --    character set
1439      -- 3. Change it to the format model :
1440      --    to_char(ascii(l_onechar),'FM0X')
1441      -- 4. Add to the already encoded string.
1442      --    characters
1443      l_byte_len := lengthb(l_onechar);
1444      if l_byte_len = 1 then
1445        l_tmp := l_tmp || '%' ||
1446         substr(to_char(ascii(l_onechar),'FM0X'),1,2);
1447      elsif l_byte_len = 2 then
1448        l_str := to_char(ascii(l_onechar),'FM0XXX');
1449        l_tmp := l_tmp
1450             || '%' || substr(l_str,1,2)
1451             || '%' || substr(l_str,3,2);
1452      elsif l_byte_len = 3 then
1453        l_str := to_char(ascii(l_onechar),'FM0XXXXX');
1454        l_tmp := l_tmp
1455                 || '%' || substr(l_str,1,2)
1456                 || '%' || substr(l_str,3,2)
1457                 || '%' || substr(l_str,5,2);
1458      elsif l_byte_len = 4 then
1459        l_str := to_char(ascii(l_onechar),'FM0XXXXXXX');
1460        l_tmp := l_tmp
1461                 || '%' || substr(l_str,1,2)
1462                 || '%' || substr(l_str,3,2)
1463                 || '%' || substr(l_str,5,2)
1464                 || '%' || substr(l_str,7,2);
1465      else            -- maximum precision
1466        wf_core.raise('WFENG_PRECESSION_EXCEED');
1467      end if;
1468    end if;
1469  end loop;
1470  return l_tmp;
1471 exception
1472   when others then
1473     Wf_Core.Context('wfa_html', 'encode_url',
1474        p_url_token);
1475     wfa_html.Error;
1476 END encode_url;
1477 
1478 --
1479 -- User_LOV
1480 --   Create the data for the User List of Values
1481 --   NOTE: This is not used by APPS.  Otherwise, we will have performance
1482 --         problem with this query against wf_roles.
1483 --
1484 procedure User_LOV (p_titles_only     IN VARCHAR2,
1485                     p_find_criteria IN VARCHAR2)
1486 
1487 IS
1488 BEGIN
1489   -- bug 7314545
1490   null;
1491 end User_Lov;
1492 
1493 procedure logout is
1494 begin
1495   -- bug 7314545
1496   null;
1497 end logout;
1498 
1499 procedure Home(message in varchar2)
1500 is
1501 begin
1502   -- bug 7314545
1503   null;
1504 end home;
1505 
1506 procedure Header
1507 is
1508 begin
1509   -- bug 7314545
1510   null;
1511 end;
1512 
1513 
1514 procedure home_float
1515 is
1516 begin
1517   -- bug 7314545
1518   null;
1519 end home_float;
1520 
1521 -- Homemenu
1522 -- Prints the menu for the home page.
1523 -- May also be called direct to print a regular page.
1524 
1525 procedure Homemenu(message in varchar2,
1526                origin  in varchar2)
1527 is
1528 begin
1529   -- bug 7314545
1530   null;
1531 end Homemenu;
1532 
1533 procedure create_reg_button (
1534 when_pressed_url  IN VARCHAR2,
1535 onmouseover       IN VARCHAR2,
1536 icon_top          IN VARCHAR2,
1537 icon_name         IN VARCHAR2,
1538 show_text         IN VARCHAR2)
1539 IS
1540 BEGIN
1541   -- bug 7314545
1542   null;
1543 end create_reg_button;
1544 
1545 -- show_plsql_doc
1546 --   Show the content of a plsql document in a browser window
1547 --   Called from the related documents function
1548 
1549 procedure show_plsql_doc (
1550   nid in number,
1551   aname in varchar2,
1552   nkey in varchar2)
1553 is
1554 
1555 username varchar2(320);
1556 
1557 clob_loc   clob;
1558 blob_loc   blob;
1559 clob_id    number;
1560 clob_chunk number := 0;
1561 doctext    varchar2(32000);
1562 end_of_text boolean :=FALSE;
1563 attr_name varchar2(30);
1564 
1565 slash           pls_integer;
1566 wfsession       varchar2(240);
1567 
1568 doctype varchar2(1000);
1569 lobsize number;
1570 amount number;
1571 
1572 l_enpos    pls_integer;
1573 l_copos    pls_integer;
1574 
1575 l_encoding varchar2(100);
1576 l_filename  varchar2(255);
1577 l_extension varchar2(50);
1578 l_mime_type varchar2(255);
1579 
1580 begin
1581 
1582   -- Verify if user is admin or can access this notification
1583   username := wfa_html.authenticate(nid,nkey);
1584 
1585   username := upper(username);
1586 
1587   -- note that GetAttrDoc will not translate for PLSQLCLOB
1588   doctext := wf_notification.getattrdoc(nid, aname,wf_notification.doc_html);
1589 
1590   -- if the attribute wasn't translated then try to translate for plsqlclobs.
1591   if doctext = '&'||aname then
1592     dbms_lob.createTemporary(clob_loc, false, dbms_lob.call);
1593     Wf_Notification.GetAttrCLOB(nid, aname, wf_notification.doc_html,
1594                                 clob_loc, doctype, attr_name);
1595     if (doctype is not null) then
1596       Wf_Mail_Util.ParseContentType(doctype, l_mime_type, l_filename, l_extension, l_encoding);
1597     end if;
1598     -- We have the document. Now determine the output method. HTML documents can be output as
1599     -- they are. Binary documents can only be downloaded
1600     if l_mime_type in (wf_notification.doc_text, wf_notification.doc_html) then
1601        -- HTML or text document.
1602        htp.htmlOpen;
1603        htp.headOpen;
1604        htp.p('<BASE TARGET="_top">');
1605        htp.title(wf_core.translate('WFITD_ATTR_TYPE_DOCUMENT'));
1606        wfa_html.create_help_function('wfnew/wfnew52.htm#nrr');
1607        htp.headClose;
1608        wfa_sec.Header(FALSE, '',wf_core.translate('WFITD_ATTR_TYPE_DOCUMENT'),
1609                       TRUE);
1610        htp.br;
1611 
1612        lobsize := dbms_lob.getlength(clob_loc);
1613        amount := 32000;
1614        wf_notification.clob_chunk := 0;
1615        while not (end_of_text) loop
1616           wf_notification.readattrclob(nid, aname, doctext, end_of_text);
1617           htp.prn(doctext);
1618        end loop;
1619        wfa_sec.Footer;
1620        htp.htmlClose;
1621     elsif attr_name is not null then
1622        -- BINARY Document
1623        if (l_encoding is not null) then
1624           -- Decode base64 encoded content
1625           if (upper(trim(l_encoding)) = 'BASE64') then
1626              dbms_lob.createTemporary(blob_loc, FALSE, dbms_lob.call);
1627 
1628              wf_mail_util.decodeBLOB(clob_loc, blob_loc);
1629              -- owa_util.mime_header(doctype, FALSE);
1630              -- Write appropriate headers before downloading the document
1631              if (l_filename is null or l_filename = '') then
1632                l_filename := aname || '.' || l_extension;
1633              end if;
1634              htp.p('Content-type: '||l_mime_type);
1635              htp.p('Content-Disposition: attachment; filename="'||l_filename||'"');
1636              htp.p('Content-length: ' || dbms_lob.getlength(blob_loc));
1637              htp.p('');
1638              -- owa_util.http_header_close;
1639 
1640              wpg_docload.download_file(blob_loc);
1641              dbms_lob.freeTemporary(blob_loc);
1642           end if;
1643        else
1644           -- This provides limited binary document support. It assumes that the document in
1645           -- stored as raw in varchar.
1646           owa_util.mime_header(l_mime_type, TRUE);
1647           lobsize := dbms_lob.getlength(clob_loc);
1648           amount := 32000;
1649           wf_notification.clob_chunk := 0;
1650           while not (end_of_text) loop
1651              wf_notification.readattrclob(nid, aname, doctext, end_of_text);
1652              htp.p(doctext);
1653           end loop;
1654        end if;
1655     else
1656        -- attr_name is null try for a PLSQLBLOB document
1657        dbms_lob.createTemporary(blob_loc, false, dbms_lob.call);
1658        Wf_Notification.GetAttrBLOB(nid, aname, wf_notification.doc_html,
1659                                    blob_loc, doctype, attr_name);
1660        if (doctype is not null) then
1661          Wf_Mail_Util.ParseContentType(doctype, l_mime_type, l_filename, l_extension, l_encoding);
1662        end if;
1663        if (l_filename is null or l_filename = '') then
1664          l_filename := aname || '.' || l_extension;
1665        end if;
1666        -- owa_util.mime_header(doctype, FALSE);
1667        htp.p('Content-type: '||l_mime_type);
1668        htp.p('Content-Disposition: attachment; filename="'||l_filename||'"');
1669        htp.p('Content-length: ' || dbms_lob.getlength(blob_loc));
1670        htp.p('');
1671        -- owa_util.http_header_close;
1672 
1673        wpg_docload.download_file(blob_loc);
1674        dbms_lob.freeTemporary(blob_loc);
1675     end if;
1676 
1677   else
1678      -- Set page title
1679      htp.htmlOpen;
1680      htp.headOpen;
1681      htp.title(wf_core.translate('WFITD_ATTR_TYPE_DOCUMENT'));
1682      wfa_html.create_help_function('wfnew/wfnew52.htm#nrr');
1683      htp.headClose;
1684      wfa_sec.Header(FALSE, '',wf_core.translate('WFITD_ATTR_TYPE_DOCUMENT'),
1685                     TRUE);
1686      htp.br;
1687 
1688      htp.p (doctext);
1689 
1690      wfa_sec.Footer;
1691      htp.htmlClose;
1692   end if;
1693 
1694 exception
1695   when others then
1696     wf_core.context('Wfa_Html','show_plsql_doc',wf_core.substitutespecialchars(nid),
1697                    wf_core.substitutespecialchars(aname));
1698     wfa_html.Error;
1699 end show_plsql_doc;
1700 
1701 -- base_url
1702 -- Get the base url for the current browser where you have launched the
1703 -- login for Workflow
1704 function base_url  (get_from_resources BOOLEAN)
1705 return varchar2 IS
1706 
1707 l_base_url   VARCHAR2(2000) := NULL;
1708 
1709 BEGIN
1710 
1711     BEGIN
1712 
1713     IF (get_from_resources = FALSE) THEN
1714 
1715        -- Need to strip off trailing / to match wf_web_agent format
1716        l_base_url  := SUBSTR(RTRIM(owa_util.get_owa_service_path), 1,
1717                           LENGTH(RTRIM(owa_util.get_owa_service_path)) - 1);
1718 
1719     ELSE
1720 
1721        l_base_url := wf_core.translate ('WF_WEB_AGENT');
1722 
1723     END IF;
1724 
1725     EXCEPTION
1726     WHEN OTHERS THEN
1727 
1728        l_base_url := wf_core.translate ('WF_WEB_AGENT');
1729 
1730     END;
1731 
1732     return (l_base_url);
1733 
1734 exception
1735   when others then
1736     wf_core.context('Wfa_Html','base_url');
1737     wfa_html.Error;
1738 end base_url;
1739 
1740 --
1741 -- wf_user_val
1742 --   Create the lov content for our user lov.  This function
1743 --   is called by the generic lov function
1744 -- IN
1745 -- RETURNS
1746 --
1747 procedure  wf_user_val (
1748 p_mode           in varchar2,
1749 p_lov_name       in varchar2,
1750 p_start_row      in number,
1751 p_max_rows       in number,
1752 p_hidden_value   in out nocopy varchar2,
1753 p_display_value  in out nocopy varchar2,
1754 p_result         out nocopy number)
1755 
1756 
1757 IS
1758 
1759 CURSOR c_user_lov (c_find_criteria IN VARCHAR2) IS
1760 SELECT
1761  name,
1762  display_name
1763 FROM   wf_role_lov_vl
1764 where  status <> 'INACTIVE'
1765 and   (UPPER(display_name) LIKE UPPER(c_find_criteria)||'%')
1766 order by display_name;
1767 
1768 -- Added additional where condition "status <> 'INACTIVE' so only ACTIVE
1769 -- roles display
1770 
1771 -- CURSOR c_user_display_value (c_name IN VARCHAR2) IS
1772 -- select name, display_name
1773 -- from   wf_roles
1774 -- where  name = c_name;
1775 
1776 ii           NUMBER := 0;
1777 nn           NUMBER := 0;
1778 l_total_rows NUMBER := 0;
1779 l_id         NUMBER;
1780 l_name       VARCHAR2 (320);  -- enlarged from 30 to match db definition
1781 l_display_name VARCHAR2 (360); -- enlarged from 80 to match db definition
1782 l_result     NUMBER := 1;  -- This is the return value for each mode
1783 
1784 colon        NUMBER;
1785 
1786 role_info_tbl wf_directory.wf_local_roles_tbl_type;
1787 
1788 BEGIN
1789 
1790 if (p_mode = 'LOV') then
1791 
1792    /*
1793    ** Need to get a count on the number of rows that will meet the
1794    ** criteria before actually executing the fetch to show the user
1795    ** how many matches are available.
1796    */
1797    select count(*)
1798    into   l_total_rows
1799    FROM   wf_role_lov_vl
1800    where  status <> 'INACTIVE'
1801    and   (UPPER(display_name) LIKE UPPER(p_display_value)||'%');
1802 
1803    wf_lov.g_define_rec.total_rows := l_total_rows;
1804 
1805    wf_lov.g_define_rec.add_attr1_title := wf_core.translate ('WFITD_INTERNAL_NAME');
1806 
1807    open c_user_lov (p_display_value);
1808 
1809    LOOP
1810 
1811      FETCH c_user_lov INTO l_name, l_display_name;
1812 
1813      EXIT WHEN c_user_lov%NOTFOUND OR nn >= p_max_rows;
1814 
1815      ii := ii + 1;
1816 
1817      IF (ii >= p_start_row) THEN
1818 
1819         nn := nn + 1;
1820 
1821         wf_lov.g_value_tbl(nn).hidden_key      := l_name;
1822         wf_lov.g_value_tbl(nn).display_value   := l_display_name;
1823         wf_lov.g_value_tbl(nn).add_attr1_value := l_name;
1824 
1825      END IF;
1826 
1827    END LOOP;
1828 
1829    l_result := 1;
1830 
1831 elsif (p_mode = 'GET_DISPLAY_VAL') THEN
1832 
1833    Wf_Directory.GetRoleInfo2(p_hidden_value,role_info_tbl);
1834    l_name         := role_info_tbl(1).name;
1835    l_display_name := role_info_tbl(1).display_name;
1836    p_display_value:= l_name;
1837 
1838    l_result := 1;
1839 
1840 elsif (p_mode = 'VALIDATE') THEN
1841 
1842    /*
1843    ** If mode = VALIDATE then see how many rows match the criteria
1844    ** If its 0 then thats not good.  Raise an error and tell them to use LOV
1845    ** If its 1 then thats great.
1846    ** If its more than 1 then check to see if they used the LOV to select
1847    ** the value
1848    */
1849    open c_user_lov (p_display_value);
1850 
1851    LOOP
1852 
1853      FETCH c_user_lov INTO l_name, l_display_name;
1854 
1855      EXIT WHEN c_user_lov%NOTFOUND OR ii = 2;
1856 
1857      ii := ii + 1;
1858 
1859      p_hidden_value := l_name;
1860 
1861    END LOOP;
1862 
1863    /*
1864    ** If ii=0 then no rows were found and you have an error in the value
1865    **     entered so present a no rows found and use the lov icon to select
1866    **     value
1867    ** If ii=1 then one row is found then you've got the right value
1868    ** If ii=2 then more than one row was found so check to see if the display
1869    ** value taht was selected is not unique in the LOV (Person Name) and
1870    ** that the LOV was used so the Hidden value has been set to a unique
1871    ** value.  If it comes up with more than 1 in this case then present
1872    ** the please use lov icon to select value.
1873    */
1874    if (ii = 2) then
1875 
1876      -- copy logic from wf_directory.getroleinfo2
1877      colon := instr(p_display_value,':');
1878      if (colon = 0) then
1879        select count(*)
1880          into ii
1881          from WF_ROLES
1882         where NAME = p_display_value
1883           and ORIG_SYSTEM not in ('HZ_PARTY','POS','ENG_LIST','AMV_CHN',
1884                                   'HZ_GROUP','CUST_CONT');
1885      else
1886        select count(*)
1887          into ii
1888          from WF_ROLES
1889         where NAME = p_display_value
1890           and ORIG_SYSTEM    = substr(p_display_value, 1, colon-1)
1891           and ORIG_SYSTEM_ID = substr(p_display_value, colon+1);
1892      end if;
1893 
1894    END IF;
1895 
1896    l_result := ii;
1897 
1898 end if;
1899 
1900 p_result := l_result;
1901 
1902 exception
1903   when others then
1904     rollback;
1905     wf_core.context('Wfa_Html', 'wf_user_val');
1906     raise;
1907 end wf_user_val;
1908 
1909 
1910 function replace_onMouseOver_quotes(p_string in varchar2) return varchar2 is
1911 
1912 temp_string varchar2(2000);
1913 c_browser varchar2(400) := owa_util.get_cgi_env('HTTP_USER_AGENT');
1914 
1915 begin
1916 
1917 -- replace single quotes
1918 temp_string := replace(p_string,'''','\''');
1919 
1920 -- replace double quotes
1921 if (instr(c_browser, 'MSIE') <> 0) then
1922     temp_string := replace(temp_string,'"','\''');
1923 else
1924     temp_string := replace(temp_string,'"','`"');
1925 end if;
1926 
1927 -- check for double escapes
1928 temp_string := replace(temp_string,'\\','\');
1929 
1930 return temp_string;
1931 
1932 end replace_onMouseOver_quotes;
1933 
1934 procedure validate_display_name (
1935 p_display_name in varchar2,
1936 p_user_name    in out nocopy varchar2) IS
1937 
1938 l_colon         NUMBER := 0;
1939 l_names_count   NUMBER := 0;
1940 l_name          VARCHAR2(320);
1941 l_upper_name    VARCHAR2(360);
1942 l_orig_system_id NUMBER;
1943 l_get_role      BOOLEAN := TRUE;
1944 
1945 role_info_tbl wf_directory.wf_local_roles_tbl_type;
1946 
1947 BEGIN
1948 
1949    /*
1950    ** Make sure to blank out the internal name if the user originally
1951    ** used the LOV to select the name and then blanked out the display
1952    ** name then make sure here to blank out the insternal name and return
1953    */
1954    if (p_display_name is null) then
1955 
1956       p_user_name := NULL;
1957       return;
1958 
1959    end if;
1960 
1961    /*
1962    ** Bug# 2236250 validating the display name to contain a valid number
1963    ** after the colon to be used as a internal name for the role
1964    */
1965    l_colon := instr(p_display_name, ':');
1966    if (l_colon > 0) then
1967       begin
1968          l_orig_system_id := to_number(substr(p_display_name, l_colon+1));
1969       exception
1970          when invalid_number then
1971              l_get_role := FALSE;
1972          when others then
1973              raise;
1974       end;
1975       l_colon := 0;
1976    end if;
1977 
1978    /*
1979    ** First look first for internal name to see if you find a match.  If
1980    ** there are duplicate internal names that match the criteria then
1981    ** there is a problem with directory services but what can you do.  Go
1982    ** ahead and pick the first name so you return something
1983    **
1984    ** Bug# 2236250 calling Wf_Directory.GetRoleInfo2 only if the value
1985    ** after ':' is numeric.
1986    */
1987    if (l_get_role) then
1988       l_upper_name := upper(p_display_name);
1989       Wf_Directory.GetRoleInfo2(l_upper_name,role_info_tbl);
1990       l_name := role_info_tbl(1).name;
1991    end if;
1992 
1993    /*
1994    ** If you found a match on internal name then set the p_user_name
1995    ** accordingly.
1996    */
1997    if (l_name IS NOT NULL) then
1998 
1999       p_user_name := l_name;
2000 
2001    /*
2002    ** If there was no match on internal name then check for a display
2003    ** name
2004    */
2005    else
2006 
2007       /*
2008       ** Check out how many names match the display name
2009       */
2010       select count(1)
2011       into   l_names_count
2012       from   wf_role_lov_vl
2013       where  display_name = p_display_name;
2014 
2015       /*
2016       ** If there are no matches for the display name then raise an error
2017       */
2018       if (l_names_count = 0) then
2019 
2020          -- Not displayed or internal role name, error
2021          wf_core.token('ROLE', p_display_name);
2022          wf_core.raise('WFNTF_ROLE');
2023 
2024       /*
2025       ** If there is just one match then get the internal name
2026       ** and assign it.
2027       */
2028       elsif (l_names_count = 1) then
2029 
2030          select name
2031          into   l_name
2032          from   wf_role_lov_vl
2033          where  display_name = p_display_name;
2034 
2035          p_user_name  := l_name;
2036 
2037       /*
2038       ** If there is more than one match then see if the user
2039       ** used the lov to select the name in which case the combination
2040       ** of the display name and the user name should be unique
2041       */
2042       else
2043 
2044         -- copy logic from wf_directory.getroleinfo2
2045         l_colon := instr(p_user_name,':');
2046 
2047         if (l_colon = 0) then
2048           select count(1)
2049             into l_names_count
2050             from WF_ROLES
2051            where NAME = p_user_name
2052              and ORIG_SYSTEM not in ('HZ_PARTY','POS','ENG_LIST','AMV_CHN',
2053                                      'HZ_GROUP','CUST_CONT')
2054              and DISPLAY_NAME = p_display_name;
2055         else
2056         /*
2057         ** Bug# 2236250 validate if the value after ':' is number
2058         ** before using it in the query
2059         */
2060           begin
2061              l_orig_system_id := to_number(substr(p_user_name, l_colon+1));
2062           exception
2063              when invalid_number then
2064                 wf_core.raise('WFNTF_ORIGSYSTEMID');
2065              when others then
2066                 raise;
2067           end;
2068           select count(1)
2069             into l_names_count
2070             from WF_ROLES
2071            where NAME = p_user_name
2072              and ORIG_SYSTEM    = substr(p_user_name, 1, l_colon-1)
2073              and ORIG_SYSTEM_ID = l_orig_system_id
2074              and DISPLAY_NAME = p_display_name;
2075         end if;
2076 
2077         if (l_names_count <> 1) then
2078           wf_core.token('ROLE', p_display_name);
2079           wf_core.raise('WFNTF_UNIQUE_ROLE');
2080         end if;
2081 
2082       end if;
2083 
2084    end if;
2085 
2086 exception
2087   when others then
2088     wf_core.context('Wfa_Html', 'validate_display_name', p_display_name,
2089       p_user_name);
2090     raise;
2091 end validate_display_name;
2092 
2093 -- LongDesc
2094 --  Displays an html page with the token message.  This is called from
2095 --  frames for the LONGDESC attribute.
2096 procedure LongDesc (p_token       in varchar2)
2097 as
2098 BEGIN
2099     htp.htmlOpen;
2100     htp.headOpen;
2101     htp.title(wf_core.translate('LONG_DESC'));
2102     htp.headClose;
2103 
2104       begin
2105         wfa_sec.Header(background_only=>TRUE);
2106       exception
2107         when others then
2108           htp.bodyOpen;
2109       end;
2110 
2111     htp.p(WF_CORE.Translate(UPPER(p_token)));
2112 
2113     wfa_sec.Footer;
2114     htp.htmlClose;
2115 
2116 END LongDesc;
2117 
2118 end WFA_HTML;