1 package body WF_MAIL as
2 /* $Header: wfmlrb.pls 120.43.12020000.7 2013/03/24 12:35:24 skandepu ship $ */
3
4
5 --
6 -- Constants
7 --
8
9 chr_indent varchar2(8) := ' '; -- 8 spaces (virtual tab)
10 chr_indentsize pls_integer := 8; -- Number of char spaces in a tab
11 -- 3432204 The LOBLineBreak algorithm as been altered. The line wrapping
12 -- has been increased to allow for the horizontal line in text/plain
13 -- notifications
14 -- wf_linelen pls_integer := 72; -- Max line length for word wrap
15 wf_linelen pls_integer := 73; -- Max line length for word wrap
16
17 FND_WFNTF_DETAILS NUMBER := 1014409;
18
19 g_timezoneName varchar2(80) := '';
20
21 g_direct_response boolean := FALSE;
22 g_send_accesskey boolean := TRUE;
23 g_autoclose_fyi boolean := TRUE;
24 g_template varchar2(30); -- internal name for a message
25 g_fyi boolean := FALSE;
26
27 -- CLOB Processing Variables
28 --g_text_message CLOB; -- LOB locator for text body message
29 --g_html_message CLOB; -- LOB locator for HTML body message
30 --g_attachment CLOB; -- LOB locator for attachments
31
32
33
34 -- Indexes for CLOB from the pool
35 g_LOBTable wf_temp_lob.wf_temp_lob_table_type;
36
37 g_text_messageIdx pls_integer;
38 g_html_messageIdx pls_integer;
39 g_attachmentIdx pls_integer;
40
41 g_text_chunk pls_integer;
42 g_html_chunk pls_integer;
43
44 -- More Info feature
45 g_moreinfo varchar2(3) := NULL;
46 g_to_role varchar2(320);
47
48 -- GLOBAL Package level varaibles that contain static data.
49 g_ntfHistory varchar2(30);
50 g_ntfActionHistory varchar2(50);
51 g_tab varchar2(1) := wf_core.tab;
52 g_moreInfoAPrompt varchar2(200);
53 g_moreInfoAnswer varchar2(200);
54 g_moreInfoQPrompt varchar2(200);
55 g_moreInfoSubject varchar2(200);
56 g_moreInfoSubmit varchar2(200);
57 g_moreInfoQuestion varchar2(200);
58 g_moreInfoFrom varchar2(200);
59 g_moreInfoRequested varchar2(200);
60 g_moreInfoRequestee varchar2(4000);
61 g_webAgent varchar2(200) := wf_core.translate('WF_WEB_AGENT');
62 g_wfmonId varchar2(60);
63 g_to varchar2(60);
64 g_from varchar2(60);
65 g_beginDate varchar2(100);
66 g_dueDate2 varchar2(60);
67 g_notificationId varchar2(60);
68 g_priority varchar2(60);
69 g_dueDate varchar2(60);
70 g_invalidRemarks varchar2(400);
71 g_forExample varchar2(200);
72 g_soOn varchar2(60);
73 g_none varchar2(200);
74 g_truncate varchar2(200);
75 g_noResult varchar2(200);
76 g_install varchar2(60) := wf_core.translate('WF_INSTALL');
77 g_ntfDocText varchar2(30) := wf_notification.doc_text;
78 g_ntfDocHtml varchar2(30) := wf_notification.doc_html;
79 g_Id varchar2(30);
80 g_isFwkNtf boolean;
81 g_sig_required varchar2(1);
82 g_fwk_flavor varchar2(255);
83 g_email_flavor varchar2(255);
84 g_render varchar2(255);
85
86 -- response_quote VARCHAR2(1) := '"';
87 g_open_text_delimiter VARCHAR2(8) := '"';
88 g_close_text_delimiter VARCHAR2(8) := '"';
89 g_open_html_delimiter VARCHAR2(8) := '''';
90 g_close_html_delimiter VARCHAR2(8) := '''';
91
92
93 -- Generic mailer globals
94 g_Alert_Nodename varchar2(30) := 'ALR';
95
96 --
97 -- HTML Table defaults
98 --
99 table_width varchar2(8) := '100%';
100 table_border varchar2(2) := '0';
101 table_cellpadding varchar2(2) := '0';
102 table_cellspacing varchar2(2) := '0';
103 table_bgcolor varchar2(7) := 'white';
104 th_bgcolor varchar2(7) := '#ffffff';
105 th_fontcolor varchar2(7) := '#000000';
106 th_fontface varchar2(80) := 'Arial, Helvetica, Geneva, sans-serif';
107 th_fontsize varchar2(2) := '2';
108 td_bgcolor varchar2(7) := '#ffffff';
109 td_fontcolor varchar2(7) := 'black';
110 td_fontface varchar2(80) := 'Arial, Helvetica, Geneva, sans-serif';
111 td_fontsize varchar2(2) := '2';
112
113
114 -- UpdateStatus
115 -- Update mail status and close any notification with no response.
116 -- Handle error.
117 -- IN
118 -- notification id
119 -- status
120 -- error name (null if error is in WF_CORE)
121 procedure UpdateStatus(
122 nid in number,
123 status in varchar2,
124 error_name in varchar2)
125 is
126 l_autoclose VARCHAR(1);
127 begin
128 if wf_mail.autoclose_fyi then
129 l_autoclose := 'Y';
130 else
131 l_autoclose := 'N';
132 end if;
133 wf_mail.UpdateStatus2(nid => UpdateStatus.nid,
134 status => UpdateStatus.status,
135 autoclose => l_autoclose,
136 error_name => UpdateStatus.error_name,
137 external_error => null);
138 exception
139 when others then
140 wf_core.context('WF_MAIL', 'UpdateStatus', to_char(nid),
141 UpdateStatus.status, UpdateStatus.error_name);
142 raise;
143
144 end UpdateStatus;
145
146 -- UpdateStatus2
147 -- Update mail status and close any notification with no response.
148 -- Handle error.
149 -- IN
150 -- nid notification id
151 -- status Status to set the notification
152 -- autoclose Flag to specify whether the notification should be closed
153 -- automitically
154 -- error name (null if error is in WF_CORE)
155 -- external_error Any error message that can not be reflected or captured
156 -- through the wf_core.context facilty ie Java.
157 procedure UpdateStatus2(
158 nid in number,
159 status in varchar2,
160 autoclose in varchar2,
161 error_name in varchar2,
162 external_error in varchar2)
163 is
164 l_mType VARCHAR2(8);
165 l_mName VARCHAR2(30);
166 l_currState VARCHAR2(8);
167 updateState boolean;
168 l_role varchar2(320);
169
170 parameterList wf_parameter_list_t;
171 begin
172 select message_type, message_name, mail_status, recipient_role
173 into l_mType, l_mName, l_currState, l_role
174 from wf_notifications
175 where notification_id = nid;
176
177 -- If the prevsious state was FAILED, then preserve this state.
178 -- A new status of null means that a null message was sent.
179 -- This does not cover the case for a pref deliberately set to
180 -- query or to summary (even from summary).
181 if l_currState = 'FAILED' and (status is null or status = '') then
182 updateState := false;
183 else
184 updateState := true;
185 end if;
186
187 if updateState then
188 -- This notification had already locked by wfmail() in the mailer
189 update WF_NOTIFICATIONS
190 set MAIL_STATUS = UpdateStatus2.status
191 where NOTIFICATION_ID = nid;
192 end if;
193
194
195 if (UpdateStatus2.status = 'ERROR') then
196 WF_MAIL.HandleSendError(nid => UpdateStatus2.nid,
197 status => UpdateStatus2.status,
198 error_name => UpdateStatus2.error_name,
199 external_error => UpdateStatus2.external_error);
200 elsif (UpdateStatus2.status = 'FAILED') then
201 -- Here we only raise an event and leave the message as is.
202 -- oracle.apps.wf.notification.send.failure
203 parameterlist := wf_parameter_list_t();
204
205 wf_event.AddParameterToList('NOTIFICATION_ID',nid,parameterlist);
206 wf_event.AddParameterToList('ROLE',l_role,parameterlist);
207 wf_event.AddParameterToList('STATUS',status,parameterlist);
208 wf_event.AddParameterToList('ERROR_NAME',error_name,
209 parameterlist);
210 wf_event.AddParameterToList('EXTERNAL_ERROR',external_error,
211 parameterlist);
212 wf_event.addParameterToList('Q_CORRELATION_ID', l_mType || ':' || l_mName, parameterlist);
213
214 --Raise the event
215 wf_event.Raise(p_event_name => 'oracle.apps.wf.notification.send.failure',
216 p_event_key => l_role,
217 p_parameters => parameterlist);
218
219 elsif UpdateStatus2.status = 'UNAVAIL' then
220 -- 4031628 The UNAVAIL mail_status has never been used, even
221 -- in the C mailer. It only happens when there is a match on
222 -- the pattern/actions. Here we can start to raise an event
223 -- that indicates that a recipient is not available to respond
224 -- to the notification.
225 parameterlist := wf_parameter_list_t();
226
227 wf_event.AddParameterToList('NOTIFICATION_ID', UpdateStatus2.nid, parameterlist);
228 wf_event.AddParameterToList('STATUS', UpdateStatus2.status, parameterlist);
229
230 -- Just for Future point of view. (...receive.unavail event).
231 wf_event.addParameterToList('Q_CORRELATION_ID', l_mType || ':' || l_mName, parameterlist);
232
233 -- Raise the event
234 -- As of now there is NO subscription of this event with SOURCE_TYPE LOCAL.
235 -- So this is just for future point of view ....
236 wf_event.Raise(p_event_name=>'oracle.apps.wf.notification.receive.unavail',
237 p_event_key => to_char(nid),
238 p_parameters => parameterlist);
239
240 elsif (UpdateStatus2.status = 'SENT') then
241 -- The default behaviour is to leave the notification open
242 -- unless there is a routing rule to tell otherwise.
243 -- This is contrary to the behaviour of previous releases
244 -- and will be re-Addressed a little later on.
245
246 -- close this notification if there is no response
247 update WF_NOTIFICATIONS N
248 set N.STATUS = 'CLOSED',
249 N.END_DATE = sysdate
250 where N.NOTIFICATION_ID = nid
251 and not exists (select NULL
252 from WF_MESSAGE_ATTRIBUTES MA
253 where MA.MESSAGE_TYPE = N.MESSAGE_TYPE
254 and MA.MESSAGE_NAME = N.MESSAGE_NAME
255 and MA.SUBTYPE = 'RESPOND')
256 and (UpdateStatus2.autoclose = 'Y'
257 and not exists (select null
258 from wf_routing_rules r
259 where (r.message_type = n.message_type
260 or r.message_type = '*')
261 and (r.message_name = n.message_name
262 or r.message_name = '*')
263 and r.action = 'FYIOPEN'
264 and r.role = n.recipient_role
265 and sysdate between nvl(begin_date, sysdate -1)
266 and nvl(end_date, sysdate + 1)));
267 end if;
268 exception
269 when others then
270 wf_core.context('WF_MAIL', 'UpdateStatus2', to_char(nid),
271 UpdateStatus2.status, UpdateStatus2.autoclose,
272 UpdateStatus2.error_name);
273 raise;
274
275 end UpdateStatus2;
276
277 -- ResetFailed
278 -- Update mail status from FAILED to MAIL for open notifications.
279 -- IN
280 -- Queue number on which to process
281 procedure ResetFailed(p_queue varchar2)
282 is
283 l_nid number;
284 l_recipient WF_NOTIFICATIONS.RECIPIENT_ROLE%TYPE;
285 l_status varchar2 (8);
286 l_timeout boolean;
287 l_error_result varchar2(2000);
288
289 begin
290
291 -- Dequeue from the exception queue
292 -- and re-enqueue the message.
293 l_timeout := FALSE;
294 wf_xml.setFirstMessage('TRUE');
295 while not l_timeout loop
296 wf_xml.GetExceptionMessage(p_queue, l_nid, l_recipient, l_status,
297 l_timeout, l_error_result);
298 if ( not l_timeout ) then
299 update WF_NOTIFICATIONS N
300 set N.MAIL_STATUS = 'MAIL'
301 where N.NOTIFICATION_ID = l_nid;
302 -- wf_xml.EnqueueNotification(l_nid);
303 end if;
304 end loop;
305 commit;
306
307 exception
308 when others then
309 wf_core.context('WF_MAIL', 'ResetFailed', p_queue);
310 raise;
311
312 end ResetFailed;
313
314 -- HandleSendError (PRIVATE)
315 -- Call any callback in error mode if error occurs in sending mail.
316 -- IN
317 -- notification id
318 -- mailer send status
319 -- error name (null if error is in WF_CORE)
320 -- external_error Any error message that can not be reflected or captured
321 -- through the wf_core.context facilty ie Java.
322 procedure HandleSendError(
323 nid in number,
324 status in varchar2,
325 error_name in varchar2,
326 external_error in varchar2)
327 is
328 cb varchar2(240);
329 ctx varchar2(2000);
330 role varchar2(320);
331
332 -- Dynamic sql stuff
333 sqlbuf varchar2(120);
334 tvalue varchar2(4000) := '';
335 nvalue number := '';
336 dvalue date := '';
337 l_dummy varchar2(1);
338 begin
339 -- Get the callback function.
340 select CALLBACK, CONTEXT, RECIPIENT_ROLE
341 into cb, ctx, role
342 from WF_NOTIFICATIONS
343 where NOTIFICATION_ID = nid;
344
345 -- If there is no callback, just clear any error and return.
346 if (cb is null) then
347 wf_core.clear;
348 return;
349 end if;
350
351 -- Put supplied error message on stack, if any
352 if (error_name is not null) then
353 begin
354 wf_core.token('NID', to_char(nid));
355 wf_core.token('STATUS', status);
356 wf_core.token('ROLE', role);
357 if external_error is not null then
358 wf_core.token('EXTERNAL_ERROR', external_error);
359 end if;
360 wf_core.raise(error_name);
361 exception
362 when others then null;
363 end;
364 end if;
365
366 -- Put default error message on stack, if none exists
367 if (wf_core.error_name is null) then
368 begin
369 wf_core.token('NID', to_char(nid));
370 if external_error is not null then
371 wf_core.token('EXTERNAL_ERROR', external_error);
372 end if;
373 wf_core.raise('WFMAIL_GENERIC');
374 exception
375 when others then null;
376 end;
377 end if;
378
379 -- Call the CB in error mode
380 -- ### cb is from table
381 -- BINDVAR_SCAN_IGNORE
382 sqlbuf := 'begin '||cb||
383 '(:p1, :p2, :p3, :p4, :p5, :p6, :p7); end;';
384 execute immediate sqlbuf using
385 in 'ERROR',
386 in ctx,
387 in l_dummy,
388 in l_dummy,
389 in out tvalue,
390 in out nvalue,
391 in out dvalue;
392
393 -- Clear the error from the stack.
394 wf_core.clear;
395
396 exception
397 when others then
398 null;
399 end HandleSendError;
400
401 -- Disable_Recipient_Ntf_pref
402 -- Updates the recipient of a notification to DISABLED where
403 -- there has been a failure to deliver to their email address.
404 -- This function is triggered by the oracle.apps.wf.notification.send.failure
405 -- event.
406 function Disable_Recipient_Ntf_Pref(p_subscription_guid in raw,
407 p_event in out NOCOPY WF_EVENT_T) return varchar2
408 is
409
410 role varchar2(320);
411 recipient varchar2(320);
412 pref varchar2(8);
413 email_address varchar2(320);
414 recipientAddress varchar2(320);
415 params wf_parameter_list_t;
416 errorName varchar2(320);
417 externError varchar2(4000);
418 nid number;
419
420 delim pls_integer;
421
422 errMessage varchar2(4000);
423 errStack varchar2(32000);
424
425 tokens wf_mail_util.parserStack_t;
426 tk pls_integer;
427 dummy varchar2(2000);
428 dummyNumber number;
429
430 orig_system varchar2(30);
431 orig_system_id number;
432
433 paramList wf_parameter_list_t;
434
435 invalidRoleList varchar2(32000);
436 reasonList varchar2(32000);
437 invalidRoleCount pls_integer := 0;
438 alertNid number;
439
440 recipient_disabled boolean;
441 errorReport varchar2(32000);
442 current_maxthreshold number := null;
443
444 cursor c_roles(parent in varchar2)
445 is
446 select name, email_address
447 from wf_roles r, wf_user_roles ur
448 where ur.role_name = parent
449 and r.name = ur.user_name;
450
451 begin
452
453 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
454 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
455 'wf.plsql.WF_MAIL.Disable_Recipient_Ntf_Pref',
456 'BEGIN');
457 end if;
458 role := p_event.getEventKey();
459 params := p_event.getParameterList();
460 errorName := wf_event.getValueForParameter('ERROR_NAME', params);
461 externError := wf_event.getValueForParameter('EXTERNAL_ERROR', params);
462 nid := to_number(wf_event.getValueForParameter('NOTIFICATION_ID', params));
463
464 if errorName = 'WFMLRSND_FAILED_UNDELIVERABLE' or
465 errorName = 'WFMLRSND_FAILED_DELIVERY' then
466
467 -- Where the notification was at all undeliverable, then there
468 -- will be a comma sperated list of recipients. Each one of these
469 -- recipients will have to be disabled.
470 -- The format of the list is {{role}{role}...{role}}.
471
472 -- FAILED_UNDELIVERABLE means that the message was not able to be
473 -- dispatched
474 -- FAILED_DELIVERY means that it was dispatched but failed to be
475 -- delivered at the receiving end. For this, there is
476 -- only the nid for which it is associated.
477 if errorName = 'WFMLRSND_FAILED_DELIVERY' then
478 -- Make up the invalid role list from the recipient_role of the
479 -- undeliverable notification.
480 begin
481
482 delim := instrb(externError, ':');
483
484 if delim = 0 then
485 -- If the details are in the wrong format, don't
486 -- bother to do anything.
487 return 'SUCCESS';
488 end if;
489
490 nid := to_number(substrb(externError, 1, delim -1));
491 recipientAddress := substrb(externError, delim+1);
492
493 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
494 wf_log_pkg.string(WF_LOG_PKG.level_statement,
495 'wf.plsql.WF_MAIL.Disable_Recipient_Ntf_Pref',
496 'NID ['||to_char(nid)||
497 '] RESPONDER ['||recipientAddress||']');
498 end if;
499
500 select recipient_role
501 into recipient
502 from wf_notifications
503 where notification_id = nid;
504
505 exception
506 when no_data_found then
507 -- If there is no notification, then don't do anything
508 return 'SUCCESS';
509 when others then
510 wf_core.context('WF_MAIL','Disable_Recipient_Ntf_Pref',
511 errorName, externError, sqlerrm);
512 raise;
513 end;
514
515 Wf_Directory.GetRoleInfoMail(role => recipient,
516 display_name => dummy,
517 email_address => email_address,
518 notification_preference => pref,
519 language => dummy,
520 territory => dummy,
521 orig_system => orig_system,
522 orig_system_id => orig_system_id,
523 installed_flag => dummy);
524
525 if email_address is not null then
526 -- Expected case for normal recipients
527 externError := '{'||recipient||'}';
528 else
529 -- Case for recipients that are members of roles
530 externError := '';
531 for recip in c_roles(recipient) loop
532 if lower(recip.email_address) = lower(recipientAddress) then
533 externError := externError||'{'||recip.name||'}';
534 end if;
535 end loop;
536 end if;
537 end if;
538
539 tokens := wf_mail_util.strParser(externError, '{}');
540 paramList := wf_parameter_list_t(null);
541
542 invalidRoleList := '';
543 reasonList := '';
544 invalidRoleCount := 0;
545 recipient_disabled := false;
546 errorReport := wf_core.translate('WFMLR_RECIPIENT_ROLE')||' - '||
547 wf_core.translate('WFMLR_NOTIFICATION_PREFERENCE')||
548 wf_core.newline||
549 '=================================================='||
550 wf_core.newline;
551 for tk in 1..tokens.COUNT loop
552 if tokens(tk) is not null and tokens(tk) <> ',' then
553
554 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
555 wf_log_pkg.string(WF_LOG_PKG.level_statement,
556 'wf.plsql.WF_MAIL.Disable_Recipient_Ntf_Pref',
557 'TOKEN ['||tokens(tk)||']');
558 end if;
559 Wf_Directory.GetRoleInfoMail(role => tokens(tk),
560 display_name => dummy,
561 email_address => dummy,
562 notification_preference => pref,
563 language => dummy,
564 territory => dummy,
565 orig_system => orig_system,
566 orig_system_id => orig_system_id,
567 installed_flag => dummy);
568
569 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
570 wf_log_pkg.string(WF_LOG_PKG.level_statement,
571 'wf.plsql.WF_MAIL.Disable_Recipient_Ntf_Pref',
572 'PREFERENCE ['||pref||']');
573 end if;
574
575 if pref is not null and
576 pref not in ('DISABLED', 'QUERY', 'SUMMARY', 'SUMHTML') then
577
578 -- 4717488 Take note of the exsiting notification
579 -- preference. This will go in the notification to the
580 -- SYSADMIN to inform them that this recipient was disabled.
581 -- For a group of recipient, only one notification should be
582 -- sent.
583
584 errorReport := errorReport || tokens(tk)||' - '||pref||
585 wf_core.newLine;
586 recipient_disabled := true;
587
588 -- ER 5748131: Store the existing notification preference of the user
589 -- in FND_USER_PREFERENCES table which can used to reset it back when
590 -- "Bulk Reset DISABLED Notification Preference" CP is run
591 -- Concatenate username with orig system and orig system id to make it
592 -- unique in FND_USER_PREFERENCES table
593 fnd_preference.put(p_user_name => tokens(tk) || ':' || orig_system ||
594 ':' || orig_system_id,
595 p_module_name => 'WF' ,
596 p_pref_name => 'PREV_MAILTYPE',
597 p_pref_value => pref);
598
599 if orig_system in ('FND_USR', 'PER') then
600 FND_PREFERENCE.put(p_user_name => tokens(tk),
601 p_module_name => 'WF',
602 p_pref_name => 'MAILTYPE',
603 p_pref_value => 'DISABLED');
604 else
605
606 paramList.DELETE;
607
608 wf_event.AddParameterToList('USER_NAME', tokens(tk),
609 paramList);
610 wf_event.AddParameterToList('ORCLWORKFLOWNOTIFICATIONPREF',
611 'DISABLED', paramList);
612
613 wf_event.AddParameterToList('RAISEERRORS',
614 'TRUE', paramList);
615 begin
616 wf_local_synch.propagate_user(p_orig_system => orig_system,
617 p_orig_system_id => orig_system_id,
618 p_attributes => paramList);
619 exception
620 when others then
621 -- Should the propagate fail, then save the
622 -- role to be used to update the ErrorStack with
623 -- the failed role and the reason.
624
625 wf_core.get_error(err_name => errorName,
626 err_message => errMessage,
627 err_stack => errStack);
628
629 invalidRoleList := invalidRoleList||'{'||tokens(tk)||
630 ', '||errMessage||'}';
631 invalidRoleCount := invalidRoleCount + 1;
632 end;
633
634 end if;
635
636 else
637 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
638 wf_log_pkg.string(WF_LOG_PKG.level_statement,
639 'wf.plsql.WF_MAIL.Disable_Recipient_Ntf_Pref',
640 'Unable to update notification preference for email ['||
641 tokens(tk)||']. Check for duplicates');
642 end if;
643 end if;
644 end if;
645 end loop;
646
647 -- 4717488 If there as a disable action, then send an error
648 -- message by calling the API. The error report
649 -- can only have 2000 characters! If larger, then it must be
650 -- truncated.
651 --
652 -- This will result in the WFMLRSND_FAILED_UNDELIVERABLE error
653 -- and the WFMLRSND_FAILED_DELIVERY error being raised.
654 --
655 -- The email for Notification NID was undeliverable. The \
656 -- following roles will be disabled DISABLE_REPORT
657 if (recipient_disabled) then
658 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
659 wf_log_pkg.string(WF_LOG_PKG.level_statement,
660 'wf.plsql.WF_MAIL.Disable_Recipient_Ntf_Pref',
661 'One or more users have been disabled. Sending a notification to SYSADMIN');
662 end if;
663 if length(errorReport) > 2000 then
664 errorReport := substrb(errorReport, 1, 1900);
665 errorReport := errorReport||wf_core.translate('WFMLR_REPORT_TRUNC');
666 end if;
667
668 -- Note, can not call HandleSendError here since that will result
669 -- in the notification activity going into error. That is too
670 -- drastic for this case. This becomes a FYI to the SYSADMIN
671 -- to inform them of the update to the user notification preference.
672
673 -- Hardcoding the recipient as SYSADMIN. The WFERROR process
674 -- notifications all have the same, hardcoded value for their
675 -- recipients.
676
677 -- Bug 6431003: Modifying the value of wf_event.phase_maxthreshold
678 -- so that the event gets deferred.
679
680 -- Taking the backup of current wf_event.phase_maxthreshold value
681
682 current_maxthreshold := wf_event.phase_maxthreshold;
683 wf_event.SetDispatchMode ('ASYNC');
684
685 alertNid := WF_NOTIFICATION.send(role => 'SYSADMIN',
686 msg_type => 'WFMAIL',
687 msg_name => 'USER_PREF_UPDATE_REPORT');
688
689 -- Set the attributes for the report. The message won't be dispatched
690 -- until the commit is performed by the calling process.
691 WF_NOTIFICATION.setAttrText(nid => alertNid,
692 aname => 'NOTIFICATION_ID',
693 avalue => to_char(nid));
694 WF_NOTIFICATION.setAttrText(nid => alertNid,
695 aname => 'ROLE',
696 avalue => role);
697 WF_NOTIFICATION.setAttrText(nid => alertNid,
698 aname => 'UPDATED_USER_REPORT',
699 avalue => errorReport);
700
701 -- Ensure that the subject is correctly populated.
702 WF_NOTIFICATION.Denormalize_Notification(alertNid);
703
704 -- Resetting the wf_event.phase_maxthreshold value
705 wf_event.phase_maxthreshold := current_maxthreshold;
706
707 end if;
708
709 end if;
710
711 if invalidRoleCount > 0 then
712 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
713 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
714 'wf.plsql.WF_MAIL.Disable_Recipient_Ntf_Pref',
715 'END WARNING');
716 end if;
717
718 p_event.setErrorMessage(wf_core.translate('WFMLR_ROLE_UPDATE_FAILURE'));
719 p_event.setErrorStack(substrb(invalidRoleList, 1, 4000));
720 return 'WARNING';
721 else
722 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
723 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
724 'wf.plsql.WF_MAIL.Disable_Recipient_Ntf_Pref',
725 'END SUCCESS');
726 end if;
727 return 'SUCCESS';
728 end if;
729
730 exception
731 when others then
732 wf_core.context('WF_MAIL','Disable_Recipient_Ntf_Pref',
733 role, pref);
734 raise;
735 end Disable_Recipient_Ntf_Pref;
736
737 -- GetLovList (PRIVATE)
738 -- Get Text Lov List
739 -- Inputs:
740 -- lk_type - lookup type, which lookup from table.
741 -- Output:
742 -- A list of valid lookup meanings, in the form
743 -- <tab> meaning
744 -- Example: LOOKUP_TYPE: YES_NO
745 -- Returns:
746 -- No
747 -- Yes
748 function GetLovList(
749 lk_type in varchar2)
750 return varchar2 is
751 cursor c is
752 select MEANING
753 from WF_LOOKUPS
754 where LOOKUP_TYPE = lk_type
755 order by MEANING;
756
757 buffer varchar2(32000);
758 begin
759
760 buffer := '';
761 --
762 -- Loop through selecting all lookups
763 --
764 for curs in c loop
765 -- Add lookup to end of buffer string.
766 buffer := buffer||chr_indent||curs.meaning||g_newLine;
767 end loop;
768
769 return(buffer);
770 exception
771 when others then
772 wf_core.context('WF_MAIL', 'GetLovList', lk_type);
773 raise;
774 end GetLovList;
775
776
777 -- Bug# 2301881
778 -- FormatErrorMessage (PRIVATE)
779 -- Gets the error message for an Invalid
780 -- response and returns it formatted
781 -- IN
782 -- error message for name WFMLR_INVALID_LOOKUP
783 --
784 -- OUT
785 -- lookup type
786 -- remarks with expected values
787
788 procedure FormatErrorMessage(lk_type in varchar2,
789 remarks out NOCOPY varchar2)
790 is
791 exp_values varchar2(1000);
792 l_vstart number;
793 l_vend number;
794 l_value1 varchar2(100);
795 l_value2 varchar2(100);
796 begin
797
798 remarks := g_invalidRemarks;
799
800 -- get the values for the lookup type
801 exp_values := GetLovList(lk_type);
802
803 -- get the first two values for the lookup type
804 l_vstart := instr(exp_values, g_newLine, 1);
805 l_vend := instr(exp_values, g_newLine, l_vstart+1);
806 l_value1 := trim(substr(exp_values, 1, l_vstart-1));
807 l_value2 := trim(substr(exp_values, l_vstart+1, l_vend-l_vstart-1));
808
809 remarks := remarks || ' (' || g_forExample || ' "'
810 || l_value1 || '", "' || l_value2
811 || '", ' || g_soOn || ')';
812 exception
813 when others then
814 remarks := g_invalidRemarks;
815 end FormatErrorMessage;
816
817
818 -- HandleResponseError (PRIVATE) handle exception in response
819 --
820 -- Sets the MAIL_ERROR error message attribute, then sets the
821 -- notification status to INVALID.
822 --
823 -- IN
824 -- notification id
825 -- lookup type
826 -- value found
827
828 procedure HandleResponseError(nid in number,
829 lk_type in varchar2,
830 lk_meaning in varchar2,
831 error_result in out NOCOPY varchar2)
832 is
833 errname varchar2(30);
834 errmsg varchar2(2000);
835 errstack varchar2(4000);
836 no_program_unit exception;
837 pragma exception_init(no_program_unit, -6508);
838
839 -- Bug# 2301881 variables to handle new error message format
840 value_found varchar2(1000);
841 remarks varchar2(1000);
842
843 parameterlist wf_parameter_list_t := wf_parameter_list_t();
844
845 role varchar2(320);
846 group_id number;
847 mType varchar2(8);
848 mName varchar2(30);
849
850 begin
851 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
852 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
853 'wf.plsql.WF_MAIL.HandleResponseError',
854 'BEGIN');
855 end if;
856
857 g_invalidRemarks := wf_core.translate('WFMLR_INVALID_REMARKS');
858 g_forExample := wf_core.translate('WFMLR_FOR_EXAMPLE');
859 g_soOn := wf_core.translate('WFMLR_SO_ON');
860 g_none := wf_core.translate('WFMLR_NONE');
861
862 -- First look for a wf_core error.
863 wf_core.get_error(errname, errmsg, errstack);
864
865 -- If no wf_core error look for a sql error.
866 if (errname is null) then
867 errmsg := sqlerrm;
868 end if;
869
870 -- Bug# 2301881 Format the error message
871 if (lk_meaning is not null) then
872 value_found := lk_meaning;
873 else
874 value_found := g_none;
875 end if;
876 if (lk_type is not null) then
877 FormatErrorMessage(lk_type, remarks);
878 else
879 remarks := g_none;
880 end if;
881
882
883 error_result := errmsg;
884
885 -- Set MAIL_ERROR_NAME attribute
886 begin
887 Wf_Notification.SetAttrText(nid, 'MAIL_ERROR_NAME', errname);
888 exception
889 when no_program_unit then
890 raise;
891 when others then
892 if (wf_core.error_name = 'WFNTF_ATTR') then
893 Wf_Core.Clear;
894 Wf_Notification.AddAttr(nid, 'MAIL_ERROR_NAME');
895 Wf_Notification.SetAttrText(nid, 'MAIL_ERROR_NAME', errname);
896 end if;
897 end;
898
899 -- Bug# 2301881 setting the values for message attributes
900 -- Set MAIL_ERROR_MESSAGE attribute
901 begin
902 Wf_Notification.SetAttrText(nid, 'MAIL_ERROR_MESSAGE', errmsg);
903 exception
904 when no_program_unit then
905 raise;
906 when others then
907 if (wf_core.error_name = 'WFNTF_ATTR') then
908 Wf_Core.Clear;
909 Wf_Notification.AddAttr(nid, 'MAIL_ERROR_MESSAGE');
910 Wf_Notification.SetAttrText(nid, 'MAIL_ERROR_MESSAGE', errmsg);
911 end if;
912 end;
913
914 -- Set MAIL_VALUE_FOUND attribute
915 begin
916 Wf_Notification.SetAttrText(nid, 'MAIL_VALUE_FOUND', value_found);
917 exception
918 when no_program_unit then
919 raise;
920 when others then
921 if (wf_core.error_name = 'WFNTF_ATTR') then
922 Wf_Core.Clear;
923 Wf_Notification.AddAttr(nid, 'MAIL_VALUE_FOUND');
924 Wf_Notification.SetAttrText(nid, 'MAIL_VALUE_FOUND', value_found);
925 end if;
926 end;
927
928 -- Set MAIL_EXP_VALUES attribute
929 begin
930 Wf_Notification.SetAttrText(nid, 'MAIL_EXP_VALUES', remarks);
931 exception
932 when no_program_unit then
933 raise;
934 when others then
935 if (wf_core.error_name = 'WFNTF_ATTR') then
936 Wf_Core.Clear;
937 Wf_Notification.AddAttr(nid, 'MAIL_EXP_VALUES');
938 Wf_Notification.SetAttrText(nid, 'MAIL_EXP_VALUES', remarks);
939 end if;
940 end;
941
942 -- End Bug# 2301881
943
944 -- Set MAIL_ERROR_STACK attribute
945 if (errstack is null) then
946 errstack := ' ';
947 end if;
948
949 begin
950 Wf_Notification.SetAttrText(nid, 'MAIL_ERROR_STACK', errstack);
951 exception
952 when no_program_unit then
953 raise;
954 when others then
955 if (wf_core.error_name = 'WFNTF_ATTR') then
956 Wf_Core.Clear;
957 Wf_Notification.AddAttr(nid, 'MAIL_ERROR_STACK');
958 Wf_Notification.SetAttrText(nid, 'MAIL_ERROR_STACK', errstack);
959 end if;
960 end;
961
962 -- Set the mail_status to INVALID (mailer will pick this up)
963 update WF_NOTIFICATIONS
964 set MAIL_STATUS = 'INVALID'
965 where NOTIFICATION_ID = nid;
966 -- wf_xml.enqueueNotification(nid);
967
968 select recipient_role, group_id, message_type, message_name
969 into role, group_id, mType, mName
970 from wf_notifications
971 where notification_id = nid;
972
973 wf_event.AddParameterToList('NOTIFICATION_ID', nid, parameterlist);
974 wf_event.AddParameterToList('ROLE', role, parameterlist);
975 wf_event.AddParameterToList('GROUP_ID', nvl(group_id, nid), parameterlist);
976 wf_event.addParameterToList('Q_CORRELATION_ID', mType || ':' || mName, parameterlist);
977
978 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
979 wf_log_pkg.string(WF_LOG_PKG.level_statement,
980 'wf.plsql.WF_MAIL.HandleResponseError',
981 'Raising the Send event');
982 end if;
983
984 --Raise the event
985 wf_event.Raise(p_event_name => 'oracle.apps.wf.notification.send',
986 p_event_key => to_char(nid),
987 p_parameters => parameterlist);
988
989 exception
990 when others then
991 if (wf_log_pkg.level_exception >= fnd_log.g_current_runtime_level) then
992 wf_log_pkg.string(WF_LOG_PKG.level_exception,
993 'wf.plsql.WF_MAIL.HandleResponseError',
994 'Error Msg '|| sqlerrm);
995 end if;
996
997 wf_core.context('WF_MAIL', 'HandleResponseError', nid);
998 raise;
999 end HandleResponseError;
1000
1001
1002 -- WordWrap (PRIVATE)
1003 -- Insert newlines to word wrap a line buffer.
1004 -- Inputs:
1005 -- text - text buffer
1006 -- indent - number of tabs to indent each line by
1007 -- Returns:
1008 -- buffer contents with newlines and tabs embedded
1009 function WordWrap(
1010 text in varchar2,
1011 indent in number)
1012 return varchar2 is
1013 buf varchar2(32000); -- Text buffer
1014 textlen pls_integer; -- Length of original 'text' argument
1015 newpos pls_integer; -- Current position in text
1016 space pls_integer; -- Position of space char to use for line break
1017 tabs varchar2(80); -- Tab string to prepend each line with
1018 maxlinelen pls_integer; -- Max line length allowed
1019 begin
1020 -- Ignore empty string
1021 if (text is null) then
1022 return('');
1023 end if;
1024
1025 buf := '';
1026 newpos := 1;
1027 textlen := length(text);
1028
1029 -- Build the indentation string. This is a string to pre-pend to every
1030 -- line, containing the requested number of tabs.
1031 -- (No, lpad/rpad won't work because initial string is null.)
1032 tabs := '';
1033 for i in 1 .. indent loop
1034 tabs := substr(tabs||chr_indent, 1, 80);
1035 end loop;
1036 -- Adjust line length to account for indentation
1037 maxlinelen := wf_linelen - (chr_indentsize * indent);
1038
1039 loop
1040 -- Exit when all remaining text fits on one line.
1041 exit when (textlen - newpos <= maxlinelen);
1042
1043 -- If next newline is before maxlinelen, then the line is already
1044 -- short enough. Use the newline as the linebreak.
1045 space := instr(text, g_newLine, newpos, 1);
1046
1047 if ((space = 0) or (space > (newpos + maxlinelen))) then
1048 -- Either no newlines, or next newline is beyond maxlinelen.
1049 -- Find the last space before maxlinelen.
1050 space := instr(text, ' ', -(textlen - newpos - maxlinelen), 1);
1051
1052 if ((space = 0) or (space < newpos)) then
1053 -- No spaces on this line.
1054 -- Wrap at the next space or newline available.
1055 space := instr(replace(text, g_newLine, ' '),
1056 ' ', newpos + maxlinelen, 1);
1057
1058 if (space = 0) then
1059 -- No spaces or newlines left at all, so no more wrapping
1060 -- can be done. Exit now and append any remaining text unaltered.
1061 exit;
1062 end if;
1063 end if;
1064 end if;
1065
1066 -- Append the new line to the buffer followed by a newline,
1067 -- indented by requested number of tabs.
1068 buf := substrb(buf||tabs||rtrim(substr(text, newpos, space - newpos))||
1069 g_newLine, 1, 32000);
1070
1071 -- Start again after last space.
1072 newpos := space + 1;
1073 end loop;
1074
1075 -- Append last partial line.
1076 buf := substrb(buf||tabs||rtrim(substr(text, newpos)), 1, 32000);
1077
1078 return(buf);
1079 exception
1080 when others then
1081 wf_core.context('WF_MAIL', 'WordWrap', text, to_char(indent));
1082 raise;
1083 end WordWrap;
1084
1085
1086 -- GetLovMeaning (PRIVATE)
1087 -- Return the displayed meaning of a lookup
1088 -- Inputs:
1089 -- lk_type - lookup type
1090 -- lk_code - lookup code
1091 -- Returns:
1092 -- lookup meaning
1093 function GetLovMeaning(
1094 lk_type in varchar2,
1095 lk_code in varchar2)
1096 return varchar2 is
1097 buf varchar2(80);
1098 begin
1099 -- Allow null values
1100 if (lk_code is null) then
1101 return(null);
1102 end if;
1103
1104 begin
1105 select MEANING
1106 into buf
1107 from WF_LOOKUPS
1108 where LOOKUP_TYPE = lk_type and LOOKUP_CODE = lk_code;
1109 exception
1110 when no_data_found then
1111 wf_core.token('TYPE', lk_type);
1112 wf_core.token('CODE', lk_code);
1113 wf_core.raise('WFSQL_LOOKUP_CODE');
1114 end;
1115
1116 return(buf);
1117 exception
1118 when others then
1119 wf_core.context('WF_MAIL', 'GetLovMeaning', lk_type, lk_code);
1120 raise;
1121 end GetLovMeaning;
1122
1123
1124 -- GetLovCode (PRIVATE) Return the hidden code of a lookup
1125 --
1126 -- IN
1127 -- lookup type
1128 -- lookup meaning
1129 -- RETURN
1130 -- lookup code
1131 function GetLovCode(
1132 lk_type in varchar2,
1133 lk_meaning in varchar2)
1134 return varchar2 is
1135 buf varchar2(30);
1136 begin
1137 -- Allow null values
1138 if (lk_meaning is null) then
1139 wf_core.raise('WFMLR_INVALID_LOOKUP');
1140 end if;
1141
1142 -- Exact match
1143 begin
1144 select LOOKUP_CODE
1145 into buf
1146 from WF_LOOKUPS
1147 where LOOKUP_TYPE = lk_type
1148 and MEANING = lk_meaning;
1149
1150 return buf;
1151 exception
1152 when no_data_found then
1153 null;
1154 end;
1155
1156 -- Case-insensitive match
1157 begin
1158 select LOOKUP_CODE
1159 into buf
1160 from WF_LOOKUPS
1161 where LOOKUP_TYPE = lk_type
1162 and upper(MEANING) = upper(lk_meaning);
1163 exception
1164 when no_data_found then
1165 wf_core.raise('WFMLR_INVALID_LOOKUP');
1166 end;
1167
1168 return buf;
1169 exception
1170 when others then
1171 wf_core.context('WF_MAIL', 'GetLovCode', lk_type, lk_meaning);
1172 raise;
1173 end GetLovCode;
1174
1175
1176 -- GetLovListInternal (PRIVATE)
1177 -- Get Text Lov List (Internal Name)
1178 -- Inputs:
1179 -- lk_type - lookup type, which lookup from table.
1180 -- Output:
1181 -- A list of valid lookup meanings, in the form
1182 -- <tab> meaning
1183 -- Example: LOOKUP_TYPE: YES_NO
1184 -- Returns:
1185 -- No
1186 -- Yes
1187 function GetLovListInternal(
1188 lk_type in varchar2)
1189 return varchar2 is
1190 cursor c is
1191 select LOOKUP_CODE
1192 from WF_LOOKUPS
1193 where LOOKUP_TYPE = lk_type
1194 order by LOOKUP_CODE;
1195
1196 buffer varchar2(32000);
1197 begin
1198
1199 buffer := '';
1200 --
1201 -- Loop through selecting all lookups
1202 --
1203 for curs in c loop
1204 -- Add lookup to end of buffer string.
1205 buffer := buffer||curs.lookup_code||g_newLine;
1206 end loop;
1207
1208 return(buffer);
1209 exception
1210 when others then
1211 wf_core.context('WF_MAIL', 'GetLovListInternal', lk_type);
1212 raise;
1213 end GetLovListInternal;
1214
1215 -- GetDirectAnswer (PRIVATE)
1216 -- Get Answer for direct response
1217 -- Inputs:
1218 -- mail body.
1219 -- Output:
1220 -- Answer
1221 procedure GetDirectAnswer(body in out NOCOPY varchar2,
1222 one_answer out NOCOPY varchar2) is
1223 answer varchar2(4000);
1224 newline_pos pls_integer;
1225 close_doublequote_pos pls_integer;
1226 answer_syntax_error exception;
1227 begin
1228
1229 -- Striping leading spaces and tabs
1230 while (substr(body, 1, 1) = ' ' or
1231 substr(body, 1, 1) = g_tab) loop
1232 body := substr(body, 2, length(body) - 1);
1233 end loop;
1234
1235 if (substr(body, 1, 1) <> '"') then
1236 -- Answer not quoted in ""
1237 newline_pos := instr(body, g_newLine, 1);
1238 if (newline_pos = 0) then
1239 answer := substrb(body,1,4000);
1240 else
1241 if (newline_pos <> 1) then
1242 answer := substr(body, 1, newline_pos-1);
1243 else
1244 answer := null;
1245 end if;
1246 body := substr(body, newline_pos + 1, length(body) - newline_pos);
1247 end if;
1248 -- Striping trailing spaces, \r or \tab
1249 while ((substr(answer, length(answer), 1) = ' ') or
1250 (substr(answer, length(answer), 1) = g_newLine) or
1251 (substr(answer, length(answer), 1) = g_tab)) loop
1252 answer := substr(answer, 1, length(answer) - 1);
1253 end loop;
1254
1255 else
1256 close_doublequote_pos := instr(body, '"', 2);
1257 if close_doublequote_pos > 4001 then
1258 answer := substr(body, 2, 3998);
1259 else
1260 answer := substr(body, 2, close_doublequote_pos -2);
1261 end if;
1262
1263 if (substr(body, close_doublequote_pos + 1, 1) <> g_newLine) then
1264 raise answer_syntax_error;
1265 end if;
1266 body := substr(body, close_doublequote_pos + 2,
1267 length(body) - close_doublequote_pos - 1);
1268 end if;
1269
1270 one_answer := answer;
1271
1272 exception
1273 when answer_syntax_error then
1274 wf_core.context('WF_MAIL', 'GetDirectAnswer');
1275 raise;
1276 when others then
1277 wf_core.context('WF_MAIL', 'GetDirectAnswer');
1278 raise;
1279 end GetDirectAnswer;
1280
1281
1282 -- GetEmailResponse (PRIVATE) - Get Email Response Section
1283 -- IN
1284 -- notification id
1285 -- RETURN
1286 -- response template
1287 function GetEmailResponse(nid in number) return varchar2
1288 is
1289
1290
1291 cursor c1 is
1292 select WMA.DISPLAY_NAME, WMA.DESCRIPTION, WMA.TYPE, WMA.FORMAT,
1293 decode(WMA.TYPE,
1294 'VARCHAR2', decode(WMA.FORMAT,
1295 '', WNA.TEXT_VALUE,
1296 substr(WNA.TEXT_VALUE, 1, to_number(WMA.FORMAT))),
1297 'NUMBER', decode(WMA.FORMAT,
1298 '', to_char(WNA.NUMBER_VALUE),
1299 to_char(WNA.NUMBER_VALUE, WMA.FORMAT)),
1300 -- 'DATE', decode(WMA.FORMAT,
1301 -- '', to_char(WNA.DATE_VALUE),
1302 -- to_char(WNA.DATE_VALUE, WMA.FORMAT)),
1303 --
1304 -- <<sstomar>> : Due to boolean flag, wf_notification_util.GetCalendarDate can not be used.
1305 --'DATE', wf_notification_util.GetCalendarDate(p_nid=>nid, p_date=>WNA.DATE_VALUE, p_date_format=>WMA.FORMAT),
1306 'LOOKUP', WNA.TEXT_VALUE,
1307 WNA.TEXT_VALUE) VALUE,
1308 WNA.DATE_VALUE -- value is Date type <<bug8430385>
1309 from WF_NOTIFICATION_ATTRIBUTES WNA,
1310 WF_NOTIFICATIONS WN,
1311 WF_MESSAGE_ATTRIBUTES_VL WMA
1312 where WNA.NOTIFICATION_ID = nid
1313 and WN.NOTIFICATION_ID = WNA.NOTIFICATION_ID
1314 and WN.MESSAGE_TYPE = WMA.MESSAGE_TYPE
1315 and WN.MESSAGE_NAME = WMA.MESSAGE_NAME
1316 and WMA.NAME = WNA.NAME
1317 and WMA.SUBTYPE = 'RESPOND'
1318 and WMA.TYPE not in ('FORM', 'URL')
1319 order by WMA.SEQUENCE;
1320
1321 buffer varchar2(32000);
1322 begin
1323 -- for each response variable
1324 for rec in c1 loop
1325 -- Print description
1326 buffer := buffer||WordWrap(rec.description, 0);
1327 if (rec.description is not null) then
1328 buffer := buffer||g_newLine;
1329 end if;
1330
1331 -- Print prompt
1332 buffer := buffer||' '||rec.display_name||': '||
1333 wf_mail.g_open_text_delimiter;
1334
1335 -- Print field
1336 if (rec.type = 'LOOKUP') then
1337 -- LOOKUPs: show displayed meaning, list of choices
1338 buffer := buffer || GetLovMeaning(rec.format, rec.value) ||
1339 wf_mail.g_close_text_delimiter || g_newLine ||
1340 GetLovList(rec.format);
1341 ELSIF (rec.type = 'DATE' AND rec.DATE_VALUE is not null) then
1342 -- <<bug8430385> : use DATE_VALUE
1343 buffer := buffer || wf_notification_util.GetCalendarDate(nid, rec.DATE_VALUE, rec.format, false)
1344 || wf_mail.g_close_text_delimiter
1345 || g_newLine;
1346 else
1347 -- VARCHAR2, NUMBER, : use value directly.
1348 buffer := buffer || rec.value || wf_mail.g_close_text_delimiter || g_newLine;
1349 end if;
1350
1351 buffer := buffer || g_newLine;
1352 end loop;
1353
1354 return buffer;
1355
1356 exception
1357 when others then
1358 wf_core.context('WF_MAIL', 'GetEmailResponse', to_char(nid));
1359 raise;
1360 end GetEmailResponse;
1361
1362
1363 -- GetEmailDirectResponse (PRIVATE) - Get Email Response Section
1364 -- IN
1365 -- notification id
1366 -- RETURN
1367 -- response template
1368 function GetEmailDirectResponse(nid in number) return varchar2
1369 is
1370 cursor c1 is
1371 select WMA.DISPLAY_NAME, WMA.DESCRIPTION, WMA.TYPE, WMA.FORMAT,
1372 decode(WMA.TYPE,
1373 'VARCHAR2', decode(WMA.FORMAT,
1374 '', WNA.TEXT_VALUE,
1375 substr(WNA.TEXT_VALUE, 1, to_number(WMA.FORMAT))),
1376 'NUMBER', decode(WMA.FORMAT,
1377 '', to_char(WNA.NUMBER_VALUE),
1378 to_char(WNA.NUMBER_VALUE, WMA.FORMAT)),
1379 --'DATE', decode(WMA.FORMAT,
1380 -- '', to_char(WNA.DATE_VALUE),
1381 -- to_char(WNA.DATE_VALUE, WMA.FORMAT)),
1382 -- 'DATE', wf_notification_util.GetCalendarDate(nid, WNA.DATE_VALUE, WMA.FORMAT, true),
1383 'LOOKUP', WNA.TEXT_VALUE,
1384 WNA.TEXT_VALUE) VALUE,
1385 WNA.DATE_VALUE
1386 from WF_NOTIFICATION_ATTRIBUTES WNA,
1387 WF_NOTIFICATIONS WN,
1388 WF_MESSAGE_ATTRIBUTES_VL WMA
1389 where WNA.NOTIFICATION_ID = nid
1390 and WN.NOTIFICATION_ID = WNA.NOTIFICATION_ID
1391 and WN.MESSAGE_TYPE = WMA.MESSAGE_TYPE
1392 and WN.MESSAGE_NAME = WMA.MESSAGE_NAME
1393 and WMA.NAME = WNA.NAME
1394 and WMA.SUBTYPE = 'RESPOND'
1395 and WMA.TYPE not in ('FORM', 'URL')
1396 order by WMA.SEQUENCE;
1397
1398 buffer varchar2(32000) := '';
1399 seq pls_integer := 1;
1400
1401 begin
1402
1403 -- for each response variable
1404 for rec in c1 loop
1405 -- Construct response instruction:
1406 wf_core.token('DISPLAY_NAME', rec.display_name);
1407 wf_core.token('SEQ', seq);
1408 wf_core.token('DESCRIPTION', rec.description);
1409
1410 -- Enter the <display_name> on line <#seq> <description>
1411 buffer := buffer||
1412 wf_core.substitute('WFMLR', 'WFMLR_DIRECT_ENTER');
1413
1414 if (rec.value is not null) then
1415 if (rec.type = 'LOOKUP') then
1416 wf_core.token('DEFAULT_VALUE',GetLovMeaning(rec.format,rec.value));
1417 else
1418 wf_core.token('DEFAULT_VALUE', rec.value);
1419 end if;
1420 end if;
1421
1422 -- <SSTOMAR> :
1423 IF(rec.date_value IS NOT null) then
1424 wf_core.token('DEFAULT_VALUE', rec.date_value);
1425 end if;
1426
1427
1428 --
1429 if (rec.format is not null) then
1430 wf_core.token('FORMAT', rec.format);
1431 elsif (rec.type = 'VARCHAR2') then
1432 wf_core.token('FORMAT', '2000');
1433 end if;
1434
1435 buffer := buffer||g_newLine;
1436
1437 -- Handle LOOKUP specially because of printing the LOV list
1438 if (rec.type = 'LOOKUP') then
1439 if (rec.value is not null) then
1440 buffer := buffer||
1441 wf_core.substitute('WFMLR', 'WFMLR_DIRECT_LOOKUP_DEFAULT');
1442 else
1443 buffer := buffer||
1444 wf_core.substitute('WFMLR', 'WFMLR_DIRECT_LOOKUP');
1445 end if;
1446 buffer := WordWrap(buffer, 0);
1447 buffer := buffer || g_newLine || GetLovList(rec.format);
1448 else
1449
1450 -- Value must be ........
1451 if (rec.type = 'DATE') then
1452 -- DATE: show date format
1453 if (rec.format is not null) then
1454 -- &FORMAT would be replaced in "{Value must be a date in the form "&FORMAT".????? }"
1455 Buffer := buffer ||
1456 wf_core.substitute('WFMLR', 'WFMLR_DIRECT_DATE_FORMAT');
1457 else
1458 buffer := buffer ||
1459 wf_core.substitute('WFMLR', 'WFMLR_DIRECT_DATE');
1460 end if;
1461 elsif (rec.type = 'NUMBER') then
1462 -- NUMBER: show number format
1463 if (rec.format is not null) then
1464 buffer := buffer ||
1465 wf_core.substitute('WFMLR','WFMLR_DIRECT_NUMBER_FORMAT');
1466 else
1467 buffer := buffer||
1468 wf_core.substitute('WFMLR', 'WFMLR_DIRECT_NUMBER');
1469 end if;
1470
1471 elsif (rec.type = 'VARCHAR2') then
1472 -- VARCHAR2: show varchar2 format
1473 buffer := buffer||
1474 wf_core.substitute('WFMLR', 'WFMLR_DIRECT_VARCHAR2_FORMAT');
1475 end if;
1476
1477 --
1478 --
1479 if ((rec.value is not null) and (rec.type <> 'LOOKUP')) then
1480
1481 wf_core.token('DEFAULT_VALUE', rec.value);
1482
1483 buffer := buffer||g_newLine||
1484 wf_core.substitute('WFMLR', 'WFMLR_DIRECT_DEFAULT');
1485
1486 elsif (rec.date_value is not null) then
1487 wf_core.token('DEFAULT_VALUE', rec.date_value);
1488
1489 -- {Default is "&DEFAULT_VALUE".??? }
1490 buffer := buffer||g_newLine||
1491 wf_core.substitute('WFMLR', 'WFMLR_DIRECT_DEFAULT');
1492
1493 end if;
1494
1495 buffer := WordWrap(buffer, 0);
1496
1497 end if;
1498
1499 buffer := buffer || g_newLine || g_newLine;
1500 seq := seq + 1;
1501 end loop;
1502
1503 return buffer;
1504
1505 exception
1506 when others then
1507 wf_core.context('WF_MAIL', 'GetEmailDirectResponse', to_char(nid));
1508 raise;
1509 end GetEmailDirectResponse;
1510
1511
1512 -- UrlEncode (PRIVATE)
1513 -- Inputs:
1514 -- input string
1515 -- Output:
1516 -- encoded string
1517 function UrlEncode(in_string varchar2) return varchar2
1518 is
1519 encoded_string varchar2(32000);
1520 begin
1521
1522 encoded_string := in_string;
1523
1524 encoded_string := replace(encoded_string, '%', '%25' );
1525 encoded_string := replace(encoded_string, ' ', '%20' );
1526 encoded_string := replace(encoded_string, '!', '%21' );
1527 encoded_string := replace(encoded_string, '"', '%22' );
1528 encoded_string := replace(encoded_string, '#', '%23' );
1529 encoded_string := replace(encoded_string, '$', '%24' );
1530 encoded_string := replace(encoded_string, '&', '%26' );
1531 encoded_string := replace(encoded_string, '''', '%27' );
1532 encoded_string := replace(encoded_string, '(', '%28' );
1533 encoded_string := replace(encoded_string, ')', '%29' );
1534 encoded_string := replace(encoded_string, '*', '%2a' );
1535 encoded_string := replace(encoded_string, '+', '%2b' );
1536 encoded_string := replace(encoded_string, ',', '%2c' );
1537 encoded_string := replace(encoded_string, '-', '%2d' );
1538 encoded_string := replace(encoded_string, '.', '%2e' );
1539 encoded_string := replace(encoded_string, '/', '%2f' );
1540 encoded_string := replace(encoded_string, ';', '%3b' );
1541 encoded_string := replace(encoded_string, '<', '%3c' );
1542 encoded_string := replace(encoded_string, '=', '%3d' );
1543 encoded_string := replace(encoded_string, '>', '%3e' );
1544 encoded_string := replace(encoded_string, '?', '%3f' );
1545 encoded_string := replace(encoded_string, '@', '%40' );
1546 encoded_string := replace(encoded_string, '[', '%5b' );
1547 encoded_string := replace(encoded_string, '\', '%5c' );
1548 encoded_string := replace(encoded_string, ']', '%5d' );
1549 encoded_string := replace(encoded_string, '^', '%5e' );
1550 encoded_string := replace(encoded_string, '_', '%5f' );
1551 encoded_string := replace(encoded_string, '`', '%60' );
1552 encoded_string := replace(encoded_string, '{', '%7b' );
1553 encoded_string := replace(encoded_string, '|', '%7c' );
1554 encoded_string := replace(encoded_string, '}', '%7d' );
1555 encoded_string := replace(encoded_string, '~', '%7e' );
1556 encoded_string := replace(encoded_string, g_newLine,
1557 '%0D%0A');
1558
1559 return(encoded_string);
1560
1561 end UrlEncode;
1562
1563 -- GetMoreInfoLOV (PRIVATE) - bug 2282139
1564 -- Return a list of WF participants (PRIVATE)
1565 -- IN
1566 -- notification id
1567 -- current_role - role/user to whom the ntf is addresses
1568 --
1569 -- RETURN list of roles whom have participated in the workflow
1570 -- <<SSTOMAR>> bug 7565684: only one user is returned for
1571 -- MORE_INFO for email notification.
1572 --
1573
1574 function GetMoreInfoLOV(nid NUMBER, current_role in VARCHAR2)
1575 return varchar2
1576 is
1577 itemType VARCHAR2(8);
1578 itemKey VARCHAR2(240);
1579 context VARCHAR2(2000);
1580 orig_sys varchar2(30);
1581 orig_sysid number;
1582 buffer varchar2(32000);
1583 col1 pls_integer;
1584 col2 pls_integer;
1585
1586 -- Cursor to find all users/roles associated with the notification
1587 -- other than the ones associated to recipient_role
1588 cursor c is
1589 SELECT DISTINCT role user_name
1590 FROM
1591 (
1592 SELECT role_priority, role
1593 FROM
1594 (
1595 -- 1). Process ONWER
1596 SELECT 2 role_priority,
1597 wi.owner_role role
1598 FROM wf_items wi
1599 where wi.item_type = itemType
1600 and wi.item_key = itemKey
1601 and owner_role IS NOT NULL
1602
1603 UNION ALL
1604
1605 -- 2). Notification current owner
1606 select 1 role_priority,
1607 ntf.recipient_role role
1608 from (select notification_id
1609 from wf_item_activity_statuses ias
1610 where ias.item_type = itemType
1611 and ias.item_key = itemKey
1612 union all
1613 select notification_id
1614 from wf_item_activity_statuses_h ias
1615 where ias.item_type = itemType
1616 and ias.item_key = itemKey)
1617 iantf,
1618 wf_notifications ntf
1619 where iantf.notification_id = ntf.group_id
1620 AND ntf.group_id = nid
1621
1622 UNION ALL
1623
1624 -- 3). Notification original recipient
1625 -- <<sstomar> For email : I don't think we should consider this sql
1626 -- because SQL#2 will select current recipient and SQL#4 will
1627 -- select wf_ntf.FROM_ROLE .
1628 select 1 role_priority,
1629 ntf.original_recipient role
1630 from (select notification_id
1631 from wf_item_activity_statuses ias
1632 where ias.item_type = itemType
1633 and ias.item_key = itemKey
1634 union all
1635 select notification_id
1636 from wf_item_activity_statuses_h ias
1637 where ias.item_type = itemType
1638 and ias.item_key = itemKey)
1639 iantf,
1640 wf_notifications ntf
1641 where iantf.notification_id = ntf.group_id
1642 and ntf.group_id = nid
1643
1644 UNION ALL
1645
1646 -- 4). #FROM_ROLE or if ntf has been transfered / delegated / Questioned / Answered
1647 --
1648 SELECT 3 role_priority,
1649 ntf.FROM_ROLE role
1650 FROM ( select notification_id
1651 from wf_item_activity_statuses ias
1652 where ias.item_type = itemType
1653 and ias.item_key = itemKey
1654 union all
1655 select notification_id
1656 from wf_item_activity_statuses_h ias
1657 where ias.item_type = itemType
1658 and ias.item_key = itemKey
1659 )
1660 iantf,
1661 wf_notifications ntf
1662 where iantf.notification_id = ntf.group_id
1663 and ntf.group_id = nid
1664 and ntf.from_role is not null
1665
1666 )
1667 WHERE role <> current_role
1668 -- this role should not be a role to whome current user belongs
1669 AND role not in (select wur.role_name
1670 from wf_user_roles wur
1671 where wur.user_name = current_role
1672 and wur.user_orig_system = orig_sys
1673 and wur.user_orig_system_id = orig_sysid
1674 )
1675 -- bug 2887904 latest participant first
1676 -- sstomar: added role_priority instead of begin_date. bug 7565684
1677 order by role_priority desc
1678 )
1679 -- Without below clause, cursor may return random user because it does not return
1680 -- sequentially baed on an order by clause.
1681 WHERE rownum=1;
1682
1683
1684 begin
1685
1686 select context
1687 into context
1688 from wf_notifications
1689 where notification_id = nid;
1690
1691 -- get item type and item key from the context
1692 if context is not null then
1693 col1 := instr(context, ':', 1, 1);
1694 col2 := instr(context, ':', -1, 1);
1695
1696 itemtype := substr(substr(context, 1, col1-1),1,8);
1697 itemkey := substr(substr(context, col1+1, col2-col1-1),1,240);
1698 end if;
1699
1700 buffer := '';
1701
1702 -- get role's orig sys and orig sys id from the role name
1703 col1 := instr(current_role, ':', 1, 1);
1704 if (col1 > 0) then
1705 orig_sys := substr(current_role, 1, col1 - 1);
1706 orig_sysid := substr(current_role, col1 + 1);
1707 else
1708 Wf_Directory.GetRoleOrigSysInfo(current_role, orig_sys, orig_sysid);
1709 end if;
1710
1711 for curs in c loop
1712 -- sacsharm bug 2887904 if one particpant, no linefeed needed
1713 -- buffer := buffer || curs.user_name || g_newLine;
1714 if c%ROWCOUNT = 1 then
1715 buffer := curs.user_name;
1716
1717 -- sacsharm bug 2887904 only latest particpant should be returned
1718 -- NOTE following exit should be removed later one issue of how to
1719 -- display participant roles in email is resolved. This is done
1720 -- so that currently this function only returns latest participant
1721
1722 --<<stomar>> : 7565684:
1723 -- Just leaving EXIT stmt as it is otherwise it is NOT required as
1724 -- cursor will return only ONE row ( though cursor too NOT required) .
1725
1726 exit;
1727 elsif c%ROWCOUNT > 1 then
1728 buffer := buffer || g_newLine || curs.user_name;
1729 end if;
1730
1731 end loop;
1732
1733 return buffer;
1734 exception
1735 when others then
1736 WF_CORE.Context('WF_MAIL','GetMoreInfoLOV', to_char(nid));
1737 raise;
1738 end GetMoreInfoLOV;
1739
1740 --
1741 -- GetMoreInfoMailTo (PRIVATE) - bug 2282139
1742 -- IN
1743 -- nid - Notification id
1744 -- n_tag - NID string
1745 -- reply_to - Reply to email id
1746 -- subject - Email subject
1747 -- OUT
1748 -- mail to html tag for more info request or submission
1749 function GetMoreInfoMailTo(nid in number,
1750 n_tag in varchar2,
1751 reply_to in varchar2,
1752 subject in varchar2) return varchar2
1753 is
1754 buffer varchar2(32000);
1755 body varchar2(32000);
1756 encoded_tag varchar2(240);
1757 question varchar2(4000);
1758 l_requestee varchar2(32000);
1759
1760 cursor c_questions is
1761 select user_comment
1762 from wf_comments
1763 where notification_id = nid
1764 and action in ('QUESTION', 'QUESTION_WA', 'QUESTION_RULE')
1765 order by comment_date desc ;
1766 begin
1767 -- this gives mailto tag for the OPEN_MOREINFO template to submit
1768 -- requested information
1769 if (g_moreinfo = 'SUB') then
1770 -- Encode any special characters
1771 encoded_tag := UrlEncode(n_tag||'[4]');
1772 -- sacsharm, too much space
1773 -- body := body || g_newLine;
1774 body := body || g_moreInfoQPrompt;
1775
1776 open c_questions;
1777 fetch c_questions into question;
1778 close c_questions;
1779
1780 -- provide response delimiters based on the content of the question
1781 if (instr(question, '''', 1) > 0 and instr(question, '"', 1) > 0 and
1782 (instr(question, '[', 1) > 0 or instr(question, ']', 1) > 0)) then
1783 -- all delimiters are used in the question, escape one and enclose
1784 -- within the escaped one
1785 question := replace(question, '''', '\\''');
1786 body := body || ': '''||question||'''';
1787 elsif (instr(question, '''', 1) > 0 and instr(question, '"', 1) > 0) then
1788 body := body || ': ['||question||']';
1789 elsif (instr(question, '''', 1) > 0) then
1790 body := body || ': "'||question||'"';
1791 else
1792 body := body || ' :'''||question||'''';
1793 end if;
1794
1795 body := body || g_newLine;
1796 body := body || g_moreInfoAPrompt;
1797
1798 -- ankung (removing <)
1799 -- body := body || ': ''<';
1800 body := body || ': '||wf_mail.g_open_html_delimiter;
1801
1802 body := body || g_moreInfoAnswer;
1803
1804 -- ankung (removing >)
1805 -- body := body || '>''';
1806 body := body || wf_mail.g_close_html_delimiter;
1807
1808 body := body || g_newLine;
1809 body := UrlEncode(body);
1810 buffer := buffer ||'&'||'nbsp;'||'&'||'nbsp;'||
1811 '<A class="OraLink" HREF="mailto:'||reply_to||'?subject=%20'||
1812 UrlEncode(g_moreInfoSubject)||':%20'||
1813 UrlEncode(subject)||'&'||'body=%20'||body||
1814 '%0D%0A%0D%0A'||encoded_tag||'">'||
1815 '<FONT size=+1><B>'||g_moreInfoSubmit||
1816 '</FONT></B>'||'</A>';
1817
1818 -- this gives the additional link along with the response links to
1819 -- request for more information from a user/role.
1820 elsif (g_moreinfo = 'REQ') then
1821 -- Encode any special characters
1822 encoded_tag := UrlEncode(n_tag||'[3]');
1823
1824 -- ankung (placing role between the '')
1825 -- body := body || g_moreInfoFrom ||': ''''';
1826 -- body := body || g_newLine;
1827 body := body || g_moreInfoFrom;
1828 body := body || ': '||wf_mail.g_open_html_delimiter;
1829
1830 l_requestee := GetMoreInfoLOV(nid, g_to_role);
1831
1832 if (l_requestee is null) then
1833 l_requestee := g_moreInfoRequestee;
1834 end if;
1835 body := body || wf_notification.SubstituteSpecialChars(l_requestee);
1836 -- body := body || GetMoreInfoLOV(nid, g_to_role);
1837
1838 -- ankung (continuation of above)
1839 body := body || wf_mail.g_close_html_delimiter;
1840
1841 -- sacsharm commented out, too much space
1842 -- body := body || g_newLine;
1843 body := body || g_newLine;
1844 body := body || g_moreInfoQPrompt;
1845
1846 -- ankung (removing <)
1847 -- body := body || ': ''<';
1848 body := body || ': '||wf_mail.g_open_html_delimiter;
1849
1850 body := body || g_moreInfoQuestion;
1851
1852 -- ankung (removing >)
1853 -- body := body || '>''';
1854 body := body || wf_mail.g_close_html_delimiter;
1855
1856 -- sacsharm commented out, too much space
1857 -- body := body || g_newLine;
1858 body := body || g_newLine;
1859 body := UrlEncode(body);
1860 buffer := buffer ||'&'||'nbsp;'||'&'||'nbsp;'||
1861 '<A class="OraLink" HREF="mailto:'||reply_to||'?subject=%20'||
1862 UrlEncode(g_moreInfoRequested)||':%20'||
1863 UrlEncode(subject)||'&'||'body=%20'||body||
1864 '%0D%0A%0D%0A'||encoded_tag||'">'||
1865 '<FONT size=+1><B>'||g_moreInfoSubject||
1866 '</FONT></B>'||'</A>';
1867 end if;
1868 return buffer;
1869 exception
1870 when others then
1871 wf_core.context('Wf_Mail', 'GetMoreInfoMailTo', to_char(nid));
1872 raise;
1873 end GetMoreInfoMailTo;
1874
1875
1876 -- GetMailToBody (PRIVATE) - Construct the mailto body part.
1877 -- IN
1878 -- notification id
1879 -- One of the Action(Result) attribute answer
1880 -- RETURN
1881 -- mailto html tag with the subject and body
1882 --
1883 -- <<<<<< Deprecated : NOT IN USE, instead procudre GetMailToBody being used >>>>>>>
1884 --
1885 function GetMailToBody(nid in number,
1886 result_answer in varchar2) return varchar2
1887 is
1888 cursor c1 is
1889 select WMA.NAME, WMA.DISPLAY_NAME, WMA.DESCRIPTION, WMA.TYPE, WMA.FORMAT,
1890 decode(WMA.TYPE,
1891 'VARCHAR2', decode(WMA.FORMAT,
1892 '', WNA.TEXT_VALUE,
1893 substr(WNA.TEXT_VALUE, 1, to_number(WMA.FORMAT))),
1894 'NUMBER', decode(WMA.FORMAT,
1895 '', to_char(WNA.NUMBER_VALUE),
1896 to_char(WNA.NUMBER_VALUE, WMA.FORMAT)),
1897 'DATE', decode(WMA.FORMAT,
1898 '', to_char(WNA.DATE_VALUE),
1899 to_char(WNA.DATE_VALUE, WMA.FORMAT)),
1900 'LOOKUP', WNA.TEXT_VALUE,
1901 WNA.TEXT_VALUE) VALUE
1902 from WF_NOTIFICATION_ATTRIBUTES WNA,
1903 WF_NOTIFICATIONS WN,
1904 WF_MESSAGE_ATTRIBUTES_VL WMA
1905 where WNA.NOTIFICATION_ID = nid
1906 and WN.NOTIFICATION_ID = WNA.NOTIFICATION_ID
1907 and WN.MESSAGE_TYPE = WMA.MESSAGE_TYPE
1908 and WN.MESSAGE_NAME = WMA.MESSAGE_NAME
1909 and WMA.NAME = WNA.NAME
1910 and WMA.SUBTYPE = 'RESPOND'
1911 and WMA.TYPE not in ('FORM', 'URL')
1912 order by decode(WMA.NAME, 'RESULT', -100, WMA.SEQUENCE);
1913
1914 buffer varchar2(32000);
1915 begin
1916
1917 -- for each response variable
1918 for rec in c1 loop
1919 -- Print description
1920 if ((rec.name <> 'RESULT') or (result_answer = 'Respond')) then
1921 if (rec.description is not null) then
1922 buffer := buffer||WordWrap(rec.description, 0);
1923 buffer := buffer||g_newLine;
1924 end if;
1925 end if;
1926
1927 -- Print prompt
1928 buffer := buffer||rec.display_name||': '||wf_mail.g_open_html_delimiter;
1929
1930 -- Preseed the answer so that recipient does not have to type in manually.
1931 if ((rec.name = 'RESULT') and (result_answer <> 'Respond')) then
1932 rec.value := result_answer;
1933 end if;
1934
1935 -- Print field
1936 if (rec.type = 'LOOKUP') then
1937 -- LOOKUPs: show displayed meaning, list of choices
1938 buffer := buffer || GetLovMeaning(rec.format, rec.value) ||
1939 wf_mail.g_close_html_delimiter|| g_newLine;
1940 if (rec.name <> 'RESULT' ) then
1941 buffer := buffer || GetLovList(rec.format);
1942 end if;
1943 else
1944 -- VARCHAR2, NUMBER, or DATE: use value directly.
1945 buffer := buffer || rec.value ||wf_mail.g_close_html_delimiter||
1946 g_newLine;
1947 end if;
1948
1949 buffer := buffer || g_newLine;
1950 end loop;
1951
1952 buffer := UrlEncode(buffer);
1953
1954 return buffer;
1955
1956 exception
1957 when others then
1958 wf_core.context('WF_MAIL', 'GetMailToBody', to_char(nid));
1959 raise;
1960 end GetMailToBody;
1961
1962 -- GetMailToBody (PRIVATE) - Construct the mailto body part.
1963 -- IN
1964 -- notification id
1965 -- One of the Action(Result) attribute answer
1966 -- RETURN
1967 -- mailto html tag with the subject and body
1968 procedure GetMailToBody(nid in number,
1969 result_answer in varchar2,
1970 doc in out NOCOPY CLOB)
1971 is
1972 cursor c1 is
1973 select WMA.NAME, WMA.DISPLAY_NAME, WMA.DESCRIPTION, WMA.TYPE, WMA.FORMAT,
1974 decode(WMA.TYPE,
1975 'VARCHAR2', decode(WMA.FORMAT,
1976 '', WNA.TEXT_VALUE,
1977 substr(WNA.TEXT_VALUE, 1, to_number(WMA.FORMAT))),
1978 'NUMBER', decode(WMA.FORMAT,
1979 '', to_char(WNA.NUMBER_VALUE),
1980 to_char(WNA.NUMBER_VALUE, WMA.FORMAT)),
1981 --'DATE', decode(WMA.FORMAT,
1982 -- '', to_char(WNA.DATE_VALUE),
1983 -- to_char(WNA.DATE_VALUE, WMA.FORMAT)),
1984 -- <<SSTOMAR>> bug 8430385
1985 -- 'DATE', wf_notification_util.GetCalendarDate(nid, WNA.DATE_VALUE, WMA.FORMAT, true),
1986 --
1987 'LOOKUP', WNA.TEXT_VALUE,
1988 WNA.TEXT_VALUE) VALUE,
1989 WNA.DATE_VALUE -- << sstomar: bug8430385 >>
1990 from WF_NOTIFICATION_ATTRIBUTES WNA,
1991 WF_NOTIFICATIONS WN,
1992 WF_MESSAGE_ATTRIBUTES_VL WMA
1993 where WNA.NOTIFICATION_ID = nid
1994 and WN.NOTIFICATION_ID = WNA.NOTIFICATION_ID
1995 and WN.MESSAGE_TYPE = WMA.MESSAGE_TYPE
1996 and WN.MESSAGE_NAME = WMA.MESSAGE_NAME
1997 and WMA.NAME = WNA.NAME
1998 and WMA.SUBTYPE = 'RESPOND'
1999 and WMA.TYPE not in ('FORM', 'URL')
2000 order by decode(WMA.NAME, 'RESULT', -100, WMA.SEQUENCE);
2001
2002 str_buffer varchar2(32000);
2003 --buffer CLOB;
2004 -- bufferIdx pls_integer;
2005
2006 begin
2007 -- bufferIdx := wf_temp_lob.getLob(g_LOBTable);
2008
2009 -- for each response variable
2010 for rec in c1 loop
2011 -- Print description
2012 if ((rec.name <> 'RESULT') or (result_answer = 'Respond')) then
2013 -- For DATE, TEXT , NUMBER Attributes.
2014 if (rec.description is not null) then
2015 str_buffer := str_buffer||WordWrap(rec.description, 0);
2016 str_buffer := str_buffer||g_newLine;
2017 end if;
2018 end if;
2019
2020 -- Print prompt
2021 str_buffer := str_buffer||rec.display_name||': '||
2022 wf_mail.g_open_html_delimiter;
2023
2024 -- Preseed the answer so that recipient does not have
2025 -- to type in manually.
2026
2027 if ((rec.name = 'RESULT') and (result_answer <> 'Respond')) then
2028 -- result_answer holds default 'lookup code' of RESULT Attr from caller.
2029 rec.value := result_answer;
2030 end if;
2031
2032 -- Print field
2033 if (rec.type = 'LOOKUP') then
2034 -- LOOKUPs: show displayed meaning, list of choices
2035 -- e.g. 'WFSTD_APPROVAL', 'APPROVED' being passed to GetLovMeaning
2036 str_buffer := str_buffer || GetLovMeaning(rec.format, rec.value)
2037 || wf_mail.g_close_html_delimiter || g_newLine;
2038
2039 if (rec.name <> 'RESULT' ) then
2040 str_buffer := str_buffer || GetLovList(rec.format);
2041 end if;
2042
2043 -- <<sstomar>> bug8430385
2044 elsif (rec.type = 'DATE' AND rec.DATE_VALUE is not null) THEN
2045 str_buffer := str_buffer
2046 || wf_notification_util.GetCalendarDate(nid, rec.DATE_VALUE, rec.FORMAT, false)
2047 || wf_mail.g_close_html_delimiter
2048 || g_newLine;
2049 else
2050 -- NOTE: <<sstomar>> we can handle DATE type Attr. here also, if required.
2051 -- VARCHAR2, NUMBER, or DATE: use value directly.
2052 str_buffer := str_buffer || rec.value
2053 || wf_mail.g_close_html_delimiter||g_newLine;
2054 end if;
2055
2056 str_buffer := str_buffer || g_newLine;
2057
2058 if(length(str_buffer) > 24000) then
2059 str_buffer := UrlEncode(str_buffer);
2060 DBMS_LOB.writeAppend(lob_loc => doc,
2061 amount => length(str_buffer),
2062 buffer => str_buffer);
2063 str_buffer := '';
2064 end if;
2065
2066 -- DBMS_LOB.writeAppend(g_LOBTable(bufferIdx).temp_lob,
2067 -- length(str_buffer),
2068 -- str_buffer);
2069 -- str_buffer := '';
2070
2071 end loop;
2072 if(length(str_buffer) > 0) then
2073 str_buffer := UrlEncode(str_buffer);
2074 DBMS_LOB.writeAppend(lob_loc => doc,
2075 amount => length(str_buffer),
2076 buffer => str_buffer);
2077 str_buffer := '';
2078 end if;
2079 -- DBMS_LOB.Append(doc, g_LOBTable(bufferIdx).temp_lob);
2080 -- wf_temp_lob.releaseLob(g_LOBTable, bufferIdx);
2081
2082 exception
2083 when others then
2084 -- wf_temp_lob.releaseLob(g_LOBTable, bufferIdx);
2085 wf_core.context('WF_MAIL', 'GetMailToBody', to_char(nid));
2086 raise;
2087 end GetMailToBody;
2088
2089 -- GetMailTo - Construct MailTo Section (PRIVATE)
2090 -- IN
2091 -- notification id
2092 -- notification tag
2093 -- notification reply to
2094 -- notification subject
2095 -- RETURN
2096 -- mailto html tag with the subject and body
2097 --
2098 -- <<<<<<< @Deprecated : NOT IN USE, procedure GetMailTo is being used <<sstomar>>>>>>
2099 --
2100 function GetMailTo(nid in number,
2101 n_tag in varchar2,
2102 reply_to in varchar2,
2103 subject in varchar2) return varchar2
2104 is
2105 -- SQL Statement for fetching URL RESPONSE attributes.
2106 cursor c1 is
2107 select WMA.NAME, WMA.DISPLAY_NAME, WNA.TEXT_VALUE, WMA.DESCRIPTION
2108 from WF_NOTIFICATION_ATTRIBUTES WNA,
2109 WF_NOTIFICATIONS WN,
2110 WF_MESSAGE_ATTRIBUTES_VL WMA
2111 where WNA.NOTIFICATION_ID = nid
2112 and WN.NOTIFICATION_ID = WNA.NOTIFICATION_ID
2113 and WN.MESSAGE_TYPE = WMA.MESSAGE_TYPE
2114 and WN.MESSAGE_NAME = WMA.MESSAGE_NAME
2115 and WMA.NAME = WNA.NAME
2116 and WMA.SUBTYPE = 'RESPOND'
2117 and WMA.TYPE = 'URL'
2118 order by WMA.SEQUENCE;
2119
2120 lov varchar2(64);
2121 lov_list varchar2(240);
2122 buffer varchar2(32000);
2123 auto_answer varchar2(64);
2124 newline_pos number;
2125 disp_name varchar2(80);
2126 attr_type varchar2(8);
2127 attr_format varchar2(240);
2128 attr_value varchar2(32000);
2129 attr_desc varchar2(240);
2130 encoded_tag varchar2(240);
2131
2132 begin
2133
2134 -- Clear buffer
2135 buffer := '';
2136
2137 -- URL RESPONSE attributes overrides the normal RESULT attributes.
2138 -- So, my goal here is to check for this case.
2139 -- URL RESPONSE attributes is going to appear as a anchor and don't have
2140 -- to construct the MAILTO html tag stuff that we do for the normal
2141 -- RESULT attribute.
2142
2143 -- NOTE: Please do know that I don't want to destablize the existing code
2144 -- for the normal RESULT attribute MAILTO handleing so that I am coding
2145 -- these two cases seperately.
2146 -- for each response variable
2147 for rec in c1 loop
2148 buffer := buffer||'<P>';
2149 if (rec.description is not null) then
2150 buffer := buffer||rec.description||'<P>';
2151 end if;
2152 buffer := buffer|| '<A class="OraLink" HREF="'||wf_notification.geturltext(rec.text_value, nid)||'" target="_top">';
2153 buffer := buffer||'<FONT size=+1> <B>'||rec.display_name;
2154 buffer := buffer||'</B></FONT>'||'</A>';
2155 buffer := buffer||g_newLine;
2156 end loop;
2157
2158 if (buffer is not null) then
2159 return(buffer);
2160 end if;
2161
2162 --
2163 -- Normal RESULT attribute handling
2164 --
2165 begin
2166 select WMA.DISPLAY_NAME, WMA.TYPE, WMA.FORMAT,
2167 decode(WMA.TYPE,
2168 'VARCHAR2', decode(WMA.FORMAT,
2169 '', WNA.TEXT_VALUE,
2170 substr(WNA.TEXT_VALUE, 1, to_number(WMA.FORMAT))),
2171 'NUMBER', decode(WMA.FORMAT,
2172 '', to_char(WNA.NUMBER_VALUE),
2173 to_char(WNA.NUMBER_VALUE, WMA.FORMAT)),
2174 'DATE', decode(WMA.FORMAT,
2175 '', to_char(WNA.DATE_VALUE),
2176 to_char(WNA.DATE_VALUE, WMA.FORMAT)),
2177 'LOOKUP', WNA.TEXT_VALUE,
2178 WNA.TEXT_VALUE), WMA.DESCRIPTION
2179 into disp_name, attr_type, attr_format, attr_value, attr_desc
2180 from WF_NOTIFICATION_ATTRIBUTES WNA,
2181 WF_NOTIFICATIONS WN,
2182 WF_MESSAGE_ATTRIBUTES_VL WMA
2183 where WNA.NOTIFICATION_ID = nid
2184 and WN.NOTIFICATION_ID = WNA.NOTIFICATION_ID
2185 and WN.MESSAGE_TYPE = WMA.MESSAGE_TYPE
2186 and WN.MESSAGE_NAME = WMA.MESSAGE_NAME
2187 and WMA.NAME = WNA.NAME
2188 and WMA.SUBTYPE = 'RESPOND'
2189 and WMA.NAME = 'RESULT'
2190 and WMA.TYPE not in ('FORM', 'URL');
2191
2192 -- We can only construct answer button or mailto link if is lookup
2193 if (attr_type <> 'LOOKUP') then
2194 auto_answer := 'Respond';
2195 else
2196 -- If is LOOKUP RESULT attribute, we need to show the description here.
2197 if (attr_desc is not null) then
2198 buffer := buffer||'<P>'||attr_desc;
2199 end if;
2200 auto_answer := attr_format;
2201 end if;
2202
2203 exception
2204 when no_data_found then
2205 auto_answer := 'Respond';
2206 end;
2207
2208 -- Encode any special characters
2209 encoded_tag := UrlEncode(n_tag);
2210
2211 -- Construct mailto syntax
2212 buffer := buffer||'<P>'||disp_name||': <A class="OraLink" HREF="mailto:'||reply_to||
2213 '?subject=%20'||
2214 UrlEncode(subject)||'&'||'body=%20';
2215
2216 if (auto_answer = 'Respond') then
2217 buffer := buffer||GetMailToBody(nid, auto_answer)||
2218 '%0D%0A%0D%0A'||encoded_tag||'">'||'<FONT size=+1><B>'||
2219 g_noResult||'</B></FONT>'||'</A>';
2220 else
2221 --
2222 --
2223 lov_list := GetLovListInternal(auto_answer);
2224 lov_list := substr(lov_list, 1, length(lov_list)-1);
2225
2226 while (lov_list is not null) loop
2227 newline_pos := instr(lov_list, g_newLine);
2228
2229 if (newline_pos = 0) then
2230 lov := lov_list;
2231 else
2232 lov := substr(lov_list, 1, newline_pos - 1);
2233 end if;
2234
2235 buffer := buffer||GetMailToBody(nid, lov);
2236 buffer :=buffer||'%0D%0A%0D%0A'||encoded_tag||'">'||
2237 '<FONT size=+1><B>'||GetLovMeaning(attr_format, lov)||
2238 '</FONT></B>'||'</A>';
2239 if (newline_pos = 0) then
2240 lov_list := null;
2241 if (g_moreinfo = 'REQ') then
2242 buffer := buffer || GetMoreInfoMailTo(nid, n_tag,
2243 reply_to, subject);
2244
2245
2246 end if;
2247 else
2248 lov_list := substr(lov_list, newline_pos+1,
2249 length(lov_list) - newline_pos);
2250 buffer := buffer||g_newLine;
2251 buffer := buffer||'&'||'nbsp;'||'&'||'nbsp;'||
2252 '<A class="OraLink" HREF="mailto:'||reply_to||
2253 '?subject=%20'||UrlEncode(subject)||'&'||'body=%20';
2254 end if;
2255 end loop;
2256
2257 end if;
2258
2259 return(buffer);
2260
2261 exception
2262 when others then
2263 wf_core.context('WF_MAIL', 'GetMailTo', nid);
2264 raise;
2265
2266 end GetMailTo;
2267
2268
2269 -- Substitute - replaces standard tokens in mail text
2270 function Substitute(
2271 txt in varchar2,
2272 n_nid in number,
2273 n_code in varchar2,
2274 n_status in varchar2,
2275 n_to_role in varchar2,
2276 r_dname in varchar2,
2277 r_email in varchar2,
2278 n_start_date in date,
2279 n_due_date in date,
2280 n_end_date in date,
2281 n_from_user in varchar2,
2282 n_priority in number,
2283 n_comment in varchar2,
2284 m_subject in varchar2,
2285 m_header in varchar2,
2286 m_body in varchar2,
2287 err_name in varchar2,
2288 err_message in varchar2,
2289 err_invalid in varchar2,
2290 err_expected in varchar2,
2291 n_timezone in varchar2) return varchar2
2292 as
2293 stxt varchar2(32000);
2294 n_due_date_text varchar2(64);
2295 n_start_date_text varchar2(64);
2296 n_end_date_text varchar2(64);
2297 n_priority_text varchar2(240);
2298
2299 begin
2300 -- BLAF recommends displaying date with the TIME element
2301
2302 -- n_due_date_text := to_char(n_due_date, Wf_Notification.g_nls_date_mask);
2303 -- n_start_date_text := to_char(n_start_date, Wf_Notification.g_nls_date_mask);
2304 -- <sstomar>>: 7578922
2305 n_start_date_text := wf_notification_util.GetCalendarDate(n_nid, n_start_date, null, true);
2306 n_due_date_text := wf_notification_util.GetCalendarDate(n_nid, n_due_date, null, true);
2307
2308 n_end_date_text := wf_notification_util.GetCalendarDate(n_nid, n_end_date, null, true);
2309
2310 if (n_priority > 66) then
2311 --Bug 2774891 fix - sacsharm
2312 --n_priority_text := wf_core.substitute('WFTKN', 'HIGH');
2313 n_priority_text := wf_core.substitute('WFTKN', 'LOW');
2314 elsif (n_priority > 33) then
2315 n_priority_text := wf_core.substitute('WFTKN', 'NORMAL');
2316 else
2317 --Bug 2774891 fix - sacsharm
2318 --n_priority_text := wf_core.substitute('WFTKN', 'LOW');
2319 n_priority_text := wf_core.substitute('WFTKN', 'HIGH');
2320 end if;
2321
2322 stxt := substrb(txt, 1, 32000);
2323 stxt := substrb(replace(stxt, '&'||'NOTIFICATION_ID', to_char(n_nid)), 1,
2324 32000);
2325 stxt := substrb(replace(stxt, '&'||'NOTIFICATION', n_code), 1, 32000);
2326 stxt := substrb(replace(stxt, '&'||'STATUS', n_status), 1, 32000);
2327 stxt := substrb(replace(stxt, '&'||'TO_DNAME', r_dname), 1, 32000);
2328 stxt := substrb(replace(stxt, '&'||'TO_EMAIL', r_email), 1, 32000);
2329 stxt := substrb(replace(stxt, '&'||'TO', n_to_role), 1, 32000);
2330 stxt := substrb(replace(stxt, '&'||'PRIORITY', n_priority_text), 1, 32000);
2331 stxt := substrb(replace(stxt, '&'||'START_DATE', n_start_date_text), 1, 32000);
2332 stxt := substrb(replace(stxt, '&'||'DUE_DATE', n_due_date_text), 1, 32000);
2333
2334 -- stxt := substrb(replace(stxt, '&'||'END_DATE', n_end_date), 1, 32000);
2335
2336 stxt := substrb(replace(stxt, '&'||'END_DATE', n_end_date_text), 1, 32000);
2337
2338
2339 -- Bug 2094159 substituting sender in email notification for From label
2340 stxt := substrb(replace(stxt, '&'||'SENDER', n_from_user), 1, 32000);
2341 stxt := substrb(replace(stxt, '&'||'COMMENT', n_comment), 1, 32000);
2342 stxt := substrb(replace(stxt, '&'||'TIMEZONE', n_timezone), 1, 32000);
2343 stxt := substrb(replace(stxt, '&'||'SUBJECT', m_subject), 1, 32000);
2344 stxt := substrb(replace(stxt, '&'||'HEADER', m_header), 1, 32000);
2345 stxt := substrb(replace(stxt, '&'||'BODY', m_body), 1, 32000);
2346 stxt := substrb(replace(stxt, '&'||'MAIL_ERROR_NAME', err_name), 1, 32000);
2347 stxt := substrb(replace(stxt, '&'||'MAIL_ERROR_MESSAGE', err_message),
2348 1, 32000);
2349 stxt := substrb(replace(stxt, '&'||'MAIL_VALUE_FOUND', err_invalid), 1, 32000);
2350 stxt := substrb(replace(stxt, '&'||'MAIL_EXP_VALUES', err_expected), 1, 32000);
2351
2352 return stxt;
2353 end;
2354
2355 -- GetWarning - get warning messages
2356 --
2357 -- IN
2358 -- Template
2359 -- unsolicited from
2360 -- unsolicited subject
2361 -- unsolicited body
2362 -- OUT
2363 -- message subject
2364 -- message body (text)
2365 -- message body (html)
2366 procedure GetWarning(
2367 template in varchar2,
2368 ufrom in varchar2,
2369 usubject in varchar2,
2370 ubody in varchar2,
2371 subject out NOCOPY varchar2,
2372 text_body_text out NOCOPY varchar2,
2373 html_body_text out NOCOPY varchar2)
2374 as
2375 t_subject varchar2(240);
2376 t_text_body varchar2(32000);
2377 t_html_body varchar2(32000);
2378 l_pos integer;
2379 l_templ_val varchar2(1000);
2380 itemType varchar2(8);
2381 messageName varchar2(30);
2382
2383 begin
2384
2385 l_pos := instrb(template, ':', 1);
2386 if l_pos > 0 then
2387 itemType := substrb(template, 1, l_pos-1);
2388 messageName := substrb(template, l_pos+1);
2389 else
2390 itemType := 'WFMAIL';
2391 messageName := 'WARNING';
2392 end if;
2393
2394 -- Get template 'WARNING'
2395 begin
2396 select SUBJECT, BODY, HTML_BODY
2397 into t_subject, t_text_body, t_html_body
2398 from WF_MESSAGES_VL
2399 where NAME = messageName
2400 and TYPE = itemType;
2401 exception
2402 when no_data_found then
2403 wf_core.token('NAME', messageName);
2404 wf_core.token('TYPE', itemType);
2405 wf_core.raise('WFNTF_MESSAGE');
2406 end;
2407
2408 -- Substitute USER_NAME with role display name
2409 t_text_body := substrb(replace(t_text_body, '&'||'UFROM', ufrom), 1, 32000);
2410 t_text_body := substrb(replace(t_text_body, '&'||'USUBJECT',
2411 nvl(usubject, ' ')), 1, 32000);
2412 t_text_body := substrb(replace(t_text_body, '&'||'UBODY',
2413 nvl(ubody, ' ')), 1, 32000);
2414
2415 -- Substitute USER_NAME with role display name
2416 t_html_body := substrb(replace(t_html_body, '&'||'UFROM', ufrom), 1, 32000);
2417 t_html_body := substrb(replace(t_html_body, '&'||'USUBJECT',
2418 nvl(usubject, ' ')), 1, 32000);
2419 t_html_body := substrb(replace(t_html_body, '&'||'UBODY',
2420 nvl(ubody, ' ')), 1, 32000);
2421
2422 subject := t_subject;
2423 text_body_text := t_text_body;
2424 html_body_text := t_html_body;
2425
2426 exception
2427 when others then
2428 wf_core.context('WF_MAIL', 'GetWarning', ufrom, usubject, ubody);
2429 raise;
2430 end GetWarning;
2431
2432
2433
2434 -- GetWarning - get warning messages
2435 --
2436 -- IN
2437 -- unsolicited from
2438 -- unsolicited subject
2439 -- unsolicited body
2440 -- OUT
2441 -- message subject
2442 -- message body (text)
2443 -- message body (html)
2444 procedure GetWarning(
2445 ufrom in varchar2,
2446 usubject in varchar2,
2447 ubody in varchar2,
2448 subject out NOCOPY varchar2,
2449 text_body_text out NOCOPY varchar2,
2450 html_body_text out NOCOPY varchar2)
2451 as
2452 begin
2453 wf_mail.GetWarning('WFMAIL:WARNING', ufrom, usubject, ubody, subject,
2454 text_body_text, html_body_text);
2455 end GetWarning;
2456
2457 -- GetTemplateName - Get the template type and name based on the
2458 -- status of the notification and whether, or not,
2459 -- the name has been overridden in the configuration
2460 -- parameters or on the message definition itself.
2461 --
2462 -- IN
2463 -- Notification ID
2464 -- Notification status
2465 -- Notification Mail status
2466 -- OUT
2467 -- Item type for template
2468 -- Message name for template
2469 procedure getTemplateName(nid in number, n_status in varchar2,
2470 n_mstatus in varchar2, t_type out NOCOPY varchar2,
2471 t_name out NOCOPY varchar2)
2472 is
2473
2474 colPos number;
2475 altTempl varchar2(100);
2476 fyi pls_integer;
2477 mType varchar2(8);
2478 mName varchar2(30);
2479 validTemplate pls_integer;
2480 inAttr varchar2(1);
2481
2482 begin
2483 t_type := 'WFMAIL'; -- Set the default type;
2484 wf_mail.Set_FYI_Flag(FALSE);
2485
2486 -- Get template name
2487 if (n_status = 'OPEN') then
2488 t_name := 'OPEN_'||n_mstatus;
2489 else
2490 t_name := n_status;
2491 end if;
2492
2493 if (g_moreinfo = 'SUB' and n_mstatus in ('MAIL','INVALID')) then
2494 if (n_mstatus = 'MAIL') then
2495 t_name := 'OPEN_MORE_INFO';
2496 elsif(n_mstatus = 'INVALID') then
2497 t_name := 'OPEN_INVALID_MORE_INFO';
2498 end if;
2499 end if;
2500
2501 -- Check if this is FYI type of message
2502 if (t_name = 'OPEN_MAIL') then
2503 begin
2504 select 1 into fyi
2505 from dual
2506 where not exists (select NULL
2507 from WF_MESSAGE_ATTRIBUTES MA,
2508 WF_NOTIFICATIONS N
2509 where N.NOTIFICATION_ID = nid
2510 and MA.MESSAGE_TYPE = N.MESSAGE_TYPE
2511 and MA.MESSAGE_NAME = N.MESSAGE_NAME
2512 and MA.SUBTYPE = 'RESPOND');
2513 -- Set the template name to FYI
2514 t_name := t_name||'_FYI';
2515 wf_mail.Set_FYI_Flag(TRUE);
2516
2517 exception
2518 when NO_DATA_FOUND then
2519 -- If a different mail template name is specified, it took
2520 -- precedence over direct response.
2521 if (g_template is not null) then
2522 t_name := g_template;
2523
2524 -- This is a response required notification.
2525 -- Qualify if DIRECT_RESPONSE=Y
2526 elsif wf_mail.direct_response then
2527 t_name := t_name || '_DIRECT';
2528 end if;
2529 end;
2530 end if;
2531
2532 select message_type, message_name
2533 into mType, mName
2534 from wf_notifications
2535 where notification_id = nid;
2536
2537 -- Now that the template name has been derrived, see
2538 -- if the default value has been overridden.
2539 altTempl := WF_MAILER_PARAMETER.getValueForCorr(nid, mType || ':'|| mName, t_name, inAttr);
2540 colPos := instrb(altTempl, ':', 1);
2541 if colPos > 0 then
2542 t_type := substrb(altTempl, 1, colPos -1);
2543 t_name := substrb(altTempl, colPos + 1, length(altTempl)-colPos);
2544 -- 3438107 Validate the template name incase the value from the
2545 -- message attribute if used contains a typo
2546 begin
2547 select 1
2548 into validTemplate
2549 from WF_MESSAGES_VL
2550 where NAME = t_name
2551 and TYPE = t_type;
2552 exception
2553 when NO_DATA_FOUND then
2554 wf_core.context('WF_MAIL','getTemplateName',
2555 'nid => '||to_char(nid),
2556 'n_status => '||n_status,
2557 'n_mstatus => '||n_mStatus,
2558 't_type => '||t_type,
2559 't_name => '||t_name);
2560 wf_core.token('TYPE', t_type);
2561 wf_core.token('NAME', t_name);
2562 wf_core.raise('WFMLR_NOTEMPLATE');
2563 end;
2564 end if;
2565
2566 exception
2567 when others then
2568 WF_CORE.Context('WF_MAIL','getTemplateName',to_char(nid), n_status,
2569 n_mstatus, t_type, t_name);
2570 raise;
2571 end getTemplateName;
2572
2573 -- ProcessSignaturePolicy (PRIVATE) Bug 2375920
2574 -- Processes mail message based on the signature policy requirement
2575 -- for the notification if the notification requires a response
2576 -- IN
2577 -- notification id
2578 -- signature policy for the notification
2579 -- notification status
2580 -- notification mail mstatus
2581 -- access key
2582 -- node
2583 -- OUT
2584 -- template name
2585 -- template type
2586 -- NID string
2587 procedure ProcessSignaturePolicy(
2588 nid in number,
2589 n_sig_policy in varchar2,
2590 n_status in varchar2,
2591 n_mstatus in varchar2,
2592 n_key in varchar2,
2593 node in varchar2,
2594 t_type out NOCOPY varchar2,
2595 t_name out NOCOPY varchar2,
2596 n_nid_str out NOCOPY varchar2)
2597 as
2598 l_sec_policy varchar2(100);
2599 begin
2600 -- signature policy is DEFAULT or NULL means no password is required
2601 -- to respond to the notification
2602 t_type := 'WFMAIL';
2603
2604 -- If the content is secure, just dont send anything pertaining to the notification
2605 -- other than the nid.
2606 Wf_Mail.ProcessSecurityPolicy(nid, l_sec_policy, t_name);
2607 if (t_name is not null) then
2608 n_nid_str := 'NID '||to_char(nid);
2609 return;
2610 end if;
2611
2612 Wf_Notification.GetSignatureRequired(n_sig_policy, nid, g_sig_required,
2613 g_fwk_flavor, g_email_flavor, g_render);
2614
2615 -- No signature required for this notification
2616 if (g_sig_required = 'N') then
2617 getTemplateName(nid, n_status, n_mstatus, t_type, t_name);
2618
2619 if (g_moreinfo = 'SUB' and n_mstatus in ('MAIL','INVALID')) then
2620 n_nid_str := 'NID['||to_char(nid)||'/'||n_key||'@'||node||']'||'[4]';
2621 return;
2622 end if;
2623
2624
2625 -- construct the NID string for the notification
2626 if (wf_mail.direct_response) then
2627 n_nid_str := 'NID['||to_char(nid)||'/'||n_key||'@'||node||']'||'[2]';
2628 else
2629 n_nid_str := 'NID['||to_char(nid)||'/'||n_key||'@'||node||']';
2630 end if;
2631 elsif (g_sig_required = 'Y') then
2632 -- OPEN_SIGN is for warning that email response will not be processed
2633 -- for notifications requiring password signature
2634 if (n_status = 'OPEN') then
2635 if (n_mstatus = 'INVALID') then
2636 t_name := 'OPEN_SIGN';
2637 else
2638 -- Template to inform the user that the ntf requires a signature
2639 -- ** not sure if signing through email will be supported in future **
2640 t_name := 'OPEN_MAIL_SIGNATURE';
2641 end if;
2642 else
2643 t_name := n_status;
2644 end if;
2645 n_nid_str := 'NID ' || to_char(nid);
2646 else
2647 wf_core.token('NID', to_char(nid));
2648 wf_core.token('POLICY', n_sig_policy);
2649 wf_core.raise('WFMLR_INVALID_SIG_POLICY');
2650 end if;
2651
2652 exception
2653 when others then
2654 wf_core.context('WF_MAIL', 'ProcessSignaturePolicy', to_char(nid));
2655 raise;
2656 end ProcessSignaturePolicy;
2657
2658 -- Returns TRUE if the language is Bi directional
2659 -- Provided as a function to centralise the management of determining
2660 -- the direction for the text.
2661 function isBiDi(lang in varchar2) return boolean
2662 is
2663 begin
2664 if upper(lang) in ('ARABIC','HEBREW') then
2665 return true;
2666 else
2667 return false;
2668 end if;
2669 end isBiDi;
2670
2671 -- Gets the table of header attributes to be
2672 -- displayed before the body
2673 -- Introduced with BUG 2659681
2674 -- IN
2675 -- nid - Notification ID
2676 -- notification_pref The document type to be displayed
2677 procedure GetHeaderTable(document_id in varchar2,
2678 display_type in varchar2,
2679 document in out NOCOPY varchar2,
2680 document_type in out NOCOPY varchar2)
2681 is
2682 cursor headers(nid in Number) is
2683 select WMA.NAME
2684 from WF_MESSAGE_ATTRIBUTES_VL WMA,
2685 WF_NOTIFICATION_ATTRIBUTES WNA,
2686 WF_NOTIFICATIONS WN
2687 where WNA.NOTIFICATION_ID = nid
2688 and WN.NOTIFICATION_ID = WNA.NOTIFICATION_ID
2689 and WN.MESSAGE_TYPE = WMA.MESSAGE_TYPE
2690 and WN.MESSAGE_NAME = WMA.MESSAGE_NAME
2691 and WMA.NAME = WNA.NAME
2692 and WMA.NAME like '#HDR%'
2693 and (WNA.TEXT_VALUE is not null OR
2694 WNA.NUMBER_VALUE is not null OR
2695 WNA.DATE_VALUE is not null)
2696 order by WMA.SEQUENCE;
2697
2698 nid number;
2699 attrList varchar2(4000);
2700 cells wf_notification.tdType;
2701 j pls_integer;
2702 pos pls_integer;
2703 language varchar2(30);
2704 headerTable varchar2(32000);
2705 l_dir varchar2(2);
2706 l_dirAttr varchar2(10);
2707
2708 l_due_date date;
2709 l_from_user varchar2(360);
2710 begin
2711
2712 pos := instrb(document_id, ':',1);
2713 language := substrb(document_id, 1, pos-1);
2714 nid := to_number(substrb(document_id, pos+1));
2715 if isBiDi(language) then
2716 l_dir := 'R';
2717 l_dirAttr := 'dir="RTL"';
2718 else
2719 l_dir := 'L';
2720 l_dirAttr := NULL;
2721 end if;
2722
2723 begin
2724 SELECT due_date, from_user
2725 INTO l_due_date, l_from_user
2726 FROM wf_notifications
2727 WHERE notification_id = nid;
2728 exception
2729 when no_data_found then
2730 wf_core.token('NID', to_char(nid));
2731 wf_core.raise('WFNTF_NID');
2732 end;
2733
2734 -- Cache the values of the product notification headers.
2735 attrList := '';
2736 for header in headers(nid) loop
2737 attrList := attrList || header.name || ',';
2738 end loop;
2739 if length(attrList) > 0 then
2740 attrList := substrb(attrList,1, length(attrList)-1);
2741 end if;
2742
2743 document := '';
2744 if display_type = g_ntfDocText then
2745 if length(attrList) > 0 then
2746 document := wf_notification.wf_msg_attr(nid, attrList, display_type);
2747 end if;
2748 elsif display_type = g_ntfDocHtml then
2749 document := '<TABLE width=100% valign="top" cellpadding="0" cellspacing="0" border="0" '||l_dirAttr||'>'||g_newLine;
2750 document := document || '<TR valign="top"><TD width=30%>';
2751 j := 1;
2752 if (l_from_user is not null) then
2753 cells(j) := 'E:'||g_from;
2754 j := j + 1;
2755 cells(j) := 'S12:';
2756 j := j + 1;
2757 cells(j) := 'S:'||'&'||'SENDER';
2758 j := j + 1;
2759 end if;
2760
2761 cells(j) := 'E:'||g_to;
2762 j := j + 1;
2763 cells(j) := 'S12:';
2764 j := j + 1;
2765 -- sacsharm bug 2897428 fix
2766 -- cells(j) := 'S:'||'&'||'TO';
2767 cells(j) := 'S:'||'&'||'TO_DNAME';
2768 j := j + 1;
2769
2770 cells(j) := 'E:'||g_beginDate;
2771 j := j + 1;
2772 cells(j) := 'S12:';
2773 j := j + 1;
2774 cells(j) := 'S:'||'&'||'START_DATE';
2775 j := j + 1;
2776
2777 if (l_due_date is not null) then
2778 cells(j) := 'E:'||g_dueDate2;
2779 j := j + 1;
2780 cells(j) := 'S12:';
2781 j := j + 1;
2782 cells(j) := 'S:'||'&'||'DUE_DATE';
2783 j := j + 1;
2784 end if;
2785
2786 cells(j) := 'E:'||g_Id;
2787 j := j + 1;
2788 cells(j) := 'S12:';
2789 j := j + 1;
2790 cells(j) := 'S:'||'&'||'NOTIFICATION_ID';
2791 wf_notification.NTF_Table(cells => cells, col => 3, type => 'N'||l_dir,
2792 rs => headerTable);
2793
2794 document := document || headerTable || g_newLine;
2795 document := document || '</TD><TD>' || g_newLine;
2796 if length(attrList) > 0 then
2797 wf_notification.set_ntf_table_type('N');
2798 wf_notification.set_ntf_table_direction(l_dir);
2799 document := document||wf_notification.wf_msg_attr(nid, attrList, display_type);
2800 wf_notification.set_ntf_table_type('V');
2801 end if;
2802 document := document || '</TD></TR></TABLE>'||g_newLine;
2803 else
2804 document := '';
2805 end if;
2806 document_type := display_type;
2807
2808 exception
2809 when others then
2810 wf_core.context('WF_MAIL','GetHeaderTable',document_id, display_type);
2811 raise;
2812 end GetHeaderTable;
2813
2814
2815 -- GetMessage - get email message data
2816 --
2817 -- IN
2818 -- notification id
2819 -- mailer node name
2820 -- web agent path
2821 -- OUT
2822 -- message subject
2823 -- message body (text)
2824 -- message body (html)
2825 -- NOTE
2826 -- This API was used by the C mailer which is now obsolete. This
2827 -- procedure is now considered deprecated.
2828 procedure GetMessage(
2829 nid in number,
2830 node in varchar2,
2831 agent in varchar2,
2832 replyto in varchar2,
2833 subject out NOCOPY varchar2,
2834 text_body out NOCOPY varchar2,
2835 html_body out NOCOPY varchar2,
2836 body_atth out NOCOPY varchar2,
2837 error_result in out NOCOPY varchar2)
2838 as
2839 n_status varchar2(8);
2840 n_mstatus varchar2(8);
2841 n_key varchar2(80);
2842 n_to_role varchar2(320);
2843 n_from_user varchar2(320); -- Bug 2094159
2844 n_due_date date;
2845 n_start_date date;
2846 n_end_date date;
2847 n_priority number;
2848 n_comment varchar2(4000);
2849 n_subject varchar2(2000);
2850 n_response varchar2(32000);
2851 n_text_body varchar2(32000);
2852 n_html_body varchar2(32000);
2853 n_direct varchar2(3);
2854 n_click_here varchar2(4000);
2855 n_disp_click varchar2(240);
2856 r_dname varchar2(360);
2857 r_email varchar2(2000);
2858 r_language varchar2(4000);
2859 r_territory varchar2(4000);
2860 r_ntf_pref varchar2(240);
2861 t_type varchar2(100);
2862 t_name varchar2(100);
2863 t_subject varchar2(240);
2864 t_text_body varchar2(4000);
2865 t_html_body varchar2(4000);
2866 t_headerText varchar2(32000);
2867 n_headerText varchar2(32000);
2868 n_timezone varchar2(230);
2869 t_headerHTML varchar2(32000);
2870 n_headerHTML varchar2(32000);
2871 m_html varchar2(32000);
2872 err_name varchar2(30);
2873 err_message varchar2(2000);
2874 err_stack varchar2(4000);
2875 fyi pls_integer;
2876 body_start pls_integer;
2877 body_end pls_integer;
2878 tag_pos pls_integer;
2879 dir_pos pls_integer;
2880 start_cnt pls_integer;
2881 end_cnt pls_integer;
2882 crpos pls_integer;
2883 str_length pls_integer;
2884 lnsize pls_integer;
2885 temp varchar2(32000);
2886 line varchar2(32000);
2887 buffer varchar2(32000);
2888 no_program_unit exception;
2889 pragma exception_init(no_program_unit, -6508);
2890 dummy varchar2(4000);
2891 -- Bug# 2301881 variables to handle invalid response error message
2892 err_invalid varchar2(1000);
2893 err_expected varchar2(1000);
2894 -- Bug 2395898 variable to check if response attr exists
2895 n_response_exists varchar2(1);
2896 -- Bug 2375920 variables to process message based on signature
2897 n_sig_policy varchar2(100);
2898 n_nid_str varchar2(200);
2899 -- bug 2282139 more info feature
2900 n_more_info_role varchar2(320);
2901 n_mailto varchar2(10000);
2902 n_html_history varchar2(32000);
2903 n_text_history varchar2(32000);
2904 n_last_ques varchar2(4000);
2905 n_dir varchar2(16);
2906
2907 begin
2908 -- Get notification information
2909 -- Bug 2094159 get from_user from wf_notifications
2910 begin
2911 select STATUS, MAIL_STATUS, ACCESS_KEY,
2912 RECIPIENT_ROLE, PRIORITY, USER_COMMENT,
2913 BEGIN_DATE, END_DATE, DUE_DATE, FROM_USER,
2914 MORE_INFO_ROLE
2915 into n_status, n_mstatus, n_key,
2916 n_to_role, n_priority, n_comment,
2917 n_start_date, n_end_date, n_due_date, n_from_user,
2918 n_more_info_role
2919 from WF_NOTIFICATIONS
2920 where NOTIFICATION_ID = nid;
2921 exception
2922 when no_data_found then
2923 wf_core.token('NID', to_char(nid));
2924 wf_core.raise('WFNTF_NID');
2925 end;
2926
2927 -- More information processing - bug 2282139
2928 g_moreinfo := NULL;
2929
2930 if (wf_mail.test_flag = TRUE) then
2931 n_mstatus := 'MAIL';
2932 if (n_status not in ('OPEN','CANCELED','CLOSED')) then
2933 n_status := 'OPEN';
2934 end if;
2935 end if;
2936
2937 -- g_to_role global variable is to identify to whom the email is addressed
2938 -- when contructing the More Info MAILTO, so that the role name is not displayed
2939 -- among the participants
2940 -- Timezone will not be supported in this version of the GetMessage
2941 -- API.
2942 n_timezone := '';
2943
2944 if (wf_notification.HideMoreInfo(nid) = 'N') then
2945 if(n_more_info_role is not null) then
2946 n_to_role := n_more_info_role;
2947 g_to_role := n_more_info_role;
2948 g_moreinfo := 'SUB';
2949 else
2950 g_to_role := n_to_role;
2951 g_moreinfo := 'REQ';
2952 end if;
2953 end if;
2954
2955 -- Get Recipient information
2956 Wf_Directory.GetRoleInfo(n_to_role, r_dname, r_email, r_ntf_pref,
2957 r_language, r_territory);
2958 r_ntf_pref := nvl(r_ntf_pref, 'QUERY');
2959
2960 wf_notification.GetComments(nid, g_ntfDocText,
2961 n_text_history, n_last_ques);
2962 wf_notification.GetComments(nid, g_ntfDocHtml,
2963 n_html_history, n_last_ques);
2964 if n_text_history is not null or n_text_history <> '' then
2965 if isBiDi(r_language) then
2966 n_text_history := n_text_history||' '|| g_ntfHistory;
2967 else
2968 n_text_history := g_ntfHistory||' '|| n_text_history;
2969 end if;
2970 end if;
2971 if n_html_history is not null or n_html_history <> '' then
2972 if isBiDi(r_language) then
2973 n_dir := 'dir="rtl" ';
2974 else
2975 n_dir := '';
2976 end if;
2977
2978 n_html_history := '<table '||n_dir||
2979 'bgcolor="'||table_bgcolor||'" width="'||
2980 table_width||'" cellpadding="'||
2981 table_cellpadding||'" cellspacing="'||
2982 table_cellspacing||'" >'||
2983 '<tr valign="top"><td width="10%">'||
2984 '<font face="'||
2985 td_fontface||'" size="'||td_fontsize||'" >'||
2986 g_ntfHistory||
2987 '</font></td><td>'|| n_html_history ||
2988 '</td></tr></table>'||g_newLine;
2989 end if;
2990
2991 -- Bug 2375920 get signature policy for the notification
2992 Wf_Mail.GetSignaturePolicy(nid, n_sig_policy);
2993
2994 n_subject := WF_NOTIFICATION.GetSubject(nid, 'text/plain');
2995
2996 -- We will always fetch plain text version of the message because
2997 -- Because for sendmail MAILATTH case, we need to send out html message
2998 -- body as attachment and then the plain text message as the body.
2999 -- For MAPI MAILATTH and MAILHTML cases, same thing.
3000 if isBiDi(r_language) then
3001 WF_NOTIFICATION.Set_NTF_Table_Direction('R');
3002 else
3003 WF_NOTIFICATION.Set_NTF_Table_Direction('L');
3004 end if;
3005
3006 n_text_body := WF_NOTIFICATION.GetBody(nid, g_ntfDocText);
3007
3008 GetHeaderTable(r_language||':'||to_char(nid), g_ntfDocText,
3009 t_headerText, dummy);
3010
3011 if r_ntf_pref in ('MAILHTML', 'MAILATTH', 'MAILHTML2') then
3012 n_html_body := WF_NOTIFICATION.GetBody(nid, g_ntfDocHtml);
3013 GetHeaderTable(r_language||':'||to_char(nid),
3014 g_ntfDocHtml, t_headerHTML, dummy);
3015
3016 -- Extracts content between <BODY> and </BODY> if there is body tag
3017 -- This is to deal with people import the whole html file to the
3018 -- html message body through the builder.
3019 -- The logic here is that if we don't see <BODY> and </BODY>, then
3020 -- this is already just a html <BODY> portion. Otherwise, extract
3021 -- the content in between <BODY> and </BODY>.
3022 body_start := 0;
3023 body_start := instr(upper(n_html_body), '<BODY>');
3024 if (body_start <> 0) then
3025 body_start := body_start + length('<BODY>');
3026 body_end := instr(upper(n_html_body), '</BODY>');
3027 if (body_end = 0) then
3028 body_end := length(n_html_body);
3029 else
3030 body_end := body_end - 1;
3031 end if;
3032 n_html_body := substr(n_html_body, body_start, body_end);
3033 end if;
3034 --
3035 -- For every 900 character, we insert a newline just in case
3036 -- Because this whole message body may go out to the Unix SMTP gateway
3037 -- which does not like a line longer than 1000 characters.
3038 -- We do it 900 here just for safty.
3039 -- 2001/03/23 Changed algorithm to start at 900 point and then
3040 -- move to the nearest whitespace.
3041 --
3042 lnsize := 900;
3043 start_cnt := 1;
3044 end_cnt := lnsize;
3045 temp := '';
3046 str_length := length(n_html_body);
3047 while start_cnt < str_length loop
3048 -- use the existing newlines as a natural break
3049 crpos := instr(n_html_body, g_newLine, start_cnt+1, 1) -
3050 start_cnt;
3051 if crpos > 0 and crpos < end_cnt then
3052 end_cnt := crpos;
3053 else
3054
3055 -- Move forward to the next white space.
3056 while (start_cnt + end_cnt < str_length) and
3057 substr(n_html_body, start_cnt + end_cnt, 1) not in
3058 (' ', g_newLine, g_tab)
3059 and end_cnt < 999 loop
3060 end_cnt := end_cnt + 1;
3061 end loop;
3062
3063 -- We need to understand the full conditions underwhich
3064 -- the previous loop exited. All characters must be preserved
3065 -- and the line, no matter what can not exceed 900 characters.
3066
3067 if end_cnt >= (999) then
3068 end_cnt := lnsize;
3069 while (start_cnt + end_cnt > start_cnt) and
3070 substr(n_html_body, start_cnt + end_cnt, 1) not in
3071 (' ', g_newLine, g_tab)
3072 and end_cnt > 0 loop
3073 end_cnt := end_cnt - 1;
3074 end loop;
3075 -- If we can not locate a white space, then use the default
3076 if end_cnt <= 0 then
3077 end_cnt := lnsize;
3078 end if;
3079 end if;
3080 end if;
3081
3082 -- Ensure the last characters are not lost.
3083 if start_cnt + end_cnt >= str_length then
3084 line := substr(n_html_body, start_cnt);
3085 else
3086 line := substr(n_html_body, start_cnt, end_cnt);
3087 end if;
3088
3089 temp := temp || line;
3090
3091 -- If there is a newline at this point,
3092 -- then do not bother with another.
3093 if substr(n_html_body, start_cnt + end_cnt, 1) <>
3094 g_newLIne then
3095 temp := temp||g_newLine;
3096 end if;
3097
3098 -- We do not want to start the new line with the space.
3099 if substr(n_html_body, start_cnt + end_cnt, 1) = ' ' then
3100 start_cnt := start_cnt + end_cnt + 1;
3101 else
3102 start_cnt := start_cnt + end_cnt;
3103 end if;
3104 end_cnt := lnsize;
3105 end loop;
3106
3107 n_html_body := temp;
3108
3109 end if;
3110
3111 -- Bug 2375920 Process the email message based on the signature policy
3112 ProcessSignaturePolicy(nid, n_sig_policy, n_status, n_mstatus,
3113 n_key, node, t_type, t_name, n_nid_str);
3114
3115 -- Get template
3116 begin
3117 select SUBJECT, BODY, HTML_BODY
3118 into t_subject, t_text_body, t_html_body
3119 from WF_MESSAGES_VL
3120 where NAME = t_name and TYPE = t_type;
3121 exception
3122 when no_data_found then
3123 wf_core.token('NAME', t_name);
3124 wf_core.token('TYPE', t_type);
3125 wf_core.raise('WFNTF_MESSAGE');
3126 end;
3127
3128 -- Get Click here Response display value
3129 begin
3130 select DESCRIPTION
3131 into n_disp_click
3132 from WF_MESSAGE_ATTRIBUTES_TL
3133 where MESSAGE_TYPE = t_type
3134 and MESSAGE_NAME = t_name
3135 and NAME = 'CLICK_HERE_RESPONSE'
3136 and LANGUAGE = userenv('LANG');
3137 exception
3138 when NO_DATA_FOUND then
3139 -- ignore if this attribute does not exist
3140 null;
3141 end;
3142
3143 -- Retrieve errror attributes for INVALID message
3144 if (t_name = 'OPEN_INVALID') then
3145 begin
3146 err_name := Wf_Notification.GetAttrText(nid, 'MAIL_ERROR_NAME');
3147 err_message := Wf_Notification.GetAttrText(nid, 'MAIL_ERROR_MESSAGE');
3148 err_invalid := Wf_Notification.GetAttrText(nid, 'MAIL_VALUE_FOUND');
3149 err_expected := Wf_Notification.GetAttrText(nid, 'MAIL_EXP_VALUES');
3150 exception
3151 when others then null;
3152 end;
3153 end if;
3154
3155 -- If there is no html template available, use the plain text one.
3156 if (t_html_body is null) then
3157 t_html_body := replace(t_text_body, g_newLine,
3158 '<BR>'||g_newLine);
3159 -- Ensure the direction of the text is correct for the language
3160 if isBiDi(r_language) then
3161 t_html_body := '<HTML DIR="RTL"><BODY>'||t_html_body;
3162 else
3163 t_html_body := '<HTML><BODY>'||t_html_body;
3164 end if;
3165 else
3166 -- Ensure that the direction of the text is correctly specified.
3167 if isBiDi(r_language) then
3168 tag_pos := instrb(upper(t_html_body), '<HTML', 1);
3169 if tag_pos > 0 then
3170 dir_pos := instrb(upper(t_html_body), ' DIR="', 1);
3171 if dir_pos = 0 then
3172 buffer := substrb(t_html_body, 1, 5);
3173 buffer := buffer||' DIR="RTL" '||substrb(t_html_body, tag_pos+5);
3174 t_html_body := buffer;
3175 end if;
3176 end if;
3177 end if;
3178 end if;
3179
3180 -- Substitute
3181 if wf_mail.direct_response then
3182 n_direct := '[2]';
3183 else
3184 n_direct := NULL;
3185 end if;
3186
3187 -- Bug# 2301881 replacing err_stack with err_invalid and err_expected
3188 -- to make the WARNING message to the responder more user-friendly
3189 n_subject := Substitute(t_subject, nid, n_nid_str,
3190 n_status, n_to_role, r_dname, r_email,
3191 n_start_date, n_due_date, n_end_date, n_from_user,
3192 n_priority, n_comment, n_subject, dummy,
3193 dummy, err_name, err_message, err_invalid,
3194 err_expected, n_timezone);
3195 n_headerText := Substitute(t_headerText, nid, n_nid_str,
3196 n_status, n_to_role, r_dname, r_email,
3197 n_start_date, n_due_date, n_end_date, n_from_user,
3198 n_priority, n_comment, n_subject, dummy,
3199 dummy, err_name, err_message, err_invalid,
3200 err_expected, n_timezone);
3201 n_headerHTML := Substitute(t_headerText, nid, n_nid_str,
3202 n_status, n_to_role, r_dname, r_email,
3203 n_start_date, n_due_date, n_end_date, n_from_user,
3204 n_priority, n_comment, n_subject, dummy,
3205 dummy, err_name, err_message, err_invalid,
3206 err_expected, n_timezone);
3207 n_text_body := Substitute(t_text_body, nid, n_nid_str,
3208 n_status, n_to_role, r_dname, r_email,
3209 n_start_date, n_due_date, n_end_date, n_from_user,
3210 n_priority, n_comment, n_subject, n_headerText,
3211 n_text_body, err_name, err_message, err_invalid,
3212 err_expected, n_timezone);
3213 n_html_body := Substitute(t_html_body, nid, n_nid_str,
3214 n_status, n_to_role, r_dname, r_email,
3215 n_start_date, n_due_date, n_end_date, n_from_user,
3216 n_priority, n_comment,
3217 UrlEncode(n_subject), n_headerHTML, n_html_body,
3218 err_name, err_message, err_invalid,
3219 err_expected, n_timezone);
3220
3221 -- Wrap the body into nice pretty lines.
3222 if (r_ntf_pref in ('MAILTEXT', 'MAILATTH')) then
3223 n_text_body := WordWrap(n_text_body, 0);
3224 end if;
3225
3226 if (g_moreinfo = 'SUB') then
3227 n_response := g_moreInfoAPrompt || ': "<' ||
3228 g_moreInfoAnswer ||'>"';
3229 n_response := n_response || g_newLine;
3230 else
3231 if wf_mail.direct_response then
3232 n_response := GetEmailDirectResponse(nid);
3233 else
3234 n_response := GetEmailResponse(nid);
3235 end if;
3236 end if;
3237
3238 -- make sure total length will not exceed 32K
3239 -- if it does truncate the body, leaving room for truncation string
3240 if (length(n_text_body) + length(n_response)) > 32000 then
3241 n_text_body := substr(n_text_body, 1, 31900 - length(n_response))
3242 ||g_newLine|| g_truncate;
3243 end if;
3244
3245
3246 -- Add email response section
3247 if instr(n_text_body,'&'||'RESPONSE')> 0 then
3248 n_text_body := substrb(replace(n_text_body, '&'||'RESPONSE', n_response),
3249 1, 32000);
3250 else
3251 -- Fix for bug 2395898 - do not append the response when no token
3252 -- Check to see if the response is included in the template
3253 begin
3254 select 'Y'
3255 into n_response_exists
3256 from WF_MESSAGES_VL
3257 where NAME = t_name and TYPE = 'WFMAIL'
3258 and instr(body,'&'||'RESPONSE')<>0;
3259 exception
3260 when no_data_found then
3261 n_response_exists := 'N';
3262 end;
3263
3264 -- we must have truncated the token, so just append the response
3265 if (n_response_exists = 'Y') then
3266 n_text_body := n_text_body||n_response;
3267 end if;
3268 end if;
3269
3270 -- repeat for html body
3271 if (length(n_html_body) + length(n_response)) > 32000 then
3272 n_html_body := substr(n_html_body, 1, 31900 - length(n_response))
3273 ||g_newLine||
3274 g_truncate;
3275 end if;
3276
3277 -- Add email response section
3278 if instr(n_html_body,'&'||'RESPONSE')> 0 then
3279 n_html_body := substrb(replace(n_html_body, '&'||'RESPONSE', n_response),
3280 1, 32000);
3281 end if;
3282
3283 -- More Information processing - adding history of questions and answers
3284 -- to outbound notifications
3285 if instr(n_html_body,'&'||'QUESTION')> 0 then
3286 n_html_body := substrb(replace(n_html_body, '&'||'QUESTION', n_last_ques),
3287 1, 32000);
3288 end if;
3289 if instr(n_text_body,'&'||'QUESTION')> 0 then
3290 n_text_body := substrb(replace(n_text_body, '&'||'QUESTION', n_last_ques),
3291 1, 32000);
3292 end if;
3293 if instr(n_html_body,'&'||'HISTORY')> 0 then
3294 n_html_body := substrb(replace(n_html_body, '&'||'HISTORY', n_html_history),
3295 1, 32000);
3296 end if;
3297 if instr(n_text_body,'&'||'HISTORY')> 0 then
3298 n_text_body := substrb(replace(n_text_body, '&'||'HISTORY', n_text_history),
3299 1, 32000);
3300 end if;
3301
3302 -- Add mailto section
3303 -- when template used is OPEN_MOREINFO, providing a template to submit
3304 -- more information
3305 if (g_moreinfo = 'SUB') then
3306 n_mailto := GetMoreInfoMailTo(nid, 'NID['||to_char(nid)||'/'||n_key
3307 ||'@'||node||']',replyto, n_subject);
3308 else
3309 n_mailto := GetMailTo(nid, 'NID['||to_char(nid)||'/'||n_key||'@'||node||']',
3310 replyto, n_subject);
3311 end if;
3312 n_html_body := substrb(replace(n_html_body, '&'||'MAILTO', n_mailto), 1, 32000);
3313
3314 -- Add click_here_response section
3315 n_click_here := '<A class="OraLink" HREF="';
3316 if (agent is null) then
3317 if wf_mail.send_accesskey then
3318 n_click_here := n_click_here||g_webAgent
3319 ||'/WFA_HTML.DetailLink?nid='||to_char(nid)
3320 ||'&'||'nkey='||n_key
3321 ||'&'||'agent='||g_webAgent;
3322 else
3323 n_click_here := n_click_here||g_webAgent
3324 ||'/'||wfa_sec.DirectLogin(nid);
3325 end if;
3326 else
3327 if wf_mail.send_accesskey then
3328 n_click_here := n_click_here||agent
3329 ||'/WFA_HTML.DetailLink?nid='||to_char(nid)
3330 ||'&'||'nkey='||n_key
3331 ||'&'||'agent='||agent;
3332 else
3333 n_click_here := n_click_here||agent
3334 ||'/'||wfa_sec.DirectLogin(nid);
3335 end if;
3336 end if;
3337 n_click_here := n_click_here||'">'||n_disp_click||'</A>';
3338
3339 n_html_body := substrb(replace(n_html_body, '&'||'CLICK_HERE_RESPONSE',
3340 n_click_here), 1, 32000);
3341
3342 -- Get HTML attachment
3343 if (agent is null) then
3344 m_html := substrb(WFA_HTML.Detail2(nid, n_key, g_webAgent), 1, 32000);
3345 else
3346 m_html := substrb(WFA_HTML.Detail2(nid, n_key, agent), 1, 32000);
3347 end if;
3348
3349 if isBiDi(r_language) then
3350 tag_pos := instrb(upper(m_html), '<HTML', 1);
3351 if tag_pos > 0 then
3352 dir_pos := instrb(upper(m_html), ' DIR="', 1);
3353 if dir_pos = 0 then
3354 buffer := substrb(m_html, 1, 5);
3355 buffer := buffer||' DIR="RTL" '||substrb(m_html, tag_pos+5);
3356 m_html := buffer;
3357 end if;
3358 end if;
3359 end if;
3360
3361 -- Close of the HTML Body only where this is none
3362 if instr(n_html_body, '</BODY>') = 0 then
3363 n_html_body := n_html_body || '</BODY></HTML>';
3364 end if;
3365
3366
3367 subject := n_subject;
3368 text_body := n_text_body;
3369 html_body := n_html_body;
3370 -- this is for the little attachment to the detail frame
3371 body_atth := m_html;
3372
3373 exception
3374 when no_program_unit then
3375 wf_core.context('WF_MAIL', 'GetMessage', to_char(nid), node);
3376 raise;
3377 when others then
3378 -- First look for a wf_core error.
3379 wf_core.get_error(err_name, err_message, err_stack);
3380
3381 -- If no wf_core error look for a sql error.
3382 if (err_name is null) then
3383 err_message := sqlerrm;
3384 end if;
3385
3386 error_result := err_message||g_newLine||err_stack;
3387 wf_core.context('WF_MAIL', 'GetMessage', to_char(nid), node, error_result);
3388
3389 end GetMessage;
3390
3391 -- LOBReplace
3392 -- To replace the given token in message with the token value
3393 -- IN
3394 -- message The CLOB message containing the tokens
3395 -- token The varchar token, complete with '&' prefix
3396 -- tokenValue The varchar value to substitute for the token
3397 -- append The boolean flag to say if the token was NOT found, then
3398 -- append the tokenValue regardless
3399 --
3400 procedure LOBReplace(message IN OUT NOCOPY CLOB,
3401 token IN VARCHAR2,
3402 tokenValue IN VARCHAR2,
3403 append IN BOOLEAN)
3404 is
3405 -- temp CLOB;
3406 tempIdx pls_integer;
3407 pos NUMBER;
3408 msgLen NUMBER;
3409 amount NUMBER;
3410
3411 continue boolean;
3412 offset number;
3413 sourcePos number;
3414 targetPos number;
3415 tokenLen pls_integer;
3416
3417 nextChar varchar2(10);
3418 validToken boolean;
3419 xSet varchar2(100) := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'||
3420 '0123456789_';
3421 tokenFound boolean;
3422
3423 begin
3424
3425 -- DBMS_LOB.CreateTemporary(temp, TRUE, DBMS_LOB.CALL);
3426 tempIdx := -1;
3427
3428 offset := 1;
3429 sourcePos := 1;
3430 targetPos := 1;
3431 continue := TRUE;
3432 msgLen := DBMS_LOB.GetLength(message);
3433 tokenLen := length(token);
3434 tokenFound := FALSE;
3435
3436 while continue
3437 loop
3438
3439 pos := DBMS_LOB.Instr(message, token, offset, 1);
3440 if (pos <> 0) then
3441 if (pos + tokenLen <= msgLen) then
3442 nextChar := upper(dbms_lob.substr(message, 1, pos + tokenLen));
3443 if (instr(xSet, nextChar,1,1) > 0) then
3444 validToken := false;
3445 else
3446 validToken := true;
3447 end if;
3448 else
3449 validToken := true;
3450 end if;
3451 else
3452 validToken := false;
3453 continue := FALSE;
3454 end if;
3455
3456 if continue then
3457 if validToken then
3458 -- Only request a LOB if it is necessary and only if one
3459 -- has not already been requested.
3460 if tempIdx = -1 then
3461 tempIdx := wf_temp_lob.getLob(g_LOBTable);
3462 end if;
3463 amount := pos - sourcePos;
3464 DBMS_LOB.Copy(dest_lob => g_LOBTable(tempIdx).temp_lob,
3465 src_lob => message,
3466 amount => amount,
3467 dest_offset => targetPos,
3468 src_offset => sourcePos);
3469 if (tokenValue <> '' or tokenValue is not null) then
3470 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob,
3471 length(tokenValue), tokenValue);
3472 end if;
3473 sourcePos := pos + tokenLen;
3474 targetPos := DBMS_LOB.GetLength(g_LOBTable(tempIdx).temp_lob) + 1;
3475 tokenFound := TRUE;
3476 end if;
3477 offset := pos + tokenLen;
3478 else
3479 amount := msgLen - sourcePos +1;
3480 if (amount > 0)then
3481 if tempIdx = -1 then
3482 tempIdx := wf_temp_lob.getLob(g_LOBTable);
3483 end if;
3484 DBMS_LOB.Copy(g_LOBTable(tempIdx).temp_lob, message, amount,
3485 targetPos, sourcePos);
3486 end if;
3487
3488 if (append and tokenFound = FALSE and msgLen > 0) then
3489 if (tokenValue <> '' or tokenValue is not null) then
3490 if tempIdx = -1 then
3491 tempIdx := wf_temp_lob.getLob(g_LOBTable);
3492 end if;
3493 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob,
3494 length(tokenValue), tokenValue);
3495 end if;
3496 end if;
3497 end if; -- CONTINUE
3498
3499 end loop;
3500
3501 if tokenFound = TRUE then
3502 msgLen := DBMS_LOB.GetLength(g_LOBTable(tempIdx).temp_lob);
3503 DBMS_LOB.Trim(message, 0);
3504 DBMS_LOB.Copy(message, g_LOBTable(tempIdx).temp_lob, msgLen);
3505 end if;
3506
3507 -- << sstomar bug 6511028 >> Release allocated TEMP LOb.
3508 if tempIdx <> -1 then
3509 wf_temp_lob.releaseLob(g_LOBTable, tempIdx);
3510 end if;
3511
3512 exception
3513 when others then
3514 wf_temp_lob.releaseLob(g_LOBTable, tempIdx);
3515 WF_CORE.Context('WF_MAIL','LOBReplace',token,
3516 tokenValue);
3517 raise;
3518
3519 end LOBReplace;
3520
3521 -- LOBReplace
3522 -- To replace the given token in message with the token value
3523 -- IN
3524 -- message The CLOB message containing the tokens
3525 -- token The varchar token, complete with '&' prefix
3526 -- tokenValue The CLOB value to substitute for the token
3527 -- append The boolean flag to say if the token was NOT found, then
3528 -- append the tokenValue regardless
3529 --
3530 procedure LOBReplace(message IN OUT NOCOPY CLOB,
3531 token IN VARCHAR2,
3532 tokenValue IN OUT NOCOPY CLOB,
3533 append IN BOOLEAN)
3534 is
3535 -- temp CLOB;
3536 tempIdx pls_integer;
3537 pos NUMBER;
3538 msgLen NUMBER;
3539 amount NUMBER;
3540 tokenValueLen number;
3541
3542 continue boolean;
3543 offset number;
3544 sourcePos number;
3545 targetPos number;
3546 tokenLen pls_integer;
3547
3548 nextChar varchar2(10);
3549 validToken boolean;
3550 xSet varchar2(100) := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'||
3551 '0123456789_';
3552 tokenFound boolean;
3553
3554 begin
3555 -- DBMS_LOB.CreateTemporary(temp, FALSE, DBMS_LOB.CALL);
3556 tempIdx := wf_temp_lob.getLob(g_LOBTable);
3557
3558 offset := 1;
3559 sourcePos := 1;
3560 targetPos := 1;
3561 continue := TRUE;
3562 msgLen := DBMS_LOB.GetLength(message);
3563 tokenLen := length(token);
3564 tokenFound := FALSE;
3565
3566 while continue
3567 loop
3568 pos := DBMS_LOB.Instr(message, token, offset, 1);
3569
3570 if pos <> 0 then
3571 if (pos + tokenLen <= msgLen) then
3572 nextChar := upper(dbms_lob.substr(message, 1, pos + tokenLen));
3573 if (instr(xSet, nextChar,1,1) > 0) then
3574 validToken := false;
3575 else
3576 validToken := true;
3577 end if;
3578 else
3579 validToken := true;
3580 end if;
3581 else
3582 validToken := false;
3583 continue := FALSE;
3584 end if;
3585
3586 if continue then
3587 if validToken then
3588 amount := pos - sourcePos;
3589 DBMS_LOB.Copy(g_LOBTable(tempIdx).temp_lob, message, amount,
3590 targetPos, sourcePos);
3591 tokenValueLen := DBMS_LOB.GetLength(tokenValue);
3592 if (tokenValueLen > 0) then
3593 DBMS_LOB.Append(g_LOBTable(tempIdx).temp_lob, tokenValue);
3594 end if;
3595 sourcePos := pos + tokenLen;
3596 targetPos := DBMS_LOB.GetLength(g_LOBTable(tempIdx).temp_lob) + 1;
3597 tokenFound := TRUE;
3598 end if;
3599 offset := pos + tokenLen;
3600 else
3601 amount := msgLen - sourcePos + 1;
3602 if (amount > 0) then
3603 DBMS_LOB.Copy(g_LOBTable(tempIdx).temp_lob, message, amount,
3604 targetPos, sourcePos);
3605 end if;
3606
3607 if (append and tokenFound = FALSE and msgLen > 0) then
3608 tokenValueLen := DBMS_LOB.GetLength(tokenValue);
3609 if tokenValueLen <> 0 then
3610 DBMS_LOB.Append(g_LOBTable(tempIdx).temp_lob, tokenValue);
3611 end if;
3612 end if;
3613 end if;
3614 end loop;
3615
3616 if tokenFound then
3617 msgLen := DBMS_LOB.GetLength(g_LOBTable(tempIdx).temp_lob);
3618 DBMS_LOB.Trim(message, 0);
3619 DBMS_LOB.Copy(message, g_LOBTable(tempIdx).temp_lob, msgLen);
3620 end if;
3621 wf_temp_lob.releaseLob(g_LOBTable, tempIdx);
3622
3623 exception
3624 when others then
3625 wf_temp_lob.releaseLob(g_LOBTable, tempIdx);
3626 WF_CORE.Context('WF_MAIL','LOBReplace',token, 'LOB');
3627 raise;
3628
3629 end LOBReplace;
3630
3631 -- LOBSubstitute
3632 -- Template contains a max length of 4000 only. We require only a varchar2.
3633 -- IN
3634 -- template IN OUT NOCOPY VARCHAR2,
3635 -- n_nid IN NUMBER,
3636 -- n_code IN VARCHAR2,
3637 -- n_status IN VARCHAR2,
3638 -- n_to_role IN VARCHAR2,
3639 -- r_dName IN VARCHAR2,
3640 -- r_email IN VARCHAR2,
3641 -- n_start_Date IN DATE,
3642 -- n_due_Date IN DATE,
3643 -- n_end_Date IN DATE,
3644 -- n_from_user IN VARCHAR2,
3645 -- n_priority IN VARCHAR2,
3646 -- n_comment IN VARCHAR2,
3647 -- m_subject IN VARCHAR2,
3648 -- m_body IN OUT NOCOPY CLOB,
3649 -- err_Name IN OUT NOCOPY VARCHAR2,
3650 -- err_Message IN OUT NOCOPY VARCHAR2,
3651 -- err_Stack IN OUT NOCOPY VARCHAR2,
3652 -- n_timezone IN VARCHAR2)
3653 procedure LOBSubstitute(template IN OUT NOCOPY VARCHAR2,
3654 n_nid IN NUMBER,
3655 n_code IN VARCHAR2,
3656 n_status IN VARCHAR2,
3657 n_to_role IN VARCHAR2,
3658 r_dName IN VARCHAR2,
3659 r_email IN VARCHAR2,
3660 n_start_Date IN DATE,
3661 n_due_Date IN DATE,
3662 n_end_Date IN DATE,
3663 n_from_user IN VARCHAR2,
3664 n_priority IN VARCHAR2,
3665 n_comment IN VARCHAR2,
3666 m_subject IN VARCHAR2,
3667 m_header IN VARCHAR2,
3668 m_body IN OUT NOCOPY CLOB,
3669 err_Name IN OUT NOCOPY VARCHAR2,
3670 err_Message IN OUT NOCOPY VARCHAR2,
3671 err_Invalid IN OUT NOCOPY VARCHAR2,
3672 err_Expected IN OUT NOCOPY VARCHAR2,
3673 n_timezone IN VARCHAR2)
3674 is
3675 -- temp CLOB;
3676 tempIdx pls_integer;
3677 tempPos NUMBER := 0;
3678 pos NUMBER := 0;
3679 amper NUMBER := 0;
3680
3681 msgLen NUMBER := 0;
3682 tknSize NUMBER := 0;
3683
3684 tokenName VARCHAR2(60);
3685 tokenMatch BOOLEAN;
3686
3687 n_due_date_text varchar2(64);
3688 n_start_date_text varchar2(64);
3689 n_end_date_text varchar2(64);
3690
3691 n_priority_text varchar2(240);
3692 n_nidStr varchar2(50);
3693
3694 eot NUMBER;
3695
3696 begin
3697
3698 -- BLAF requriement to display the date with TIME elelment
3699 -- n_due_date_text := to_char(n_due_date, Wf_Notification.g_nls_date_mask);
3700 -- n_start_date_text := to_char(n_start_date, Wf_Notification.g_nls_date_mask);
3701
3702 --<< sstomar>: NLS changes, bug 7578922
3703 n_due_date_text := wf_notification_util.GetCalendarDate(n_nid, n_due_date, null, true);
3704 n_start_date_text := wf_notification_util.GetCalendarDate(n_nid, n_start_date, null, true);
3705 n_end_date_text := wf_notification_util.GetCalendarDate(n_nid, n_end_date, null, true);
3706
3707 if (n_priority > 66) then
3708 --Bug 2774891 fix - sacsharm
3709 --n_priority_text := wf_core.substitute('WFTKN', 'HIGH');
3710 n_priority_text := wf_core.substitute('WFTKN', 'LOW');
3711 elsif (n_priority > 33) then
3712 n_priority_text := wf_core.substitute('WFTKN', 'NORMAL');
3713 else
3714 --Bug 2774891 fix - sacsharm
3715 --n_priority_text := wf_core.substitute('WFTKN', 'LOW');
3716 n_priority_text := wf_core.substitute('WFTKN', 'HIGH');
3717 end if;
3718
3719 -- DBMS_LOB.CreateTemporary(temp, TRUE, DBMS_LOB.SESSION);
3720 -- DBMS_LOB.Open(temp, DBMS_LOB.LOB_READWRITE);
3721 tempIdx := wf_temp_lob.getLob(g_LOBTable);
3722
3723 pos := 1;
3724 tempPos := 1;
3725 msgLen := length(template);
3726 while pos < msgLen loop
3727 -- Locate each instance of an ampersand and assume it is
3728 -- a token reference.
3729 amper := instr(template, '&', pos, 1);
3730
3731 if amper = 0 then
3732 -- No ampers left. so write the rest of the CLOB
3733 if pos < msgLen then
3734 -- DBMS_LOB.Copy(temp, template, (msgLen - pos)+1, tempPos, pos);
3735 DBMS_LOB.Write(g_LOBTable(tempIdx).temp_lob, (msgLen - pos)+1, tempPos,
3736 substr(template, pos, (msgLen - pos)+1));
3737 end if;
3738 EXIT;
3739 end if;
3740
3741 -- Now we have the position of the amper, workout what
3742 -- token it is, if any.
3743
3744 -- write from the last pos to the new token.
3745 if amper > pos then
3746 -- DBMS_LOB.Copy(temp, template, (amper - pos), tempPos, pos);
3747 DBMS_LOB.Write(g_LOBTable(tempIdx).temp_lob, (amper - pos), tempPos,
3748 substr(template, pos, (amper - pos)));
3749 tempPos := tempPos + ((amper - pos));
3750 end if;
3751 pos := amper + 1;
3752
3753 eot := amper;
3754 while ((eot <= msgLen) and
3755 (substr(template, eot, 1) not in (' ', g_newLine, g_tab))) loop
3756 eot := eot +1;
3757 end loop;
3758
3759 tknSize := (eot - amper) - 1;
3760 tokenName := substr(template, amper+1, tknSize);
3761
3762 tokenMatch := FALSE;
3763 -- Bug 10394986: Changed all the if ... end if conditions to if ... elsif ...end if
3764 -- as only one token can be replaced in each iteration of while loop
3765 if instr(tokenName,'NOTIFICATION_ID',1,1)=1 then
3766 n_nidStr := to_char(n_nid);
3767 if n_nidStr is not null then
3768 -- DBMS_LOB.WriteAppend(temp, length(n_nidStr), n_nidStr);
3769 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, length(n_nidStr),
3770 n_nidStr);
3771 tempPos := tempPos + length(n_nidStr);
3772 end if;
3773 pos := amper + length('NOTIFICATION_ID') + 1;
3774 tokenMatch := TRUE;
3775
3776 elsif instr(tokenName,'NOTIFICATION',1,1)=1 then
3777 if n_code is not null then
3778 -- DBMS_LOB.WriteAppend(temp, length(n_code), n_code);
3779 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, length(n_code),
3780 n_code);
3781 tempPos := tempPos + length(n_code);
3782 end if;
3783 pos := amper + length('NOTIFICATION') + 1;
3784 tokenMatch := TRUE;
3785
3786 elsif instr(tokenName,'STATUS',1,1)=1 then
3787 if n_status is not null then
3788 -- DBMS_LOB.WriteAppend(temp, length(n_status), n_status);
3789 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, length(n_status), n_status);
3790 tempPos := tempPos + length(n_status);
3791 end if;
3792 pos := amper + length('STATUS') + 1;
3793 tokenMatch := TRUE;
3794
3795 elsif instr(tokenName, 'TO_DNAME', 1, 1)=1 then
3796 if r_dname is not null then
3797 -- DBMS_LOB.WriteAppend(temp, length(r_dname), r_dname);
3798 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, length(r_dname), r_dname);
3799 tempPos := tempPos + length(r_dname);
3800 end if;
3801 pos := amper + length('TO_DNAME') + 1;
3802 tokenMatch := TRUE;
3803
3804 elsif instr(tokenName, 'TO_EMAIL', 1, 1)=1 then
3805 if r_email is not null then
3806 -- DBMS_LOB.WriteAppend(temp, length(r_email), r_email);
3807 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, length(r_email), r_email);
3808 tempPos := tempPos + length(r_email);
3809 end if;
3810 pos := amper + length('TO_EMAIL') + 1;
3811 tokenMatch := TRUE;
3812
3813 elsif instr(tokenName,'TO',1,1)=1 then
3814 if n_to_role is not null then
3815 -- DBMS_LOB.WriteAppend(temp, length(n_to_role), n_to_role);
3816 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, length(n_to_role), n_to_role);
3817 tempPos := tempPos + length(n_to_role);
3818 end if;
3819 pos := amper + length('TO') + 1;
3820 tokenMatch := TRUE;
3821
3822 elsif instr(tokenName, 'PRIORITY', 1, 1)=1 then
3823 if n_priority_text is not null then
3824 -- DBMS_LOB.WriteAppend(temp, length(n_priority_text), n_priority_text);
3825 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, length(n_priority_text),
3826 n_priority_text);
3827 tempPos := tempPos + length(n_priority_text);
3828 end if;
3829 pos := amper + length('PRIORITY') + 1;
3830 tokenMatch := TRUE;
3831
3832 elsif instr(tokenName, 'START_DATE', 1, 1)=1 then
3833 if n_start_date is not null then
3834 -- DBMS_LOB.WriteAppend(temp, length(n_start_date), n_start_date);
3835 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob,
3836 length(n_start_date_text), n_start_date_text);
3837 tempPos := tempPos + length(n_start_date_text);
3838 end if;
3839 pos := amper + length('START_DATE') + 1;
3840 tokenMatch := TRUE;
3841
3842 elsif instr(tokenName, 'DUE_DATE', 1, 1)=1 then
3843 if n_due_date is not null then
3844 -- DBMS_LOB.WriteAppend(temp, length(n_due_date_text), n_due_date_text);
3845 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, length(n_due_date_text),
3846 n_due_date_text);
3847 tempPos := tempPos + length(n_due_date_text);
3848 end if;
3849 pos := amper + length('DUE_DATE') + 1;
3850 tokenMatch := TRUE;
3851
3852 elsif instr(tokenName, 'END_DATE', 1, 1)=1 then
3853 if n_end_date is not null then
3854 -- DBMS_LOB.WriteAppend(temp, length(n_end_date), n_end_date);
3855 -- DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, length(n_end_date),
3856 -- n_end_date);
3857 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, length(n_end_date_text),
3858 n_end_date_text);
3859
3860 tempPos := tempPos + length(n_end_date_text);
3861 end if;
3862 pos := amper + length('END_DATE') + 1;
3863 tokenMatch := TRUE;
3864
3865 elsif instr(tokenName, 'SENDER', 1, 1)=1 then
3866 if n_from_user is not null then
3867 -- DBMS_LOB.WriteAppend(temp, length(n_from_user), n_from_user);
3868 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, length(n_from_user),
3869 n_from_user);
3870 tempPos := tempPos + length(n_from_user);
3871 end if;
3872 pos := amper + length('SENDER') + 1;
3873 tokenMatch := TRUE;
3874
3875 elsif instr(tokenName, 'COMMENT', 1, 1)=1 then
3876 if n_comment is not null then
3877 -- DBMS_LOB.WriteAppend(temp, length(n_comment), n_comment);
3878 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob,
3879 length(n_comment), n_comment);
3880 tempPos := tempPos + length(n_comment);
3881 end if;
3882 pos := amper + length('COMMENT') + 1;
3883 tokenMatch := TRUE;
3884
3885 elsif instr(tokenName, 'TIMEZONE', 1, 1)=1 then
3886 if n_timezone is not null then
3887 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob,
3888 length(n_timezone), n_timezone);
3889 tempPos := tempPos + length(n_timezone);
3890 end if;
3891 pos := amper + length('TIMEZONE') + 1;
3892 tokenMatch := TRUE;
3893
3894 elsif instr(tokenName, 'SUBJECT', 1, 1)=1 then
3895 if m_subject is not null then
3896 -- DBMS_LOB.WriteAppend(temp, length(m_subject), m_subject);
3897 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, length(m_subject), m_subject);
3898 tempPos := tempPos + length(m_subject);
3899 end if;
3900 pos := amper + length('SUBJECT') + 1;
3901 tokenMatch := TRUE;
3902
3903 elsif instr(tokenName, 'HEADER', 1, 1)=1 then
3904 if m_header is not null then
3905 --DBMS_LOB.WriteAppend(temp, length(m_header), m_header);
3906 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, length(m_header), m_header);
3907 tempPos := tempPos + length(m_header);
3908 end if;
3909 pos := amper + length('HEADER') + 1;
3910 tokenMatch := TRUE;
3911
3912 elsif instr(tokenName, 'BODY', 1, 1)=1 then
3913 if (m_body is not null and dbms_lob.getLength(m_body) > 0) or not g_isFwkNtf then
3914 DBMS_LOB.Append(g_LOBTable(tempIdx).temp_lob, m_body);
3915 tempPos := tempPos + DBMS_LOB.GetLength(m_body);
3916 pos := amper + length('BODY') + 1;
3917 tokenMatch := TRUE;
3918 else
3919 tokenMatch := FALSE;
3920 end if;
3921
3922 elsif instr(tokenName, 'MAIL_ERROR_NAME', 1, 1)=1 then
3923 if err_name is not null then
3924 -- DBMS_LOB.WriteAppend(temp, length(err_name), err_name);
3925 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, length(err_name), err_name);
3926 tempPos := tempPos + length(err_name);
3927 end if;
3928 pos := amper + length('MAIL_ERROR_NAME') + 1;
3929 tokenMatch := TRUE;
3930
3931 elsif instr(tokenName, 'MAIL_ERROR_MESSAGE', 1, 1)=1 then
3932 if err_message is not null then
3933 -- DBMS_LOB.WriteAppend(temp, length(err_message), err_message);
3934 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, length(err_message),
3935 err_message);
3936 tempPos := tempPos + length(err_message);
3937 end if;
3938 pos := amper + length('MAIL_ERROR_MESSAGE') + 1;
3939 tokenMatch := TRUE;
3940
3941
3942 -- Bug# 2301881 Replacing error stack with invalid value
3943 -- found and the original response values
3944 -- to go with the WARNING message
3945
3946 elsif instr(tokenName, 'MAIL_VALUE_FOUND', 1, 1)=1 then
3947 if err_invalid is not null then
3948 -- DBMS_LOB.WriteAppend(temp, length(err_invalid), err_invalid);
3949 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, length(err_invalid),
3950 err_invalid);
3951 tempPos := tempPos + length(err_invalid);
3952 end if;
3953 pos := amper + length('MAIL_VALUE_FOUND') + 1;
3954 tokenMatch := TRUE;
3955
3956
3957 elsif instr(tokenName, 'MAIL_EXP_VALUES', 1, 1)=1 then
3958 if err_expected is not null then
3959 -- DBMS_LOB.WriteAppend(temp, length(err_expected), err_expected);
3960 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, length(err_expected),
3961 err_expected);
3962 tempPos := tempPos + length(err_expected);
3963 end if;
3964 pos := amper + length('MAIL_EXP_VALUES') + 1;
3965 tokenMatch := TRUE;
3966 end if;
3967
3968 if not tokenMatch and amper > 0 then
3969 -- DBMS_LOB.WriteAppend(temp, 1, '&');
3970 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, 1, '&');
3971 tempPos := tempPos + 1;
3972 end if;
3973
3974 end loop;
3975
3976 -- msgLen := DBMS_LOB.GetLength(temp);
3977 msgLen := DBMS_LOB.GetLength(g_LOBTable(tempIdx).temp_lob);
3978 if msgLen > 0 then
3979 DBMS_LOB.Trim(m_body, 0);
3980 -- DBMS_LOB.Copy(m_body, temp, msgLen);
3981 DBMS_LOB.Copy(m_body, g_LOBTable(tempIdx).temp_lob, msgLen);
3982 end if;
3983
3984 -- DBMS_LOB.Close(temp);
3985 -- DBMS_LOB.FreeTemporary(temp);
3986 wf_temp_lob.releaseLob(g_LOBTable, tempIdx);
3987
3988 exception
3989 when others then
3990 wf_temp_lob.releaseLob(g_LOBTable, tempIdx);
3991 WF_CORE.Context('WF_MAIL','LOBSubstitute',tokenName,
3992 to_char(msgLen)||':'||to_char(pos)||':'||to_char(tempPos));
3993 raise;
3994 end LOBSubstitute;
3995
3996 -- OBSOLETELOBLineBreak - To add a new line every 900 characters
3997 -- or the nearst white space
3998 -- IN
3999 -- message
4000 -- line size default 900
4001 procedure OBSOLETELOBLineBreak(message IN OUT NOCOPY CLOB,
4002 lineSize in INTEGER,
4003 maxLineSize INTEGER)
4004 is
4005 lnsize NUMBER;
4006 start_cnt NUMBER;
4007 end_cnt NUMBER;
4008 crpos NUMBER;
4009 tempOffset NUMBER;
4010 str_length NUMBER;
4011
4012 -- temp CLOB;
4013 -- line CLOB;
4014 tempIdx pls_integer;
4015 lineIdx pls_integer;
4016
4017 begin
4018
4019 --
4020 -- For every 900 character, we insert a newline just in case
4021 -- Because this whole message body may go out to the Unix SMTP gateway
4022 -- which does not like a line longer than 1000 characters.
4023 -- We do it 900 here just for safty.
4024 -- 2001/03/23 Changed algorithm to start at 900 point and then
4025 -- move to the nearest whitespace.
4026 --
4027 lnsize := lineSize;
4028 start_cnt := 1;
4029 end_cnt := lnsize;
4030 str_length := DBMS_LOB.GetLength(message);
4031 if str_length = 0 then
4032 return;
4033 end if;
4034
4035 -- DBMS_LOB.CreateTemporary(temp, TRUE, DBMS_LOB.CALL);
4036 -- DBMS_LOB.CreateTemporary(line, TRUE, DBMS_LOB.CALL);
4037 -- DBMS_LOB.Open(temp, DBMS_LOB.LOB_READWRITE);
4038 -- DBMS_LOB.Open(line, DBMS_LOB.LOB_READWRITE);
4039 tempIdx := wf_temp_lob.getLob(g_LOBTable);
4040 lineIdx := wf_temp_lob.getLob(g_LOBTable);
4041
4042 while start_cnt < str_length loop
4043 -- use the existing newlines as a natural break
4044 crpos := DBMS_LOB.instr(message, g_newLine, start_cnt+1, 1) - start_cnt;
4045
4046
4047 if crpos > 0 and crpos < end_cnt then
4048 -- If there was a line bread and it is positioned less than the
4049 -- maximum allowed, then use that instead.
4050 end_cnt := crpos;
4051 else
4052 if crpos < 0 and (str_length - start_cnt) < end_cnt then
4053 end_cnt := str_length - start_cnt;
4054 end if;
4055
4056 -- Move forward to the next white space.
4057 while (start_cnt + end_cnt < str_length) and
4058 DBMS_LOB.substr(message, 1, start_cnt + end_cnt)
4059 not in (' ', g_newLine, g_tab)
4060 and end_cnt < maxLineSize loop
4061 end_cnt := end_cnt + 1;
4062 end loop;
4063
4064 -- We need to understand the full conditions underwhich
4065 -- the previous loop exited. All characters must be preserved
4066 -- and the line, no matter what can not exceed 900 characters.
4067
4068 if end_cnt >= (maxLineSize) then
4069 end_cnt := lnsize;
4070 while (start_cnt + end_cnt > start_cnt) and
4071 DBMS_LOB.substr(message, 1, start_cnt + end_cnt)
4072 not in (' ', g_newLine, g_tab)
4073 and end_cnt > 0 loop
4074 end_cnt := end_cnt - 1;
4075 end loop;
4076 -- If we can not locate a white space, then use the default
4077 if end_cnt <= 0 then
4078 end_cnt := lnsize;
4079 end if;
4080 end if;
4081 end if;
4082
4083 -- Ensure the last characters are not lost.
4084 -- DBMS_LOB.Trim(line, 0);
4085 DBMS_LOB.Trim(g_LOBTable(lineIdx).temp_lob, 0);
4086 tempOffset := dbms_lob.getLength(g_LOBTable(tempIdx).temp_lob) +1;
4087 if start_cnt + end_cnt >= str_length then
4088 -- line := DBMS_LOB.substr(message, start_cnt);
4089 -- DBMS_LOB.Copy(line, message,
4090 -- DBMS_LOB.GetLength(message) - start_cnt +1 , 1,
4091 -- start_cnt);
4092 -- DBMS_LOB.Copy(g_LOBTable(lineIdx).temp_lob, message,
4093 -- DBMS_LOB.GetLength(message) - start_cnt +1 , 1,
4094 -- start_cnt);
4095 DBMS_LOB.Copy(dest_lob => g_LOBTable(tempIdx).temp_lob,
4096 src_lob => message,
4097 amount => DBMS_LOB.GetLength(message) - start_cnt +1 ,
4098 dest_offset => tempOffset,
4099 src_offset => start_cnt);
4100
4101 else
4102 -- line := DBMS_LOB.substr(message, start_cnt, end_cnt);
4103 -- DBMS_LOB.Copy(line, message, end_cnt, 1, start_cnt);
4104 -- DBMS_LOB.Copy(g_LOBTable(lineIdx).temp_lob, message, end_cnt, 1,
4105 -- start_cnt);
4106 DBMS_LOB.Copy(dest_lob => g_LOBTable(tempIdx).temp_lob,
4107 src_lob => message,
4108 amount => end_cnt,
4109 dest_offset => tempOffset,
4110 src_offset => start_cnt);
4111 end if;
4112
4113 -- temp := temp || line;
4114 -- DBMS_LOB.Append(temp, line);
4115 -- DBMS_LOB.Append(g_LOBTable(tempIdx).temp_lob,
4116 -- g_LOBTable(lineIdx).temp_lob);
4117
4118 -- If there is a newline at this point,
4119 -- then do not bother with another.
4120 if DBMS_LOB.substr(message, 1, start_cnt + end_cnt) <>
4121 g_newLine then
4122 -- DBMS_LOB.WriteAppend(temp, 1, g_newLine);
4123 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, 1, g_newLine);
4124 end if;
4125
4126 -- We do not want to start the new line with the space.
4127 if DBMS_LOB.substr(message, 1, start_cnt + end_cnt) = ' ' then
4128 start_cnt := start_cnt + end_cnt + 1;
4129 else
4130 start_cnt := start_cnt + end_cnt;
4131 end if;
4132 end_cnt := lnsize;
4133 end loop;
4134 DBMS_LOB.Trim(message, 0);
4135 -- DBMS_LOB.Copy(message, temp, DBMS_LOB.GetLength(temp), 1, 1);
4136 DBMS_LOB.Copy(message, g_LOBTable(tempIdx).temp_lob,
4137 DBMS_LOB.GetLength(g_LOBTable(tempIdx).temp_lob), 1, 1);
4138
4139
4140 -- if DBMS_LOB.IsOpen(temp)=1 then
4141 -- DBMS_LOB.Close(temp);
4142 -- DBMS_LOB.FreeTemporary(temp);
4143 -- end if;
4144 -- if DBMS_LOB.IsOpen(line)=1 then
4145 -- DBMS_LOB.Close(line);
4146 -- DBMS_LOB.FreeTemporary(line);
4147 -- end if;
4148 wf_temp_lob.releaseLob(g_LOBTable, lineIdx);
4149 wf_temp_lob.releaseLob(g_LOBTable, tempIdx);
4150
4151 end OBSOLETELOBLineBreak;
4152
4153 -- OBSOLETE2LOBLineBreak
4154 -- To wrap the text at textWidth but no line can exceed maLineSize
4155 -- NOTE:
4156 -- In order to be performant, the textWidth is given
4157 -- as a guide. If not natural break appears, then the nearest
4158 -- whitespace after textWidth will be used.
4159 procedure OBSOLETE2LOBLineBreak(message IN OUT NOCOPY CLOB,
4160 textWidth in INTEGER,
4161 maxLineSize INTEGER)
4162 is
4163
4164 lnsize NUMBER;
4165 bfr_start NUMBER;
4166 chk_start NUMBER;
4167 line_size NUMBER;
4168 crpos NUMBER;
4169 wsLoc NUMBER;
4170 doc_length NUMBER;
4171 tempOffset NUMBER;
4172 insertNewLine boolean;
4173 whitespace boolean;
4174
4175 tempIdx pls_integer;
4176 lineBuffer varchar2(32000);
4177
4178 begin
4179
4180 lnsize := textWidth;
4181 bfr_start := 1;
4182 chk_start := 1;
4183 line_size := lnsize;
4184 doc_length := DBMS_LOB.GetLength(message);
4185 if doc_length = 0 or doc_length < line_size then
4186 return;
4187 end if;
4188
4189 tempIdx := wf_temp_lob.getLob(g_LOBTable);
4190
4191 -- While the block start counter is less than the length of the
4192 -- document, then start scanning to make sure that the document
4193 -- conforms to the requirements of the parameters.
4194 while chk_start < doc_length loop
4195
4196 wsLoc := -1;
4197 insertNewLine := false;
4198
4199 -- use the existing newlines as a natural break. If found
4200 -- crpos will be the relative position from chk_start.
4201 crpos := DBMS_LOB.instr(lob_loc => message,
4202 pattern => g_newLine,
4203 offset => chk_start,
4204 nth => 1) - chk_start;
4205
4206 -- If the position of crpos makes the respective line less than
4207 -- the required linesize, then use that. Otherwise, go looking for
4208 -- some whitespace to insert a new line.
4209
4210 if crpos > -1 and crpos < line_size then
4211 line_size := crpos +1;
4212 insertNewLine := false;
4213 else
4214 -- Move forward to the next white space.
4215
4216 wsLoc := DBMS_LOB.instr(lob_loc => message,
4217 pattern => ' ',
4218 offset => (chk_start + line_size),
4219 nth => 1) - chk_start;
4220
4221 crpos := DBMS_LOB.instr(lob_loc => message,
4222 pattern => g_newline,
4223 offset => (chk_start + line_size),
4224 nth => 1) - chk_start;
4225
4226 if(crpos > -1 and crpos < wsLoc and crpos < maxLineSize) then
4227 line_size := crpos +1;
4228 insertNewLine := false;
4229 elsif (wsLoc > -1 and wsLoc < maxLineSize) then
4230 line_size := wsLoc;
4231 insertNewLine := true;
4232 whitespace := true;
4233 else
4234
4235 wsLoc := DBMS_LOB.instr(lob_loc => message,
4236 pattern => g_newLine,
4237 offset => chk_start + line_size,
4238 nth => 1) - chk_start;
4239
4240 if (wsLoc > -1 and wsLoc < maxLineSize) then
4241 line_size := wsLoc;
4242 wsLoc := 0;
4243 insertNewLine := false;
4244 whitespace := true;
4245 else
4246
4247 wsLoc := DBMS_LOB.instr(lob_loc => message,
4248 pattern => g_tab,
4249 offset => chk_start + line_size,
4250 nth => 1) - chk_start;
4251
4252 if (wsLoc > -1 and wsLoc < maxLineSize) then
4253 line_size := wsLoc;
4254 insertNewLine := true;
4255 whitespace := true;
4256 else
4257 line_size := maxLineSize;
4258 insertNewLine := true;
4259 whitespace := true;
4260 end if;
4261 end if;
4262 end if;
4263 end if;
4264
4265 -- Ensure the last characters are not lost.
4266 if chk_start + line_size >= doc_length then
4267 -- copy from the chk_start to the end of the document.
4268 tempOffset := dbms_lob.getLength(g_LOBTable(tempIdx).temp_lob) +1;
4269
4270 DBMS_LOB.Copy(dest_lob => g_LOBTable(tempIdx).temp_lob,
4271 src_lob => message,
4272 amount => doc_length - bfr_start +1 ,
4273 dest_offset => tempOffset,
4274 src_offset => bfr_start);
4275 elsif insertNewLine then
4276 -- Copy partial and make note of the current position
4277 -- This is to minimise the number of calls to dbms_lob.copy.
4278 tempOffset := dbms_lob.getLength(g_LOBTable(tempIdx).temp_lob) +1;
4279 DBMS_LOB.Copy(dest_lob => g_LOBTable(tempIdx).temp_lob,
4280 src_lob => message,
4281 amount => (chk_start - bfr_start) + line_size,
4282 dest_offset => tempOffset,
4283 src_offset => bfr_start);
4284 DBMS_LOB.WriteAppend(g_LOBTable(tempIdx).temp_lob, 1, g_newLine);
4285 bfr_start := chk_start + line_size +1;
4286 end if;
4287
4288 if wsLoc > 0 then
4289 chk_start := chk_start + line_size + 1;
4290 else
4291 chk_start := chk_start + line_size;
4292 end if;
4293 line_size := lnsize;
4294 end loop;
4295
4296 DBMS_LOB.Trim(message, 0);
4297 DBMS_LOB.Copy(message, g_LOBTable(tempIdx).temp_lob,
4298 DBMS_LOB.GetLength(g_LOBTable(tempIdx).temp_lob), 1, 1);
4299
4300 DBMS_LOB.Trim(g_LOBTable(tempIdx).temp_lob, 0);
4301 wf_temp_lob.releaseLob(g_LOBTable, tempIdx);
4302
4303 end OBSOLETE2LOBLineBreak;
4304
4305
4306 -- LOBLineBreak
4307 -- To wrap the text at textWidth but no line can exceed maLineSize
4308 -- NOTE:
4309 -- In order to be performant, the textWidth is given
4310 -- as a guide. If not natural break appears, then the nearest
4311 -- whitespace after textWidth will be used.
4312 -- Re-written for bug 4510044
4313 procedure LOBLineBreak(message IN OUT NOCOPY CLOB,
4314 textWidth in INTEGER,
4315 maxLineSize INTEGER)
4316 is
4317
4318 l_amount number := 0;
4319 l_offset number := 1;
4320 l_bufferSize number := 0;
4321 l_forcedBreak boolean := false;
4322 l_strBuffer varchar2(32000);
4323
4324 l_linesize number := textWidth;
4325
4326 l_lastCR number;
4327 l_lastWS number;
4328
4329 l_tempIdx pls_integer;
4330
4331 begin
4332
4333 l_tempIdx := wf_temp_lob.getLob(g_LOBTable);
4334
4335 l_amount := dbms_lob.getLength(message);
4336 l_offset := 1;
4337 l_bufferSize := l_lineSize;
4338 l_forcedBreak := false;
4339
4340 if(l_amount > 0) then
4341 loop
4342 l_lastCR := 0;
4343 l_forcedBreak := false;
4344 if(l_amount > l_lineSize) then
4345 dbms_lob.read(lob_loc => message, amount => l_lineSize,
4346 offset => l_offSet, buffer => l_strBuffer);
4347
4348 l_lastCR := instr(l_strBuffer, wf_core.newline, -1);
4349 l_lastWS := instr(l_strBuffer, ' ', -1);
4350
4351 if(l_lastCR > 1) then
4352 l_bufferSize := l_lastCR;
4353 elsif(l_lastWS > 1) then
4354 l_bufferSize := l_lastWS;
4355 l_forcedBreak := true;
4356 else
4357 l_bufferSize := l_lineSize;
4358 end if;
4359
4360 l_amount := l_amount - l_bufferSize;
4361 l_offset := l_offset + l_bufferSize;
4362
4363 if (l_forcedBreak) then
4364 l_strBuffer := substr(l_strBuffer, 1, l_bufferSize - 1)||
4365 wf_core.newline;
4366 -- Recalculate the buffer size incase newline is not the
4367 -- same size as the space that was removed
4368 l_bufferSize := length(l_strBuffer);
4369 end if;
4370
4371 DBMS_LOB.writeAppend(lob_loc => g_LOBTable(l_tempIdx).temp_lob,
4372 amount => l_bufferSize,
4373 buffer => l_strBuffer);
4374
4375 l_strBuffer := '';
4376 else
4377
4378 l_amount := (dbms_lob.getLength(message) - l_offset) + 1;
4379 dbms_lob.read(lob_loc => message, amount => l_amount,
4380 offset => l_offset, buffer => l_strBuffer);
4381
4382 dbms_lob.writeAppend(lob_loc => g_LOBTable(l_tempIdx).temp_lob,
4383 amount => l_amount,
4384 buffer => l_strBuffer);
4385
4386 exit;
4387 end if;
4388 end loop;
4389 DBMS_LOB.Trim(message, 0);
4390 DBMS_LOB.Copy(message, g_LOBTable(l_tempIdx).temp_lob,
4391 DBMS_LOB.GetLength(g_LOBTable(l_tempIdx).temp_lob), 1, 1);
4392
4393 DBMS_LOB.Trim(g_LOBTable(l_tempIdx).temp_lob, 0);
4394 wf_temp_lob.releaseLob(g_LOBTable, l_tempIdx);
4395 end if;
4396
4397 -- exception
4398 -- when others then
4399 -- wf_core.context('WF_MAIL', 'LOBLineBreak', to_char(textWidth));
4400 -- raise;
4401 end LOBLineBreak;
4402
4403
4404 -- GetMailTo - Construct MailTo Section (PRIVATE)
4405 -- IN
4406 -- notification id
4407 -- notification tag
4408 -- notification reply to
4409 -- notification subject
4410 -- RETURN
4411 -- mailto html tag with the subject and body
4412 procedure GetMailTo(nid in number,
4413 n_tag in varchar2,
4414 reply_to in varchar2,
4415 subject in varchar2,
4416 doc in out nocopy CLOB)
4417 is
4418 -- SQL Statement for fetching URL RESPONSE attributes.
4419 cursor c1 is
4420 select WMA.NAME, WMA.DISPLAY_NAME, WNA.TEXT_VALUE, WMA.DESCRIPTION
4421 from WF_NOTIFICATION_ATTRIBUTES WNA,
4422 WF_NOTIFICATIONS WN,
4423 WF_MESSAGE_ATTRIBUTES_VL WMA
4424 where WNA.NOTIFICATION_ID = nid
4425 and WN.NOTIFICATION_ID = WNA.NOTIFICATION_ID
4426 and WN.MESSAGE_TYPE = WMA.MESSAGE_TYPE
4427 and WN.MESSAGE_NAME = WMA.MESSAGE_NAME
4428 and WMA.NAME = WNA.NAME
4429 and WMA.SUBTYPE = 'RESPOND'
4430 and WMA.TYPE = 'URL'
4431 order by WMA.SEQUENCE;
4432
4433 lov varchar2(64);
4434 lov_list varchar2(240);
4435 str_buffer varchar2(32000);
4436 -- buffer CLOB;
4437 bufferIdx pls_integer;
4438 auto_answer varchar2(64);
4439 newline_pos number;
4440 disp_name varchar2(80);
4441 attr_type varchar2(8);
4442 attr_format varchar2(240);
4443 -- attr_value varchar2(32000);
4444 attr_desc varchar2(240);
4445 encoded_tag varchar2(240);
4446
4447 begin
4448
4449
4450
4451 -- Clear buffer
4452 str_buffer := '';
4453 -- DBMS_LOB.createTemporary(buffer, FALSE, dbms_lob.call);
4454 bufferIdx := wf_temp_lob.getLob(g_LOBTable);
4455
4456 -- URL RESPONSE attributes overrides the normal RESULT attributes.
4457 -- So, my goal here is to check for this case.
4458 -- URL RESPONSE attributes is going to appear as a anchor and don't have
4459 -- to construct the MAILTO html tag stuff that we do for the normal
4460 -- RESULT attribute.
4461
4462 -- NOTE: Please do know that I don't want to destablize the existing code
4463 -- for the normal RESULT attribute MAILTO handling so that I am coding
4464 -- these two cases seperately.
4465 -- for each response variable
4466 for rec in c1 loop
4467 str_buffer := str_buffer||'<P>';
4468 if (rec.description is not null) then
4469 str_buffer := str_buffer||rec.description||'<P>';
4470 end if;
4471 str_buffer := str_buffer|| '<A class="OraLink" HREF="'||
4472 wf_notification.geturltext(rec.text_value, nid)||
4473 '" target="_top">';
4474 str_buffer := str_buffer||'<FONT size=+1> <B>'||rec.display_name;
4475 str_buffer := str_buffer||'</B></FONT>'||'</A>';
4476 str_buffer := str_buffer||g_newLine;
4477 -- DBMS_LOB.writeAppend(buffer, length(str_buffer), str_buffer);
4478 DBMS_LOB.writeAppend(g_LOBTable(bufferIdx).temp_lob, length(str_buffer), str_buffer);
4479 str_buffer := '';
4480 end loop;
4481
4482 -- if (dbms_lob.GetLength(buffer) > 0) then
4483 if (dbms_lob.GetLength(g_LOBTable(bufferIdx).temp_lob) > 0) then
4484 -- LOBReplace(doc, '&'||'MAILTO', buffer, FALSE);
4485 LOBReplace(doc, '&'||'MAILTO', g_LOBTable(bufferIdx).temp_lob, FALSE);
4486 RETURN;
4487 end if;
4488
4489 --
4490 -- Normal RESULT attribute handling
4491 --
4492 begin
4493 select WMA.DISPLAY_NAME, WMA.TYPE, WMA.FORMAT,
4494
4495 -- <<sstomar>> : TEXT_VALUE (Attr value is not being used within this API)
4496 --
4497 --decode(WMA.TYPE,
4498 -- 'VARCHAR2', decode(WMA.FORMAT,
4499 -- '', WNA.TEXT_VALUE,
4500 -- substr(WNA.TEXT_VALUE, 1, to_number(WMA.FORMAT))),
4501 --
4502 -- 'NUMBER', decode(WMA.FORMAT,
4503 -- '', to_char(WNA.NUMBER_VALUE),
4504 -- to_char(WNA.NUMBER_VALUE, WMA.FORMAT)),
4505 -- 'DATE', decode(WMA.FORMAT,
4506 -- '', to_char(WNA.DATE_VALUE),
4507 -- to_char(WNA.DATE_VALUE, WMA.FORMAT)),
4508 -- 'LOOKUP', WNA.TEXT_VALUE,
4509 -- WNA.TEXT_VALUE),
4510 WMA.DESCRIPTION
4511 into disp_name, attr_type, attr_format, attr_desc
4512 from WF_NOTIFICATION_ATTRIBUTES WNA,
4513 WF_NOTIFICATIONS WN,
4514 WF_MESSAGE_ATTRIBUTES_VL WMA
4515 where WNA.NOTIFICATION_ID = nid
4516 and WN.NOTIFICATION_ID = WNA.NOTIFICATION_ID
4517 and WN.MESSAGE_TYPE = WMA.MESSAGE_TYPE
4518 and WN.MESSAGE_NAME = WMA.MESSAGE_NAME
4519 and WMA.NAME = WNA.NAME
4520 and WMA.SUBTYPE = 'RESPOND'
4521 and WMA.NAME = 'RESULT'
4522 and WMA.TYPE not in ('FORM', 'URL');
4523
4524 -- We can only construct answer button or mailto link if is lookup
4525 if (attr_type <> 'LOOKUP') then
4526 auto_answer := 'Respond';
4527 else
4528 -- If is LOOKUP RESULT attribute, we need to show the description here.
4529 if (attr_desc is not null) then
4530 str_buffer := str_buffer||'<P>'||attr_desc;
4531 end if;
4532 --
4533 -- e.g. WFSTD_APPROVAL lookup type
4534 auto_answer := attr_format;
4535 end if;
4536
4537 exception
4538 when no_data_found then
4539 auto_answer := 'Respond';
4540 end;
4541
4542 -- Encode any special characters
4543 encoded_tag := UrlEncode(n_tag);
4544
4545 -- Construct mailto syntax
4546 str_buffer := str_buffer||'<P>'||disp_name||': <A class="OraLink" HREF="mailto:'||reply_to||
4547 '?subject=%20'||
4548 UrlEncode(subject)||'&'||'body=%20';
4549
4550 DBMS_LOB.WriteAppend(g_LOBTable(bufferIdx).temp_lob, length(str_buffer), str_buffer);
4551
4552 str_buffer := '';
4553
4554 if (auto_answer = 'Respond') then
4555 -- NOT a LookUP Type RESULT Attribute.
4556 GetMailToBody(nid, auto_answer, g_LOBTable(bufferIdx).temp_lob);
4557
4558 str_buffer := '%0D%0A%0D%0A'||encoded_tag||'">'||'<FONT size=+1><B>'||
4559 g_noResult||'</B></FONT>'||'</A>';
4560
4561 DBMS_LOB.WriteAppend(g_LOBTable(bufferIdx).temp_lob, length(str_buffer), str_buffer);
4562 str_buffer := '';
4563
4564 ELSE -- 'LOOKUP' Type Result Attribute.
4565
4566 -- Get the LookUp codes for a Lookup type.
4567 -- e.g. WFSTD_APPROVAL : APPROVED
4568 -- : REJECTED
4569 lov_list := GetLovListInternal(auto_answer);
4570
4571 lov_list := substr(lov_list, 1, length(lov_list)-1);
4572
4573 while (lov_list is not null) loop
4574 newline_pos := instr(lov_list, g_newLine);
4575
4576 if (newline_pos = 0) then
4577 lov := lov_list;
4578 else
4579 lov := substr(lov_list, 1, newline_pos - 1);
4580 end if;
4581
4582 -- For each Lookup Code, prepare BODY with 'RESPOND' type attributes.
4583 GetMailToBody(nid, lov, g_LOBTable(bufferIdx).temp_lob);
4584
4585 str_buffer :=str_buffer||'%0D%0A%0D%0A'||encoded_tag||'">'||
4586 '<FONT size=+1><B>'||GetLovMeaning(attr_format, lov)||
4587 '</FONT></B>'||'</A>';
4588
4589 if (newline_pos = 0) then
4590 lov_list := null;
4591 if (g_moreinfo = 'REQ') then
4592 str_buffer := str_buffer || GetMoreInfoMailTo(nid, n_tag, reply_to, subject);
4593 end if;
4594 else
4595 lov_list := substr(lov_list, newline_pos+1,
4596 length(lov_list) - newline_pos);
4597 str_buffer := str_buffer||g_newLine;
4598 str_buffer := str_buffer||'&'||'nbsp;'||'&'||'nbsp;'||
4599 '<A class="OraLink" HREF="mailto:'||reply_to||
4600 '?subject=%20'||UrlEncode(subject)||'&'||'body=%20';
4601
4602 end if;
4603
4604 -- DBMS_LOB.WriteAppend(buffer, length(str_buffer), str_buffer);
4605 DBMS_LOB.WriteAppend(g_LOBTable(bufferIdx).temp_lob, length(str_buffer), str_buffer);
4606 str_buffer := '';
4607 end loop;
4608
4609 end if;
4610
4611 -- LOBReplace(doc, '&'||'MAILTO', buffer, FALSE);
4612 LOBReplace(doc, '&'||'MAILTO', g_LOBTable(bufferIdx).temp_lob, FALSE);
4613 wf_temp_lob.releaseLob(g_LOBTable, bufferIdx);
4614
4615 exception
4616 when others then
4617 wf_temp_lob.releaseLob(g_LOBTable, bufferIdx);
4618 wf_core.context('WF_MAIL', 'GetMailTo', nid);
4619 raise;
4620
4621 end GetMailTo;
4622
4623 --
4624 -- Validate_JSP_Agent
4625 -- Function to parse the given URL to check if it is a valid JSP agent.
4626 -- If the agent is from the old mailer config with /pls/wf/ or from
4627 -- APPS_FRAMEWORK_AGENT profile option without /OA_HTML/ or /pls/wf/ this
4628 -- function will return in format http://hostname.domain:port/OA_HTML/
4629 -- (The logic is based on fnd_run_function.get_jsp_agent)
4630 --
4631 function Validate_JSP_Agent(p_web_agent in varchar2)
4632 return varchar2
4633 is
4634 l_web_agent varchar2(2000);
4635 l_pos1 pls_integer;
4636 l_pos2 pls_integer;
4637 begin
4638 l_web_agent := trim(p_web_agent);
4639
4640 if (l_web_agent is not null) then
4641 -- Add a trailing slash if not available
4642 if (substr(l_web_agent, -1, 1) <> '/') then
4643 l_web_agent := l_web_agent||'/';
4644 end if;
4645
4646 -- http://
4647 l_pos1 := instrb(l_web_agent, '//', 1) + 2;
4648 -- http://hostname.domain:port/
4649 l_pos2 := instrb(l_web_agent, '/', l_pos1);
4650
4651 l_web_agent := substrb(l_web_agent, 1, l_pos2)||'OA_HTML/';
4652
4653 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
4654 wf_log_pkg.string(wf_log_pkg.level_statement,
4655 'wf.plsql.wf_mail.Validate_JSP_Agent',
4656 'Validated JSP Agent -> '||l_web_agent);
4657 end if;
4658 end if;
4659
4660 return l_web_agent;
4661
4662 exception
4663 when others then
4664 if (wf_log_pkg.level_error >= fnd_log.g_current_runtime_level) then
4665 wf_log_pkg.string(wf_log_pkg.level_error,
4666 'wf.plsql.wf_mail.Validate_JSP_Agent',
4667 'Error validating JSP Agent -> '||sqlerrm);
4668 end if;
4669 return p_web_agent;
4670 end Validate_JSP_Agent;
4671
4672 -- Returns the Applications Framework function URL
4673 function Get_Ntf_Function_URL(nid in number,
4674 n_key in varchar2,
4675 n_sig_policy in varchar2,
4676 n_override_agent in varchar2)
4677 return varchar2
4678 is
4679 url varchar2(4000);
4680 validateAccess varchar2(1);
4681 params varchar2(240);
4682 functionName varchar2(240);
4683 functionId number;
4684
4685 sig_required varchar2(1);
4686 fwk_flavor varchar2(255);
4687 email_flavor varchar2(255);
4688 render varchar2(255);
4689 begin
4690
4691 validateAccess := FND_PROFILE.value('WF_VALIDATE_NTF_ACCESS');
4692
4693 Wf_Notification.GetSignatureRequired(p_sig_policy => n_sig_policy,
4694 p_nid => nid,
4695 p_sig_required => sig_required,
4696 p_fwk_sig_flavor => fwk_flavor,
4697 p_email_sig_flavor => email_flavor,
4698 p_render_hint => render);
4699
4700 if sig_required = 'Y' then
4701 -- TODO set the correct name for hte PSIG function.
4702 functionName := 'FND_WFNTF_DETAILS';
4703 else
4704 functionName := 'FND_WFNTF_DETAILS';
4705 end if;
4706
4707 functionId := fnd_function.get_function_id (functionName);
4708
4709 -- The default set of parameters for all functions.
4710 params := 'wfMailer=Y&'||'NtfId='||to_char(nid);
4711
4712 if validateAccess = 'Y' then
4713 -- Add on the access key only when requried.
4714 params := params||'&'||'wfnkey='||n_key;
4715 end if;
4716
4717 -- Moreinfo will be globally set from the calling procedure
4718 if g_moreinfo = 'SUB' then
4719 params := params||'&'||'wfMoreinfo=Y';
4720 else -- moreinfo REQ or NULL
4721 params := params||'&'||'wfMoreinfo=N';
4722 end if;
4723
4724 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
4725 wf_log_pkg.string(WF_LOG_PKG.level_statement,
4726 'wf.plsql.WF_MAIL.Get_Ntf_Function_url',
4727 'params: {'||params||'} override agent: {'
4728 ||n_override_agent||'}');
4729 end if;
4730
4731 url := fnd_run_function.get_run_function_url(
4732 p_function_id => functionId,
4733 p_resp_appl_id => -1,
4734 p_resp_id => -1,
4735 p_security_group_id => null,
4736 p_parameters => params,
4737 p_override_agent => Validate_JSP_Agent(n_override_agent));
4738
4739 return url;
4740
4741 end get_Ntf_Function_url;
4742
4743 -- PRIVATE function to return the CLICK_HERE_TO_RESPOND value
4744 function getClickHereResponse(nid in number, n_key in varchar2,
4745 agent in varchar2, n_disp_click in varchar2,
4746 n_sig_policy in varchar2)
4747 return varchar2
4748 is
4749
4750 n_click_here varchar2(4000);
4751 l_function_id number;
4752 params varchar2(240);
4753 url varchar2(4000);
4754 validateAccess varchar2(1);
4755
4756 begin
4757 n_click_here := '<A class="OraLink" HREF="';
4758
4759 if g_install = 'EMBEDDED' then
4760 url := get_Ntf_Function_URL(nid => nid,
4761 n_key => n_key,
4762 n_sig_policy => n_sig_policy,
4763 n_override_agent => agent);
4764
4765 n_click_here := n_click_here || url;
4766
4767 else
4768 if (agent is null) then
4769 if wf_mail.send_accesskey then
4770 n_click_here := n_click_here||g_webAgent
4771 ||'/WFA_HTML.DetailLink?nid='||to_char(nid)
4772 ||'&'||'nkey='||n_key
4773 ||'&'||'agent='||g_webAgent;
4774 else
4775 n_click_here := n_click_here||g_webAgent
4776 ||'/'|| wfa_sec.DirectLogin(nid);
4777 end if;
4778 else
4779 if wf_mail.send_accesskey then
4780 n_click_here := n_click_here||agent
4781 ||'/WFA_HTML.DetailLink?nid='||to_char(nid)
4782 ||'&'||'nkey='||n_key
4783 ||'&'||'agent='||agent;
4784 else
4785 n_click_here := n_click_here||agent
4786 ||'/'|| wfa_sec.DirectLogin(nid);
4787 end if;
4788 end if;
4789 end if;
4790
4791 n_click_here := n_click_here||'">'||n_disp_click||'</A>';
4792
4793 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
4794 wf_log_pkg.string(WF_LOG_PKG.level_statement,'wf.plsql.WF_MAIL.newLOBTag',
4795 'URL: {'||n_click_here||'}');
4796 end if;
4797
4798
4799 return n_click_here;
4800
4801 end getClickHereResponse;
4802
4803 --
4804 -- setContext (PRIVATE)
4805 -- Set the context by executing the selector function
4806 -- IN
4807 -- nid - Notification id
4808 --
4809 procedure setContext(nid NUMBER)
4810 is
4811 context VARCHAR2(2000); /* Bug 2312742 */
4812 callback VARCHAR2(100);
4813 tvalue varchar2(4000);
4814 nvalue number;
4815 dvalue date;
4816
4817 sqlbuf varchar2(4000);
4818 l_dummy varchar2(1);
4819 begin
4820
4821 SELECT context, callback
4822 into context, callback
4823 FROM wf_notifications
4824 where notification_id = nid;
4825
4826 wf_engine.preserved_context := FALSE;
4827 if (callback is not null) then
4828 -- ### callback is from table
4829 -- BINDVAR_SCAN_IGNORE
4830 sqlbuf := 'begin '||callback||
4831 '(:p1, :p2, :p3, :p4, :p5, :p6, :p7); end;';
4832 execute immediate sqlbuf using
4833 in 'TESTCTX',
4834 in context,
4835 in l_dummy,
4836 in l_dummy,
4837 in out tvalue,
4838 in out nvalue,
4839 in out dvalue;
4840
4841 if (tvalue in ('FALSE', 'NOTSET')) then
4842 execute immediate sqlbuf using
4843 in 'SETCTX',
4844 in context,
4845 in l_dummy,
4846 in l_dummy,
4847 in out tvalue,
4848 in out nvalue,
4849 in out dvalue;
4850 end if;
4851 end if;
4852
4853 exception
4854 when others then
4855 WF_CORE.Context('WF_MAIL','SetContext',to_char(nid));
4856 raise;
4857 end setContext;
4858
4859 -- Get_Last_Question (Private)
4860 -- Retrieves the last More Information question
4861 -- If no question exists, then it is blank.
4862 -- IN
4863 -- p_nid - Notification ID
4864 -- OUT
4865 -- p_last_ques - Returned last question
4866 procedure Get_Last_Question(p_nid in number,
4867 p_last_ques out nocopy varchar2)
4868 is
4869
4870 CURSOR c_ques IS
4871 SELECT user_comment
4872 FROM wf_comments
4873 WHERE notification_id = p_nid
4874 AND action in ('QUESTION', 'QUESTION_WA', 'QUESTION_RULE')
4875 ORDER BY comment_date desc;
4876
4877 begin
4878
4879 -- Fetch the last question asked
4880 open c_ques;
4881 fetch c_ques into p_last_ques;
4882 if (c_ques%notfound) then
4883 p_last_ques := '';
4884 end if;
4885 close c_ques;
4886
4887 end Get_Last_Question;
4888
4889
4890 -- Get_Action_History (Private)
4891 -- Scans the notifications message definition and determines if Action History
4892 -- should be displayed
4893 -- IN
4894 -- p_nid - Notification Id
4895 -- p_lang - User Language
4896 -- OUT
4897 -- p_html_history - Action History in HTML
4898 -- p_text_history - Action History in Text
4899 -- p_last_ques - Last Question Asked if More Infor Requested
4900 procedure Get_Action_History(p_nid in number,
4901 p_lang in varchar2,
4902 p_html_history out nocopy varchar2,
4903 p_text_history out nocopy varchar2,
4904 p_last_ques out nocopy varchar2)
4905 is
4906 l_text_body varchar2(4000);
4907 l_html_body varchar2(4000);
4908 l_comm_cnt pls_integer;
4909 l_text_history varchar2(32000);
4910 l_html_history varchar2(32000);
4911 l_get_html boolean;
4912 l_get_text boolean;
4913
4914 CURSOR c_comm IS
4915 SELECT count(1)
4916 FROM wf_comments
4917 WHERE action_type in ('REASSIGN', 'QA')
4918 AND notification_id = p_nid;
4919
4920 begin
4921
4922 -- Fetch the last question asked
4923 Get_Last_Question(Get_Action_History.p_nid,
4924 Get_Action_History.p_last_ques);
4925
4926 l_get_html := false;
4927 l_get_text := false;
4928
4929 SELECT wm.body, wm.html_body
4930 INTO l_text_body, l_html_body
4931 FROM wf_notifications n, wf_messages_vl wm
4932 WHERE n.notification_id = p_nid
4933 AND n.message_name = wm.name
4934 AND n.message_type = wm.type;
4935
4936 -- FYI notification
4937 if (wf_mail.Get_FYI_Flag) then
4938 open c_comm;
4939 fetch c_comm into l_comm_cnt;
4940 if (c_comm%notfound) then
4941 l_comm_cnt := 0;
4942 end if;
4943
4944 -- If HISTORY macro is defined, Action History would appear anyways. If the FYI notification
4945 -- was reassigned at least once, include the Action History if even macro is not defined
4946 if (l_comm_cnt > 0) then
4947 if (instrb(l_text_body, 'WF_NOTIFICATION(HISTORY)') = 0) then
4948 l_get_text := true;
4949 end if;
4950 if (instrb(l_html_body, 'WF_NOTIFICATION(HISTORY)') = 0) then
4951 l_get_html := true;
4952 end if;
4953 end if;
4954 close c_comm;
4955
4956 -- Response Required notification
4957 else
4958 -- If HISTORY macro is defined, Action History would appear anyways. Otherwise
4959 -- display it in the e-mail
4960 if (instrb(l_text_body, 'WF_NOTIFICATION(HISTORY)') = 0) then
4961 l_get_text := true;
4962 end if;
4963 if (instrb(l_html_body, 'WF_NOTIFICATION(HISTORY)') = 0) then
4964 l_get_html := true;
4965 end if;
4966 end if;
4967
4968 -- Call the GetComments2 procedure to get the Action History
4969 if (l_get_text) then
4970 Wf_Notification.GetComments2(p_nid => Get_Action_History.p_nid,
4971 p_display_type => wf_notification.doc_text,
4972 p_hide_reassign => 'N',
4973 p_hide_requestinfo => 'N',
4974 p_action_history => l_text_history);
4975 end if;
4976 if (l_get_html)then
4977 Wf_Notification.GetComments2(p_nid => Get_Action_History.p_nid,
4978 p_display_type => wf_notification.doc_html,
4979 p_hide_reassign => 'N',
4980 p_hide_requestinfo => 'N',
4981 p_action_history => l_html_history);
4982 end if;
4983
4984 p_text_history := l_text_history;
4985 p_html_history := l_html_history;
4986
4987 exception
4988 when others then
4989 if (wf_log_pkg.level_exception >= fnd_log.g_current_runtime_level) then
4990 wf_log_pkg.string(WF_LOG_PKG.level_exception,
4991 'wf.plsql.wf_mail.Get_Action_History',
4992 'Get_Action_History failed. Error: ' || sqlerrm);
4993 end if;
4994 p_text_history := '';
4995 p_html_history := '';
4996 end Get_Action_History;
4997
4998
4999
5000 -- GetLOBMessage4 - get email message data as a LOB
5001 -- Bug 10202313: Added n_status, n_mstatus parameters to store the status, mail_status
5002 -- columns of wf_notifications table which are propagated from WF_XML.GenerateMessage() API
5003 --
5004 -- IN
5005 -- notification id
5006 -- mailer node name
5007 -- web agent path
5008 -- reply to
5009 -- recipient role
5010 -- lanague
5011 -- territory
5012 -- notification preference
5013 -- dsiplay name
5014 -- Render BODY token flag
5015 -- notification status
5016 -- notification mail status
5017 -- OUT
5018 -- message subject
5019 -- message body (text)
5020 -- message body (html)
5021 procedure GetLOBMessage4(
5022 nid in number,
5023 node in varchar2,
5024 agent in varchar2,
5025 replyto in varchar2,
5026 recipient in varchar2,
5027 language in varchar2,
5028 territory in varchar2,
5029 ntf_pref in varchar2,
5030 email in varchar2,
5031 dname in varchar2,
5032 renderBody in varchar2,
5033 subject out NOCOPY varchar2,
5034 body_atth out NOCOPY varchar2,
5035 error_result in out NOCOPY varchar2,
5036 bodyToken in out NOCOPY varchar2,
5037 n_status in out NOCOPY varchar2,
5038 n_mstatus in out NOCOPY varchar2)
5039 as
5040 n_key varchar2(80);
5041 n_to_role varchar2(320);
5042 n_from_user varchar2(320); -- Bug# 2094159
5043 n_due_date date;
5044 n_start_date date;
5045 n_end_date date;
5046 n_priority number;
5047 n_comment varchar2(4000);
5048 n_subject varchar2(2000);
5049 n_response varchar2(32000);
5050 n_direct varchar2(3);
5051 n_click_here varchar2(4000);
5052 n_disp_click varchar2(240);
5053 n_text_timezone varchar2(240);
5054 n_html_timezone varchar2(240);
5055 r_dname varchar2(360);
5056 r_email varchar2(2000);
5057 r_ntf_pref varchar2(240);
5058 r_language varchar2(4000);
5059 r_territory varchar2(4000);
5060 t_type varchar2(100);
5061 t_name varchar2(100);
5062 t_subject varchar2(240);
5063 t_text_body varchar2(4000);
5064 t_html_body varchar2(4000);
5065 t_hdrRequired boolean;
5066 m_html varchar2(32000);
5067 mailTo VARCHAR2(32000);
5068 t_headerText varchar2(32000);
5069 n_headerText varchar2(32000);
5070 t_headerHTML varchar2(32000);
5071 n_headerHTML varchar2(32000);
5072 err_name varchar2(30);
5073 err_message varchar2(2000);
5074 err_stack varchar2(4000);
5075 str_dummy varchar2(4000) := NULL;
5076 fyi pls_integer;
5077 body_start pls_integer;
5078 body_end pls_integer;
5079 tmp_start pls_integer;
5080 tmp_end pls_integer;
5081 tag_pos pls_integer;
5082 dir_pos pls_integer;
5083 start_cnt pls_integer;
5084 end_cnt pls_integer;
5085 str_length pls_integer;
5086 end_of_message boolean;
5087 buffer VARCHAR2(32767);
5088
5089 no_program_unit exception;
5090 pragma exception_init(no_program_unit, -6508);
5091 dummy varchar2(4000);
5092 -- Bug# 2301881 variables to handle invalid response error message
5093 err_invalid varchar2(2000);
5094 err_expected varchar2(2000);
5095 n_sig_policy varchar2(100);
5096 n_nid_str varchar2(200);
5097 -- More Info feature bug 2282139
5098 n_more_info_role varchar2(320);
5099 n_mailto varchar2(10000);
5100 n_text_history varchar2(32000);
5101 n_html_history varchar2(32000);
5102 n_last_ques varchar2(4000);
5103 n_dir varchar2(16);
5104
5105 step varchar2(200);
5106 textForHtml boolean;
5107
5108 htmlBodyPos pls_integer;
5109 textBodyPos pls_integer;
5110
5111 n_start_date2 varchar2(64);
5112
5113 begin
5114
5115 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
5116 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
5117 'wf.plsql.WF_MAIL.GetLOBMessage4', 'BEGIN');
5118 end if;
5119
5120 -- 3532615 Moved these from being initialized at the session level
5121 -- back to the notification level.
5122 g_ntfHistory := wf_core.translate('WFNTF_HISTORY');
5123 g_ntfActionHistory := wf_core.translate('WFNTF_ACTION_HISTORY');
5124 g_moreInfoAPrompt := wf_core.translate('WFNTF_MOREINFO_APROMPT');
5125 g_moreInfoAnswer := wf_core.translate('WFNTF_MOREINFO_ANSWER');
5126 g_moreInfoQPrompt := wf_core.translate('WFNTF_MOREINFO_QPROMPT');
5127 g_moreInfoSubject := wf_core.translate('WFNTF_MOREINFO');
5128 g_moreInfoSubmit := wf_core.translate('WFNTF_MOREINFO_SUBMIT');
5129 g_moreInfoQuestion := wf_core.translate('WFNTF_MOREINFO_QUESTION');
5130 g_moreInfoFrom := wf_core.translate('WFNTF_MOREINFO_FROM');
5131 g_moreInfoRequested := wf_core.translate('WFNTF_MOREINFO_REQUESTED');
5132 g_moreInfoRequestee := wf_core.translate('WFNTF_MOREINFO_REQUESTEE');
5133 g_wfmonId := wf_core.translate('WFMON_ID');
5134 g_to := wf_core.translate('TO');
5135 g_from := wf_core.translate('FROM');
5136
5137 g_beginDate := wf_core.translate('BEGIN_DATE');
5138 g_dueDate2 := wf_core.translate('DUE_DATE');
5139 g_notificationId := wf_core.translate('NOTIFICATION_ID');
5140 g_priority := wf_core.translate('PRIORITY');
5141
5142 g_dueDate := wf_core.translate('WFMON_DUE_DATE');
5143
5144 g_invalidRemarks := wf_core.translate('WFMLR_INVALID_REMARKS');
5145 g_forExample := wf_core.translate('WFMLR_FOR_EXAMPLE');
5146 g_soOn := wf_core.translate('WFMLR_SO_ON');
5147 g_none := wf_core.translate('WFMLR_NONE');
5148 g_truncate := wf_core.translate('WFNTF_TRUNCATE');
5149 g_noResult := wf_core.translate('WFNTF_NO_RESULT');
5150 g_Id := wf_core.translate('ID');
5151
5152 step := 'Getting notification information';
5153 -- Get notification information
5154 begin
5155 select ACCESS_KEY,
5156 PRIORITY, USER_COMMENT,
5157 BEGIN_DATE, END_DATE, DUE_DATE, FROM_USER,
5158 MORE_INFO_ROLE
5159 into n_key,
5160 n_priority, n_comment,
5161 n_start_date, n_end_date, n_due_date, n_from_user,
5162 n_more_info_role
5163 from WF_NOTIFICATIONS
5164 where NOTIFICATION_ID = nid;
5165 exception
5166 when no_data_found then
5167 wf_core.token('NID', to_char(nid));
5168 wf_core.raise('WFNTF_NID');
5169 end;
5170
5171
5172 n_to_role := recipient;
5173 r_language := language;
5174 r_territory := territory;
5175 r_ntf_pref := ntf_pref;
5176 r_email := email;
5177 r_dname := dname;
5178
5179
5180 -- More information processing
5181 g_moreinfo := NULL;
5182 if (wf_notification.HideMoreInfo(nid) = 'N') then
5183 if(n_more_info_role is not null) then
5184 n_to_role := n_more_info_role;
5185 g_to_role := n_more_info_role;
5186 -- Flags that template for More Info submission needs to be used
5187 g_moreinfo := 'SUB';
5188 else
5189 -- Flags that template for More Info request needs to be used
5190 g_to_role := n_to_role;
5191 g_moreinfo := 'REQ';
5192 end if;
5193 end if;
5194
5195 r_ntf_pref := nvl(r_ntf_pref, 'QUERY');
5196
5197 step := 'Getting Signature policy';
5198 -- Bug 2375920 get signature policy for the notification
5199 Wf_Mail.GetSignaturePolicy(nid, n_sig_policy);
5200
5201 -- Bug 2375920 Process the email message based on the signature policy
5202 ProcessSignaturePolicy(nid, n_sig_policy, n_status, n_mstatus,
5203 n_key, node, t_type, t_name, n_nid_str);
5204
5205 if isBiDi(r_language) then
5206 WF_NOTIFICATION.Set_NTF_Table_Direction('R');
5207 else
5208 WF_NOTIFICATION.Set_NTF_Table_Direction('L');
5209 end if;
5210
5211 -- PLSQL Action History for the notification will not be explicitly processed by the
5212 -- mailer now. The notification sub-system would handle this as part of GetFullBody.
5213
5214 -- if (renderBody = 'Y') then
5215 -- step := 'Getting action history';
5216 -- Get_Action_History(nid, r_language, n_html_history, n_text_history,
5217 -- n_last_ques);
5218 -- else
5219 Get_Last_Question(nid, n_last_ques);
5220 n_html_history := '';
5221 n_text_history := '';
5222 -- end if;
5223
5224 step := 'Getting template';
5225 -- Get template
5226 begin
5227 select SUBJECT, BODY, HTML_BODY
5228 into t_subject, t_text_body, t_html_body
5229 from WF_MESSAGES_VL
5230 where NAME = t_name and TYPE = t_type;
5231 exception
5232 when no_data_found then
5233 wf_core.token('NAME', t_name);
5234 wf_core.token('TYPE', t_type);
5235 wf_core.raise('WFNTF_MESSAGE');
5236 end;
5237
5238 g_isFwkNtf := true;
5239 if (t_name in ('VIEW_FROMUI', 'VIEW_FROMUI_FYI')) then
5240 t_hdrRequired := TRUE;
5241 elsif renderBody = 'Y' then
5242 t_hdrRequired := TRUE;
5243 g_isFwkNtf := false;
5244 else
5245 t_hdrRequired := FALSE;
5246 g_isFwkNtf := true;
5247 end if;
5248
5249 step := 'Getting timezone details';
5250 n_text_timezone := wf_mail_util.getTimezone(g_ntfDocText);
5251 n_html_timezone := wf_mail_util.getTimezone(g_ntfDocHtml);
5252
5253 step := 'Getting subject';
5254 n_subject := WF_NOTIFICATION.GetSubject(nid, 'text/plain');
5255
5256 -- We will always fetch plain text version of the message because
5257 -- Because for sendmail MAILATTH case, we need to send out html message
5258 -- body as attachment and then the plain text message as the body.
5259 -- For MAPI MAILATTH and MAILHTML cases, same thing.
5260
5261 -- we will request a temp LOB from the pool only if necessary
5262 -- we donot need the text message if the ntf pref is MAILHTML
5263 -- this will reduce the time spent in unecessarily processing
5264 -- the text LOB Message
5265 t_headerText := '';
5266 t_headerHTML := '';
5267 step := 'Getting body';
5268 if (r_ntf_pref in ('MAILTEXT', 'MAILATTH')) then
5269 -- Below Allocated TEMP LOB here is released within WF_XML.getBodyPart
5270 -- ( which is called by caller of GetLOBMessage4 API)
5271 -- based on the Ntf type (text/plain or text/html) by calling wf_mail.CloseLOB
5272 g_text_messageIdx := wf_temp_lob.getLob(g_LOBTable);
5273
5274 if (renderbody = 'Y') then
5275 end_of_message := FALSE;
5276 step := 'Getting text/plain body';
5277 begin
5278 while not (end_of_message) loop
5279 WF_NOTIFICATION.GetFullBody(nid, buffer, end_of_message,
5280 g_ntfDocText);
5281 if buffer is not null and length(buffer) > 0 then
5282 DBMS_LOB.WriteAppend(g_LOBTable(g_text_messageIdx).temp_lob,
5283 length(buffer), buffer);
5284 end if;
5285 end loop;
5286 exception
5287 when others then
5288
5289 wf_core.context('WF_MAIL','GetLOBMessage4',
5290 'nid => '||to_char(nid),
5291 'r_ntf_pref => '||r_ntf_pref);
5292 wf_core.token('ERROR',sqlerrm);
5293 wf_core.raise('WFMLR_NTFERR');
5294 end;
5295 -- Get the table of header attributes. Use a PL/SQL document
5296 -- API format.
5297 end if; -- RENDERBODY
5298 if (t_hdrRequired = TRUE) then
5299 GetHeaderTable(r_language||':'||to_char(nid),
5300 g_ntfDocText, t_headerText, str_dummy);
5301 end if;
5302 end if;
5303
5304 if (r_ntf_pref in ('MAILHTML', 'MAILATTH', 'MAILHTM2')) then
5305 -- Below Allocated TEMP LOB IS released within WF_XML.getBodyPart
5306 -- based on the Ntf type (text/plain or text/html) by calling wf_mail.CloseLOB
5307 g_html_messageIdx := wf_temp_lob.getLob(g_LOBTable);
5308
5309 if (renderbody = 'Y') then
5310 end_of_message := FALSE;
5311 step := 'Getting text/html body';
5312 begin
5313 while not (end_of_message) loop
5314 WF_NOTIFICATION.GetFullBody(nid, buffer, end_of_message,
5315 g_ntfDocHtml);
5316 if buffer is not null and length(buffer) > 0 then
5317 DBMS_LOB.WriteAppend(g_LOBTable(g_html_messageIdx).temp_lob,
5318 length(buffer), buffer);
5319 end if;
5320 end loop;
5321 exception
5322 when others then
5323 wf_core.context('WF_MAIL','GetLOBMessage4',
5324 'nid => '||to_char(nid),
5325 'r_ntf_pref => '||r_ntf_pref);
5326 wf_core.token('ERROR',sqlerrm);
5327 wf_core.raise('WFMLR_NTFERR');
5328 end;
5329
5330 end if; -- RENDERBODY
5331 if (t_hdrRequired = TRUE) then
5332 GetHeaderTable(r_language||':'||to_char(nid),
5333 g_ntfDocHtml, t_headerHTML, str_dummy);
5334
5335
5336 end if;
5337 end if;
5338
5339
5340 step := 'Getting click-here section';
5341 -- Get Click here Response display value
5342 begin
5343 select DESCRIPTION
5344 into n_disp_click
5345 from WF_MESSAGE_ATTRIBUTES_TL
5346 where MESSAGE_TYPE = t_type
5347 and MESSAGE_NAME = t_name
5348 and NAME = 'CLICK_HERE_RESPONSE'
5349 and LANGUAGE = userenv('LANG');
5350 exception
5351 when NO_DATA_FOUND then
5352 -- ignore if this attribute does not exist
5353 null;
5354 end;
5355
5356 step := 'Getting error information for invalid response';
5357 -- Retrieve error attributes for INVALID message
5358 -- Bug# 2301881 Replacing err_stack with err_invalid and err_expected
5359 -- to make the WARNING message to the responder more
5360 -- user-friendly
5361 if (t_name in ('OPEN_INVALID', 'OPEN_INVALID_MORE_INFO')) then
5362 begin
5363 err_name := Wf_Notification.GetAttrText(nid, 'MAIL_ERROR_NAME');
5364 err_message := Wf_Notification.GetAttrText(nid, 'MAIL_ERROR_MESSAGE');
5365 err_invalid := Wf_Notification.GetAttrText(nid, 'MAIL_VALUE_FOUND');
5366 err_expected := Wf_Notification.GetAttrText(nid, 'MAIL_EXP_VALUES');
5367 exception
5368 when others then null;
5369 end;
5370 end if;
5371
5372 -- If there is no html template available, use the plain text one.
5373 step := 'Setting content to the template';
5374 if (t_html_body is null) then
5375 t_html_body := replace(t_text_body, g_newLine,
5376 '<BR>'||g_newLine);
5377 -- Ensure the direction of the text is correct for the language
5378 textForHtml := true;
5379 if isBiDi(r_language) then
5380 t_html_body := '<HTML DIR="RTL"><BODY>'||t_html_body;
5381 else
5382 t_html_body := '<HTML><BODY>'||t_html_body;
5383 end if;
5384 else
5385 -- Ensure that the direction of the text is correctly specified.
5386 if isBiDi(r_language) then
5387 tag_pos := instrb(upper(t_html_body), '<HTML', 1);
5388 if tag_pos > 0 then
5389 dir_pos := instrb(upper(t_html_body), ' DIR="', 1);
5390 if dir_pos = 0 then
5391 buffer := substrb(t_html_body, 1, tag_pos+4);
5392 buffer := buffer||' DIR="RTL" '||substrb(t_html_body, tag_pos+5);
5393 t_html_body := buffer;
5394 end if;
5395 end if;
5396 end if;
5397 end if;
5398
5399 -- DBMS_LOB.Write(template_html, length(t_html_body), 1, t_html_body);
5400
5401 if wf_mail.direct_response then
5402 n_direct := '[2]';
5403 else
5404 n_direct := NULL;
5405 end if;
5406
5407 -- More info feature
5408 if (g_moreinfo = 'SUB') then
5409 n_response := g_moreInfoAPrompt || ': '||wf_mail.g_open_text_delimiter||
5410 '<' ||
5411 g_moreInfoAnswer ||'>'||wf_mail.g_close_text_delimiter;
5412 n_response := n_response || g_newLine;
5413 else
5414 if wf_mail.direct_response then
5415 n_response := GetEmailDirectResponse(nid);
5416 else
5417 n_response := GetEmailResponse(nid);
5418 end if;
5419 end if;
5420
5421 -- Substitute
5422
5423 htmlBodyPos := instrb(t_html_body, '&'||'BODY',1, 1);
5424 textBodyPos := instrb(t_text_body, '&'||'BODY',1, 1);
5425
5426 if (htmlBodyPos > 0 or textBodyPos > 0) then
5427 bodyToken := 'Y';
5428 else
5429 bodyToken := 'N';
5430 end if;
5431
5432 step := 'Performing token substitution';
5433 n_subject := Substitute(t_subject, nid, n_nid_str,
5434 n_status, n_to_role, r_dname, r_email,
5435 n_start_date, n_due_date, n_end_date, n_from_user,
5436 n_priority, n_comment, n_subject, str_dummy,
5437 str_dummy, err_name, err_message, err_invalid,
5438 err_expected, n_text_timezone);
5439
5440 if (r_ntf_pref in ('MAILTEXT', 'MAILATTH')) then
5441
5442 n_headerText := Substitute(t_headerText, nid, n_nid_str,
5443 n_status, n_to_role, r_dname, r_email,
5444 n_start_date, n_due_date, n_end_date, n_from_user,
5445 n_priority, n_comment, n_subject, str_dummy,
5446 str_dummy, err_name, err_message, err_invalid,
5447 err_expected, n_text_timezone);
5448 LOBSubstitute(t_text_body, nid, n_nid_str,
5449 n_status, n_to_role, r_dname, r_email,
5450 n_start_date, n_due_date, n_end_date, n_from_user,
5451 n_priority, n_comment, n_subject, n_headerText,
5452 g_LOBTable(g_text_messageIdx).temp_lob,
5453 err_name, err_message, err_invalid,
5454 err_expected, n_text_timezone);
5455
5456 -- Wrap the body into nice pretty lines.
5457 LOBLineBreak(g_LOBTable(g_text_messageIdx).temp_lob, wf_linelen, 999);
5458
5459 -- Add email response section
5460 LOBReplace(g_LOBTable(g_text_messageIdx).temp_lob,
5461 '&'||'RESPONSE', n_response, FALSE);
5462
5463 -- More Information Processing - Bug 2282139
5464 LOBReplace(g_LOBTable(g_text_messageIdx).temp_lob,
5465 '&'||'HISTORY', n_text_history, FALSE);
5466 LOBReplace(g_LOBTable(g_text_messageIdx).temp_lob,
5467 '&'||'QUESTION', n_last_ques, FALSE);
5468 end if;
5469
5470 if (r_ntf_pref in ('MAILHTML', 'MAILATTH', 'MAILHTM2')) then
5471
5472 n_headerHTML := Substitute(t_headerHTML, nid, n_nid_str,
5473 n_status, n_to_role, r_dname, r_email,
5474 n_start_date, n_due_date, n_end_date, n_from_user,
5475 n_priority, n_comment, n_subject, str_dummy,
5476 str_dummy, err_name, err_message, err_invalid,
5477 err_expected, n_html_timezone);
5478
5479
5480 LOBSubstitute(t_html_body, nid, n_nid_str,
5481 n_status, n_to_role, r_dname, r_email,
5482 n_start_date, n_due_date, n_end_date,
5483 n_from_user, n_priority, n_comment,
5484 UrlEncode(n_subject), n_headerHTML,
5485 g_LOBTable(g_html_messageIdx).temp_lob,
5486 err_name, err_message, err_invalid,
5487 err_expected, n_html_timezone);
5488
5489 -- Add the local stylesheet references.
5490 LOBReplace(g_LOBTable(g_html_messageIdx).temp_lob,
5491 '&'||'TEMPLATE_STYLE', g_template_style, FALSE);
5492
5493 -- Add email response section
5494 LOBReplace(g_LOBTable(g_html_messageIdx).temp_lob,
5495 '&'||'RESPONSE', n_response, FALSE);
5496
5497 -- More Information processing
5498 LOBReplace(g_LOBTable(g_html_messageIdx).temp_lob,
5499 '&'||'HISTORY', n_html_history, FALSE);
5500 LOBReplace(g_LOBTable(g_html_messageIdx).temp_lob,
5501 '&'||'QUESTION', n_last_ques, FALSE);
5502
5503 -- Add mailto section
5504 if (g_moreinfo = 'SUB') then
5505 n_mailto := GetMoreInfoMailTo(nid, 'NID['||to_char(nid)||'/'
5506 ||n_key||'@'||node||']', replyTo, n_subject);
5507
5508 LOBReplace(g_LOBTable(g_html_messageIdx).temp_lob,
5509 '&'||'MAILTO', n_mailto, FALSE);
5510 else
5511 -- Overloaded : LOB specific is being called.
5512 GetMailTo(nid, 'NID['||to_char(nid)||'/'||n_key||'@'|| node||']',
5513 replyTo, n_subject, g_LOBTable(g_html_messageIdx).temp_lob);
5514 end if;
5515
5516 -- If GUEST access is enabled and signature is required for response,
5517 -- no click here reponse link is provided to discourage signing under
5518 -- GUEST login
5519 if (g_sig_required = 'Y' and wf_mail.Send_AccessKey) then
5520 n_click_here := '';
5521 else
5522 n_click_here := getClickHereResponse(nid => nid, n_key => n_key,
5523 agent => agent,
5524 n_disp_click => n_disp_click,
5525 n_sig_policy => n_sig_policy);
5526 end if;
5527
5528 LOBReplace(g_LOBTable(g_html_messageIdx).temp_lob,
5529 '&'||'CLICK_HERE_RESPONSE', n_click_here, FALSE);
5530
5531 -- Close of the HTML Body only where this is none
5532 -- This is only done for those tempaltes that the html/body tag
5533 -- was added. Otherwise there is a clash where there is nested
5534 -- HTML. Since this is rendered in a LOB, there should be no
5535 -- cause for the exising end /body tag should drop off the end
5536 -- like what would happen in the varchar2 version.
5537 if textForHtml then
5538 DBMS_LOB.WriteAppend(g_LOBTable(g_html_messageIdx).temp_lob,
5539 length('</BODY></HTML>'), '</BODY></HTML>');
5540 end if;
5541
5542 end if;
5543
5544 step := 'Getting HTML attachment';
5545 -- Get HTML attachment
5546 m_html := substrb(WFA_HTML.Detail2(nid, n_key, agent), 1, 32000);
5547 if isBiDi(r_language) then
5548 tag_pos := instrb(upper(m_html), '<HTML', 1);
5549 if tag_pos > 0 then
5550 dir_pos := instrb(upper(m_html), ' DIR="', 1);
5551 if dir_pos = 0 then
5552 buffer := substrb(m_html, 1, 5);
5553 buffer := buffer||' DIR="RTL" '||substrb(m_html, tag_pos+5);
5554 m_html := buffer;
5555 end if;
5556 end if;
5557 end if;
5558
5559 subject := n_subject;
5560 -- text_body := n_text_body;
5561 -- html_body := n_html_body;
5562 -- this is for the little attachment to the detail frame
5563 body_atth := m_html;
5564
5565 -- if (DBMS_LOB.IsOpen(template_text)=1) then
5566 -- DBMS_LOB.Close(template_text);
5567 -- DBMS_LOB.FreeTemporary(template_text);
5568 -- end if;
5569 -- if (DBMS_LOB.IsOpen(template_html)=1) then
5570 -- DBMS_LOB.Close(template_html);
5571 -- DBMS_LOB.FreeTemporary(template_html);
5572 -- end if;
5573
5574 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
5575 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
5576 'wf.plsql.WF_MAIL.GetLOBMessage4', 'END');
5577 end if;
5578
5579 exception
5580 when no_program_unit then
5581 wf_core.context('WF_MAIL', 'GetLOBMessage4', to_char(nid), node,
5582 'step -> '||step);
5583
5584 if(g_html_messageIdx IS NOT NULL AND g_html_messageIdx > 0 ) then
5585 wf_temp_lob.releaseLob(g_LOBTable, g_html_messageIdx);
5586 end if;
5587
5588 if(g_text_messageIdx IS NOT NULL AND g_text_messageIdx > 0 ) then
5589 wf_temp_lob.releaseLob(g_LOBTable, g_text_messageIdx);
5590 end if;
5591
5592 raise;
5593 when others then
5594 -- First look for a wf_core error.
5595 wf_core.get_error(err_name, err_message, err_stack);
5596 -- If no wf_core error look for a sql error.
5597 if (err_name is null) then
5598 err_message := sqlerrm;
5599 end if;
5600
5601 if(g_html_messageIdx is not null and g_html_messageIdx > 0 ) then
5602 wf_temp_lob.releaseLob(g_LOBTable, g_html_messageIdx);
5603 end if;
5604
5605 if(g_text_messageIdx is not null and g_text_messageIdx > 0 ) then
5606 wf_temp_lob.releaseLob(g_LOBTable, g_text_messageIdx);
5607 end if;
5608
5609 error_result := err_message||g_newLine||err_stack;
5610 wf_core.context('WF_MAIL', 'GetLOBMessage4', to_char(nid), node,
5611 error_result, 'Step -> '||step);
5612 end GetLOBMessage4;
5613
5614
5615 -- GetLOBMessage3 - get email message data as a LOB
5616 --
5617 -- IN
5618 -- notification id
5619 -- mailer node name
5620 -- web agent path
5621 -- reply to
5622 -- recipient role
5623 -- lanague
5624 -- territory
5625 -- notification preference
5626 -- dsiplay name
5627 -- Render BODY token flag
5628 -- OUT
5629 -- message subject
5630 -- message body (text)
5631 -- message body (html)
5632 procedure GetLOBMessage3(
5633 nid in number,
5634 node in varchar2,
5635 agent in varchar2,
5636 replyto in varchar2,
5637 recipient in varchar2,
5638 language in varchar2,
5639 territory in varchar2,
5640 ntf_pref in varchar2,
5641 email in varchar2,
5642 dname in varchar2,
5643 renderBody in varchar2,
5644 subject out NOCOPY varchar2,
5645 body_atth out NOCOPY varchar2,
5646 error_result in out NOCOPY varchar2,
5647 bodyToken in out NOCOPY varchar2)
5648
5649 as
5650
5651 n_status varchar2(20);
5652 n_mstatus varchar2(20);
5653
5654 no_program_unit exception;
5655 pragma exception_init(no_program_unit, -6508);
5656
5657 err_name varchar2(30);
5658 err_message varchar2(2000);
5659 err_stack varchar2(4000);
5660
5661 begin
5662
5663 begin
5664 select status,
5665 mail_status
5666 into n_status,
5667 n_mstatus
5668 from WF_NOTIFICATIONS
5669 where NOTIFICATION_ID = nid;
5670 exception
5671 when no_data_found then
5672 wf_core.token('NID', to_char(nid));
5673 wf_core.raise('WFNTF_NID');
5674 end;
5675
5676
5677 wf_mail.getLobMessage4(nid, node, agent, replyto, recipient, language,
5678 territory, ntf_pref, email, dname, 'Y',
5679 subject, body_atth, error_result, bodyToken, n_status, n_mstatus);
5680
5681 exception
5682 when no_program_unit then
5683 wf_core.context('WF_MAIL', 'GetLOBMessage3', to_char(nid), node);
5684 raise;
5685 when others then
5686 -- First look for a wf_core error.
5687 wf_core.get_error(err_name, err_message, err_stack);
5688
5689 -- If no wf_core error look for a sql error.
5690 if (err_name is null) then
5691 err_message := sqlerrm;
5692 end if;
5693
5694 error_result := err_message||g_newLine||err_stack;
5695 wf_core.context('WF_MAIL', 'GetLOBMessage3', to_char(nid), node,
5696 error_result);
5697
5698 end getLOBMessage3;
5699
5700
5701 -- GetLOBMessage2 - get email message data as a LOB
5702 --
5703 -- IN
5704 -- notification id
5705 -- mailer node name
5706 -- web agent path
5707 -- reply to
5708 -- recipient role
5709 -- lanague
5710 -- territory
5711 -- notification preference
5712 -- dsiplay name
5713 -- OUT
5714 -- message subject
5715 -- message body (text)
5716 -- message body (html)
5717 procedure GetLOBMessage2(
5718 nid in number,
5719 node in varchar2,
5720 agent in varchar2,
5721 replyto in varchar2,
5722 recipient in varchar2,
5723 language in varchar2,
5724 territory in varchar2,
5725 ntf_pref in varchar2,
5726 email in varchar2,
5727 dname in varchar2,
5728 subject out NOCOPY varchar2,
5729 body_atth out NOCOPY varchar2,
5730 error_result in out NOCOPY varchar2)
5731 as
5732
5733 err_name varchar2(30);
5734 err_message varchar2(2000);
5735 err_stack varchar2(4000);
5736
5737 bodyToken varchar2(1);
5738
5739 no_program_unit exception;
5740 pragma exception_init(no_program_unit, -6508);
5741
5742 begin
5743
5744 wf_mail.getLobMessage3(nid, node, agent, replyto, recipient, language,
5745 territory, ntf_pref, email, dname, 'Y',
5746 subject, body_atth, error_result, bodyToken);
5747
5748 exception
5749 when no_program_unit then
5750 wf_core.context('WF_MAIL', 'GetLOBMessage2', to_char(nid), node);
5751 raise;
5752 when others then
5753 -- First look for a wf_core error.
5754 wf_core.get_error(err_name, err_message, err_stack);
5755
5756 -- If no wf_core error look for a sql error.
5757 if (err_name is null) then
5758 err_message := sqlerrm;
5759 end if;
5760
5761 error_result := err_message||g_newLine||err_stack;
5762 wf_core.context('WF_MAIL', 'GetLOBMessage2', to_char(nid), node,
5763 error_result);
5764
5765 end getLOBMessage2;
5766
5767
5768 -- GetLOBMessage - get email message data as a LOB
5769 --
5770 -- IN
5771 -- notification id
5772 -- mailer node name
5773 -- web agent path
5774 -- OUT
5775 -- message subject
5776 -- message body (text)
5777 -- message body (html)
5778 procedure GetLOBMessage(
5779 nid in number,
5780 node in varchar2,
5781 agent in varchar2,
5782 replyto in varchar2,
5783 subject out NOCOPY varchar2,
5784 body_atth out NOCOPY varchar2,
5785 error_result in out NOCOPY varchar2)
5786 as
5787 n_to_role varchar2(320);
5788 r_dname varchar2(360);
5789 r_email varchar2(2000);
5790 r_ntf_pref varchar2(240);
5791 r_language varchar2(30);
5792 r_territory varchar2(30);
5793 r_orig_system varchar2(30);
5794 r_orig_system_id number;
5795 r_installed varchar2(1);
5796 err_name varchar2(30);
5797 err_message varchar2(2000);
5798 err_stack varchar2(4000);
5799
5800 no_program_unit exception;
5801 pragma exception_init(no_program_unit, -6508);
5802
5803 begin
5804 -- Get notification information
5805 begin
5806 select RECIPIENT_ROLE
5807 into n_to_role
5808 from WF_NOTIFICATIONS
5809 where NOTIFICATION_ID = nid;
5810 exception
5811 when no_data_found then
5812 wf_core.token('NID', to_char(nid));
5813 wf_core.raise('WFNTF_NID');
5814 end;
5815
5816 -- Get Recipient information
5817 Wf_Directory.GetRoleInfoMail(n_to_role, r_dname, r_email, r_ntf_pref,
5818 r_language, r_territory, r_orig_system,
5819 r_orig_system_id, r_installed);
5820
5821 if r_installed = 'N' then
5822 r_language := 'AMERICAN';
5823 r_territory := 'AMERICA';
5824 end if;
5825
5826 wf_mail.getLobMessage2(nid, node, agent, replyto, n_to_role, r_language,
5827 r_territory, r_ntf_pref, r_email, r_dname,
5828 subject, body_atth, error_result);
5829
5830 exception
5831 when no_program_unit then
5832 wf_core.context('WF_MAIL', 'GetLOBMessage', to_char(nid), node);
5833 raise;
5834 when others then
5835 -- First look for a wf_core error.
5836 wf_core.get_error(err_name, err_message, err_stack);
5837
5838 -- If no wf_core error look for a sql error.
5839 if (err_name is null) then
5840 err_message := sqlerrm;
5841 end if;
5842
5843 error_result := err_message||g_newLine||err_stack;
5844 wf_core.context('WF_MAIL', 'GetLOBMessage', to_char(nid), node,
5845 error_result);
5846 end GetLOBMessage;
5847
5848 -- GetSummary - get summary messages for one role
5849 -- ( with LOB support )
5850 -- IN
5851 -- role name
5852 -- display role name
5853 -- mailer node name
5854 -- OUT
5855 -- message subject
5856 -- message body (text)
5857 -- message body (html)
5858 procedure GetSummary(
5859 role in varchar2,
5860 dname in varchar2,
5861 node in varchar2,
5862 subject out NOCOPY varchar2,
5863 body_text out NOCOPY varchar2)
5864 as
5865 lob varchar2(1);
5866 begin
5867 GetSummary(role, dname, node, subject, body_text,lob);
5868 if lob = 'Y' then
5869 wf_core.context('WF_MAIL', 'GetSummary', role, node);
5870 wf_core.raise('WFMLR_SUMMARY_TOOBIG');
5871 end if;
5872 exception
5873 when others then
5874 wf_core.context('WF_MAIL', 'GetSummary', role, node);
5875 raise;
5876 end GetSummary;
5877
5878 -- GetSummary2 - get summary messages for one role
5879 -- Support the render flag for Applications Framework.
5880 -- If set, no body will be rendered as it will be
5881 -- deferred to the middle tier.
5882 -- IN
5883 -- role name
5884 -- display role name
5885 -- mailer node name
5886 -- content type
5887 -- OUT
5888 -- message subject
5889 -- message body (text)
5890 -- message body (html)
5891 -- lob (Y or N)
5892 procedure GetSummary2(
5893 role in varchar2,
5894 dname in varchar2,
5895 node in varchar2,
5896 renderBody in varchar2,
5897 contType in varchar2,
5898 subject out NOCOPY varchar2,
5899 body_text out NOCOPY varchar2,
5900 lob out NOCOPY varchar2)
5901 as
5902 n_key varchar2(80);
5903 n_subject varchar2(240);
5904 n_summ varchar2(32000);
5905 n_buf varchar2(32000);
5906 templateName varchar2(30);
5907 altTempl varchar2(40);
5908 templateType varchar2(8) := 'WFMAIL';
5909 t_subject varchar2(240);
5910 t_body varchar2(32000);
5911 t_timezone varchar2(240);
5912 t_html_body varchar2(32000);
5913 n_timezone varchar2(240);
5914 nid pls_integer;
5915 to_name varchar2(320);
5916 colon pls_integer;
5917 rorig_system varchar2(30);
5918 rorig_system_id number;
5919 priority_text varchar2(240);
5920
5921 ntf_pref varchar2(240);
5922 dummyStr varchar2(2000);
5923 r_language varchar2(30);
5924 r_displayName varchar2(360);
5925 tag_pos pls_integer;
5926 dir_pos pls_integer;
5927 buffer varchar2(32000);
5928
5929
5930 lob_init boolean := FALSE;
5931 -- temp_text CLOB;
5932 temp_textIdx pls_integer;
5933
5934 -- Bug 1753464 included sort order for the query
5935 -- Bug 2439529 Altered query to use UNION instead of OR.
5936 cursor c1 is
5937 select NOTIFICATION_ID, RECIPIENT_ROLE, ACCESS_KEY, PRIORITY, DUE_DATE
5938 from WF_NOTIFICATIONS
5939 where STATUS = 'OPEN'
5940 and RECIPIENT_ROLE IN
5941 (select role from dual
5942 union
5943 select UR.ROLE_NAME
5944 from WF_USER_ROLES UR
5945 where UR.USER_ORIG_SYSTEM = rorig_system
5946 and UR.USER_ORIG_SYSTEM_ID = rorig_system_id
5947 and UR.USER_NAME = role)
5948 order by PRIORITY desc, DUE_DATE asc, NOTIFICATION_ID asc ;
5949
5950 begin
5951
5952 if (wf_log_pkg.level_event >= fnd_log.g_current_runtime_level) then
5953 wf_log_pkg.string(wf_log_pkg.level_event,
5954 'wf.plsql.WF_MAIL.GetSummary2',
5955 'BEGIN');
5956 end if;
5957
5958 g_wfmonId := wf_core.translate('WFMON_ID');
5959 g_to := wf_core.translate('TO');
5960 g_priority := wf_core.translate('PRIORITY');
5961 g_dueDate := wf_core.translate('WFMON_DUE_DATE');
5962
5963 -- Bug# 2358498 - flag to indicate if the sumamry is LOB
5964 lob := 'N';
5965
5966 if (renderBody = 'Y') then
5967 templateName := 'SUMMARY';
5968 else
5969 templateName := 'SUMHTML';
5970 end if;
5971
5972 -- We have the basic template name. Now check to see if has been
5973 -- redirected using a mailer configuration parameter of the same name.
5974 altTempl := WF_MAILER_PARAMETER.GetValueForCorr('WFMAIL', templateName);
5975 colon := instrb(altTempl, ':', 1);
5976 if colon > 0 then
5977 templateType := substrb(altTempl, 1, colon -1);
5978 templateName := substrb(altTempl, colon + 1, length(altTempl)-colon);
5979 end if;
5980
5981 -- Get notification information
5982
5983 -- Get template 'SUMMARY'
5984 begin
5985 select SUBJECT, BODY, HTML_BODY
5986 into t_subject, t_body, t_html_body
5987 from WF_MESSAGES_VL
5988 where NAME = templateName
5989 and TYPE = templateType;
5990 exception
5991 when no_data_found then
5992 wf_core.token('NAME', templateName);
5993 wf_core.token('TYPE', templateType);
5994 wf_core.raise('WFNTF_MESSAGE');
5995 end;
5996
5997 -- Retrieve role orig_system ids for index access
5998 -- <<sstomar>> : It is OK to use OLD API here,
5999 --- instead of Wf_Directory.GetRoleInfoMail2
6000 Wf_Directory.GetRoleInfoMail(role, r_displayName, dummyStr, ntf_pref,
6001 r_language, dummyStr, rorig_system,
6002 rorig_system_id, dummyStr);
6003
6004 t_subject := substrb(replace(t_subject, '&'||'USER_NAME',
6005 r_displayName), 1, 240);
6006
6007 if (rorig_system is null or rorig_system = '') then
6008 wf_core.token('ROLE', role);
6009 wf_core.raise('WFNTF_ROLE');
6010 end if;
6011
6012 if contType = g_ntfDocHtml then
6013 if (t_html_body is null) then
6014 t_html_body := replace(t_body, g_newLine,
6015 '<BR>'||g_newLine);
6016 -- Ensure the direction of the text is correct for the language
6017 if isBiDi(r_language) then
6018 t_html_body := '<HTML DIR="RTL"><BODY>'||t_html_body;
6019 else
6020 t_html_body := '<HTML><BODY>'||t_html_body;
6021 end if;
6022 else
6023 -- Ensure that the direction of the text is correctly specified.
6024 if isBiDi(r_language) then
6025 tag_pos := instrb(upper(t_html_body), '<HTML', 1);
6026 if tag_pos > 0 then
6027 dir_pos := instrb(upper(t_html_body), ' DIR="', 1);
6028 if dir_pos = 0 then
6029 buffer := substrb(t_html_body, tag_pos, 5);
6030 buffer := buffer||' DIR="RTL" '||
6031 substrb(t_html_body, tag_pos+5);
6032 t_html_body := buffer;
6033 end if;
6034 end if;
6035 end if;
6036 end if;
6037 end if;
6038
6039
6040 -- Substitute USER_NAME with role display name
6041 t_timezone := wf_mail_util.getTimezone(contType);
6042
6043 if contType = g_ntfDocText then
6044 t_body := substrb(replace(t_body, '&'||'USER_NAME', dname), 1, 32000);
6045 t_body := substrb(replace(t_body, '&'||'TIMEZONE', t_timezone), 1, 32000);
6046 else
6047 t_html_body := substrb(replace(t_html_body, '&'||'TEMPLATE_STYLE',
6048 g_template_style), 1, 32000);
6049 t_html_body := substrb(replace(t_html_body, '&'||'USER_NAME', dname),
6050 1, 32000);
6051 t_html_body := substrb(replace(t_html_body, '&'||'TIMEZONE',
6052 t_timezone), 1, 32000);
6053 end if;
6054
6055 if (renderBody = 'Y') then
6056 -- Prepare summary header
6057 if contType = g_ntfDocText then
6058 n_summ := g_newLine;
6059 n_summ := n_summ||rpad(g_wfmonId, 7)||' ';
6060 n_summ := n_summ||rpad(g_to, 42)||' ';
6061 n_summ := n_summ||rpad(g_priority, 12)||' ';
6062 n_summ := n_summ||rpad(g_dueDate, 12)||
6063 g_newLine;
6064 n_summ := n_summ||'------- ------------------------------------------ ';
6065 n_summ := n_summ||'------------ ------------'||g_newLine;
6066
6067 n_buf := '';
6068 end if;
6069
6070
6071 for rec in c1 loop
6072
6073 nid := rec.notification_id;
6074 n_key := rec.access_key;
6075 to_name := rec.recipient_role;
6076
6077 -- Get and token subsitute subject
6078 n_subject := WF_NOTIFICATION.GetSubject(nid, 'text/plain');
6079
6080 if contType = g_ntfDocText then
6081 n_buf := lpad(to_char(nid), 7, ' ')||' '||
6082 rpad(substr(dname, 1, 42), 42, ' ')||' ';
6083 if (rec.priority > 66) then
6084 --Bug 2774891 fix - sacsharm
6085 --priority_text := wf_core.substitute('WFTKN', 'HIGH');
6086 priority_text := wf_core.substitute('WFTKN', 'LOW');
6087 elsif (rec.priority > 33) then
6088 priority_text := wf_core.substitute('WFTKN', 'NORMAL');
6089 else
6090 --Bug 2774891 fix - sacsharm
6091 --priority_text := wf_core.substitute('WFTKN', 'LOW');
6092 priority_text := wf_core.substitute('WFTKN', 'HIGH');
6093 end if;
6094
6095 n_buf := n_buf||lpad(priority_text, 12, ' ');
6096 n_buf := n_buf||' '||to_char(rec.due_date)||g_newLine;
6097 n_buf := n_buf||WordWrap(n_subject, 1);
6098
6099 n_summ := n_summ||n_buf||g_newLine||g_newLine;
6100 end if;
6101
6102 -- Bug 2358498 write content to LOB if there is a possibility
6103 -- that the size might go beyond 32K
6104 if length(n_summ) > 30000 then
6105 lob := 'Y';
6106
6107 if NOT lob_init then
6108 lob_init := TRUE;
6109 -- DBMS_LOB.CreateTemporary(g_text_message, TRUE, DBMS_LOB.SESSION);
6110 -- DBMS_LOB.Open(g_text_message, DBMS_LOB.LOB_READWRITE);
6111
6112 -- This g_text_messageIdx Locator will be returned back to pool within caller
6113 -- GenerateSummaryDoc -> getBodyPart
6114 g_text_messageIdx := wf_temp_lob.getLob(g_LOBTable);
6115 if contType = g_ntfDocText then
6116 DBMS_LOB.WriteAppend(g_LOBTable(g_text_messageIdx).temp_lob,
6117 length(t_body), t_body);
6118 else
6119 DBMS_LOB.WriteAppend(g_LOBTable(g_text_messageIdx).temp_lob,
6120 length(t_html_body), t_html_body);
6121 end if;
6122
6123 -- DBMS_LOB.CreateTemporary(temp_text, FALSE, DBMS_LOB.CALL);
6124 temp_textIdx := wf_temp_lob.getLob(g_LOBTable);
6125 end if;
6126 DBMS_LOB.WriteAppend(g_LOBTable(temp_textIdx).temp_lob,
6127 length(n_summ), n_summ);
6128 n_summ := '';
6129 end if;
6130 end loop;
6131 if lob = 'Y' then
6132 t_body := '';
6133 t_html_body := '';
6134 DBMS_LOB.WriteAppend(g_LOBTable(temp_textIdx).temp_lob,
6135 length(n_summ), n_summ);
6136 LOBReplace(g_LOBTable(g_text_messageIdx).temp_lob, '&'||'SUMMARY',
6137 g_LOBTable(temp_textIdx).temp_lob, FALSE);
6138
6139 -- Release temp_textIdx locator too. << bug 6511028 >>
6140 wf_temp_lob.releaseLob(g_LOBTable, temp_textIdx);
6141
6142 else
6143 t_body := replace(t_body, '&'||'SUMMARY', n_summ);
6144 end if;
6145 end if; -- RENDERBODY
6146
6147 subject := t_subject;
6148 if contType = g_ntfDocText then
6149 body_text := t_body;
6150 else
6151 body_text := t_html_body;
6152 end if;
6153
6154 if (wf_log_pkg.level_event >= fnd_log.g_current_runtime_level) then
6155 wf_log_pkg.string(wf_log_pkg.level_event,
6156 'wf.plsql.WF_MAIL.GetSummary2',
6157 'END');
6158 end if;
6159
6160
6161 exception
6162 when others then
6163 -- Release temp_textIdx and g_text_messageIdx locators in case of any exception .
6164 if(lob = 'Y' ) then
6165 if (temp_textIdx is not null and temp_textIdx > 0 ) then
6166 wf_temp_lob.releaseLob(g_LOBTable, temp_textIdx);
6167 end if;
6168
6169 if ( g_text_messageIdx is not null and g_text_messageIdx > 0 ) then
6170 wf_temp_lob.releaseLob(g_LOBTable, g_text_messageIdx);
6171 end if;
6172
6173 end if;
6174
6175
6176 wf_core.context('WF_MAIL', 'GetSummary2', role, node, contType);
6177 raise;
6178 end GetSummary2;
6179
6180 -- GetSummary - get summary messages for one role
6181 -- ( with LOB support )
6182 -- IN
6183 -- role name
6184 -- display role name
6185 -- mailer node name
6186 -- OUT
6187 -- message subject
6188 -- message body (text)
6189 -- message body (html)
6190 -- lob (Y or N)
6191 procedure GetSummary(
6192 role in varchar2,
6193 dname in varchar2,
6194 node in varchar2,
6195 subject out NOCOPY varchar2,
6196 body_text out NOCOPY varchar2,
6197 lob out NOCOPY varchar2)
6198 as
6199
6200 begin
6201 GetSummary2(role, dname, node, 'Y', 'text/plain', subject, body_text, lob);
6202 exception
6203 when others then
6204 wf_core.context('WF_MAIL', 'GetSummary', role, node);
6205 raise;
6206 end GetSummary;
6207
6208
6209 -- initFetchLOB
6210 --
6211 -- IN
6212 -- Document type (TEXT or HTML)
6213 --
6214 procedure InitFetchLOB(doc_type VARCHAR2,
6215 doc_length OUT NOCOPY NUMBER)
6216 is
6217 begin
6218 if doc_type = g_ntfDocHtml then
6219 g_html_chunk := 0;
6220 -- doc_length := DBMS_LOB.GetLength(g_html_message);
6221 doc_length := DBMS_LOB.GetLength(g_LOBTable(g_html_messageIdx).temp_lob);
6222 else
6223 -- Always assume that the caller wants the TEXT
6224 g_text_chunk := 0;
6225 -- doc_length := DBMS_LOB.GetLength(g_text_message);
6226 doc_length := DBMS_LOB.GetLength(g_LOBTable(g_text_messageIdx).temp_lob);
6227 end if;
6228 end InitFetchLOB;
6229
6230
6231 -- FetchLOBContent
6232 --
6233 -- IN
6234 -- type of document to fetch TEXT/HTML
6235 -- End of LOB marker
6236 -- OUT
6237 -- 32K chunk of the LOB
6238 --
6239 -- Use the API in the following manner
6240 -- WF_MAIL.InitFetchLob(g_ntfDocText)
6241 -- while not clob_end loop
6242 -- WF_MAIL.FetchLobContent(cBuf, g_ntfDocText, clob_end);
6243 -- ...
6244 -- end loop;
6245 --
6246 procedure FetchLOBContent(buffer OUT NOCOPY VARCHAR2,
6247 doc_type IN VARCHAR2,
6248 end_of_clob IN OUT NOCOPY NUMBER)
6249 is
6250 pos NUMBER;
6251 buffer_length pls_integer := 16000;
6252 begin
6253 if doc_type = g_ntfDocHtml then
6254 pos := (buffer_length * nvl(g_html_chunk,0))+1;
6255 -- DBMS_LOB.Read(g_html_message, buffer_length, pos, buffer);
6256 DBMS_LOB.Read(g_LOBTable(g_html_messageIdx).temp_lob, buffer_length, pos, buffer);
6257 if pos+buffer_length > DBMS_LOB.GetLength(g_LOBTable(g_html_messageIdx).temp_lob) then
6258 end_of_clob := 1;
6259 g_html_chunk := 0;
6260 else
6261 g_html_chunk := g_html_chunk + 1;
6262 end if;
6263 else
6264 -- Always assume that the caller wants the TEXT
6265 pos := (buffer_length * nvl(g_text_chunk,0))+1;
6266 -- DBMS_LOB.Read(g_text_message, buffer_length, pos, buffer);
6267 DBMS_LOB.Read(g_LOBTable(g_text_messageIdx).temp_lob, buffer_length, pos, buffer);
6268 if pos+buffer_length > DBMS_LOB.GetLength(g_LOBTable(g_text_messageIdx).temp_lob) then
6269 end_of_clob := 1;
6270 g_text_chunk := 0;
6271 else
6272 g_text_chunk := g_text_chunk + 1;
6273 end if;
6274 end if;
6275 exception
6276 when others then
6277 WF_CORE.Context('WF_MAIL','FetchLOBContent',doc_type,
6278 to_char(pos)||':'||buffer);
6279 raise;
6280 end FetchLOBContent;
6281
6282 -- CloseLOB - Close the message LOBs ready for use again later
6283 --
6284 procedure CloseLOB(doc_type in VARCHAR2)
6285 is
6286 begin
6287 if doc_type = g_ntfDocHtml then
6288 -- DBMS_LOB.close(g_html_message);
6289 -- DBMS_LOB.FreeTemporary(g_html_message);
6290 wf_temp_lob.releaseLob(g_LOBTable, g_html_messageIdx);
6291 else
6292 -- DBMS_LOB.close(g_text_message);
6293 -- DBMS_LOB.FreeTemporary(g_text_message);
6294 wf_temp_lob.releaseLob(g_LOBTable, g_text_messageIdx);
6295 end if;
6296 exception
6297 when others then
6298 WF_CORE.Context('WF_MAIL','CloseLOB', doc_type);
6299 raise;
6300 end;
6301
6302 -- CloseLOB - Close the message LOBs ready for use again later
6303 --
6304 procedure CloseLOB
6305 is
6306 begin
6307 WF_MAIL.CloseLOB(g_ntfDocText);
6308 WF_MAIL.CloseLOB(g_ntfDocHtml);
6309 exception
6310 when others then
6311 WF_CORE.Context('WF_MAIL','CloseLOB');
6312 raise;
6313 end;
6314
6315
6316 -- FetchUrlContent - Fetched the content from the global buffer which
6317 -- populated by GetUrlContent().
6318 --
6319 -- IN
6320 -- piece_count - the index to the url_content_array.
6321 -- OUT
6322 -- piece_value - the data stored in the global content_array table.
6323 function FetchUrlContent(piece_count in number,
6324 error_result in out NOCOPY varchar2) return varchar2 as
6325 begin
6326 return(wf_mail.content_array(piece_count));
6327
6328 exception
6329 when NO_DATA_FOUND then
6330 return('NO_DATA_FOUND');
6331
6332 when others then
6333 error_result := sqlerrm;
6334 wf_core.context('WF_MAIL', 'FetchUrlContent', piece_count);
6335
6336 end FetchUrlContent;
6337
6338
6339 -- GetUrlContent - get URL content
6340 --
6341 -- IN
6342 -- url address id
6343 -- OUT
6344 -- piece_count
6345 -- error result
6346 procedure GetUrlContent(
6347 url in varchar2,
6348 piece_count out NOCOPY number,
6349 error_result in out NOCOPY varchar2)
6350
6351 as
6352 no_program_unit exception;
6353 pragma exception_init(no_program_unit, -6508);
6354
6355 url_pieces utl_http.html_pieces;
6356 err_name varchar2(30);
6357 err_message varchar2(2000);
6358 err_stack varchar2(4000);
6359 content_array url_content_array;
6360
6361 begin
6362
6363 url_pieces := utl_http.request_pieces(url);
6364
6365 for l_rec_num in 1..url_pieces.count loop
6366 wf_mail.content_array(l_rec_num) := url_pieces(l_rec_num);
6367 piece_count := l_rec_num;
6368 end loop;
6369
6370 exception
6371
6372 when utl_http.init_failed then
6373 error_result := 'UTL_HTTP.INIT_FAILED';
6374 error_result := error_result || sqlerrm;
6375 wf_core.context('WF_MAIL', 'GetUrlContent', url);
6376
6377 when utl_http.request_failed then
6378 error_result := 'UTL_HTTP.REQUEST_FAILED';
6379 error_result := error_result || sqlerrm;
6380 wf_core.context('WF_MAIL', 'GetUrlContent', url);
6381
6382 when no_program_unit then
6383 wf_core.context('WF_MAIL', 'GetUrlContent', url);
6384 raise;
6385 when others then
6386 error_result := sqlerrm;
6387 wf_core.context('WF_MAIL', 'GetUrlContent', url);
6388
6389 end GetUrlContent;
6390
6391 -- GetDocContent - get Document content
6392 --
6393 -- IN
6394 -- notification id
6395 -- document attribute name
6396 -- display type
6397 -- OUT
6398 -- document content
6399 -- error result
6400 procedure GetDocContent(
6401 nid in number,
6402 docattrname in varchar2,
6403 disptype in varchar2,
6404 doccontent out NOCOPY varchar2,
6405 error_result in out NOCOPY varchar2)
6406
6407 as
6408 no_program_unit exception;
6409 pragma exception_init(no_program_unit, -6508);
6410
6411 err_name varchar2(30);
6412 err_message varchar2(2000);
6413 err_stack varchar2(4000);
6414 begin
6415
6416 doccontent := Wf_Notification.GetAttrDoc(nid, docattrname, disptype);
6417
6418 exception
6419 when no_program_unit then
6420 wf_core.context('WF_MAIL', 'GetDocContent', docattrname);
6421 raise;
6422 when others then
6423 -- First look for a wf_core error.
6424 wf_core.get_error(err_name, err_message, err_stack);
6425
6426 -- If no wf_core error look for a sql error.
6427 if (err_name is null) then
6428 err_message := sqlerrm;
6429 end if;
6430
6431 error_result := err_message;
6432 wf_core.context('WF_MAIL', 'GetDocContent', docattrname);
6433
6434 end GetDocContent;
6435
6436 -- GetLOBDocContent - get Document content
6437 -- Returns the document type of the PLSQLCLOB document
6438 --
6439 -- IN
6440 -- notification id
6441 -- document attribute name
6442 -- display type
6443 -- OUT
6444 -- document content
6445 -- error result
6446 procedure GetLOBDocContent(
6447 nid in number,
6448 docattrname in varchar2,
6449 disptype in varchar2,
6450 error_result in out NOCOPY varchar2)
6451 as
6452 doctype varchar2(500);
6453 no_program_unit exception;
6454 pragma exception_init(no_program_unit, -6508);
6455 err_name varchar2(30);
6456 err_message varchar2(2000);
6457 err_stack varchar2(4000);
6458 begin
6459
6460 Wf_Mail.GetLOBDocContent(nid, docattrname, disptype, doctype, error_result);
6461
6462 exception
6463 when no_program_unit then
6464 wf_core.context('WF_MAIL', 'oldGetLOBDocContent', docattrname);
6465 raise;
6466 when others then
6467 -- First look for a wf_core error.
6468 wf_core.get_error(err_name, err_message, err_stack);
6469
6470 -- If no wf_core error look for a sql error.
6471 if (err_name is null) then
6472 err_message := sqlerrm;
6473 end if;
6474
6475 error_result := err_message;
6476 wf_core.context('WF_MAIL', 'oldGetDocLOBContent', docattrname);
6477 end GetLOBDocContent;
6478
6479 -- GetLOBDocContent - get Document content
6480 --
6481 -- IN
6482 -- notification id
6483 -- document attribute name
6484 -- display type
6485 -- OUT
6486 -- document type
6487 -- document content
6488 -- error result
6489 procedure GetLOBDocContent(
6490 nid in number,
6491 docattrname in varchar2,
6492 disptype in varchar2,
6493 doctype out NOCOPY varchar2,
6494 error_result in out NOCOPY varchar2)
6495
6496 as
6497 no_program_unit exception;
6498 pragma exception_init(no_program_unit, -6508);
6499
6500 doc varchar(32000) := '';
6501
6502 aname varchar2(30);
6503 err_name varchar2(30);
6504 err_message varchar2(2000);
6505 err_stack varchar2(4000);
6506 begin
6507 -- There is a difference betwen PLSQL: and PLSQLCLOB: documents
6508 -- First go for the PLSQL: if that returns the name of the
6509 -- attribute, then try the PLSQLCLOB:
6510 doc := WF_NOTIFICATION.GetAttrDoc(nid, docattrname, disptype);
6511 if disptype = g_ntfDocHtml then
6512 -- DBMS_LOB.CreateTemporary(g_html_message, true, dbms_lob.SESSION);
6513 -- DBMS_LOB.Open(g_html_message, DBMS_LOB.LOB_READWRITE);
6514 g_html_messageIdx := wf_temp_lob.getLob(g_LOBTable);
6515 if doc = '&'||docattrname then
6516 Wf_Notification.GetAttrCLOB(nid, docattrname, disptype,
6517 g_LOBTable(g_html_messageIdx).temp_lob, doctype, aname);
6518 else
6519 DBMS_LOB.Write(g_LOBTable(g_html_messageIdx).temp_lob, length(doc), 1, doc);
6520 end if;
6521 else
6522 -- DBMS_LOB.CreateTemporary(g_text_message, true, dbms_lob.SESSION);
6523 -- DBMS_LOB.Open(g_text_message, DBMS_LOB.LOB_READWRITE);
6524 g_text_messageIdx := wf_temp_lob.getLob(g_LOBTable);
6525 if doc = '&'||docattrname then
6526 Wf_Notification.GetAttrCLOB(nid, docattrname, disptype,
6527 g_LOBTable(g_text_messageIdx).temp_lob, doctype, aname);
6528 else
6529 DBMS_LOB.Write(g_LOBTable(g_text_messageIdx).temp_lob, length(doc), 1, doc);
6530 end if;
6531 end if;
6532
6533
6534 exception
6535 -- propagating all exceptions to the calling program
6536 when others then
6537 wf_core.context('WF_MAIL', 'GetLOBDocContent', docattrname);
6538 raise;
6539
6540 end GetLOBDocContent;
6541
6542 -- RemoveSpace (PRIVATE)
6543 -- Removes white spaces between response prompt and colon, from colon
6544 -- to the quote.
6545 -- IN
6546 -- body - Email response body
6547 -- resp_attrs - Response attribtue info for the current notification
6548 -- OUT
6549 -- body - Email body with the white spaces removed wherever required
6550
6551 function RemoveSpace(body in varchar2,
6552 resp_attrs in resp_attrs_t)
6553 return varchar2
6554 is
6555 colonPos pls_integer;
6556 quotePos pls_integer;
6557 prompPos pls_integer;
6558 prompt varchar2(80);
6559 tmpStr varchar2(32000);
6560 tmpBody varchar2(32000);
6561
6562 begin
6563
6564 tmpBody := body;
6565
6566 -- remove spaces from the response prompt till the following colon
6567 for i in 1..resp_attrs.COUNT loop
6568 prompt := resp_attrs(i).attr_prompt;
6569 prompPos := instrb(tmpBody, prompt, 1);
6570 while (prompPos > 0) loop
6571 prompPos := prompPos + length(prompt) - 1;
6572 colonPos := instrb(tmpBody, ':', prompPos);
6573 tmpStr := substrb(tmpBody, prompPos + 1, (colonPos - prompPos) - 1);
6574 tmpStr := replace(tmpStr, g_tab);
6575 tmpStr := replace(tmpStr, g_newLine);
6576 if (ltrim(rtrim(tmpStr)) is NULL and colonPos > 0) then
6577 tmpBody := substrb(tmpBody, 1, prompPos) || substrb(tmpBody, colonPos);
6578 end if;
6579 prompPos := instrb(tmpBody, prompt, prompPos);
6580 end loop;
6581 end loop;
6582
6583 -- first occurence of a colon
6584 colonPos := instrb(tmpBody, ':', 1);
6585 -- loop until there is a colon
6586 while colonPos > 0 loop
6587 -- first occurence of a double quote after the colon
6588 quotePos := instrb(tmpBody, '"', colonPos);
6589 if (quotePos > 0) then
6590 -- examine the string between the colon the following double quote
6591 -- and replace tab and newline
6592 tmpStr := substrb(tmpBody, colonPos+1, (quotePos-colonPos)-1);
6593 tmpStr := replace(tmpStr, g_tab);
6594 tmpStr := replace(tmpStr, g_newLine);
6595 -- if trim results in NULL, the string need not exist within the email
6596 if (ltrim(rtrim(tmpStr)) IS NULL) then
6597 tmpBody := substrb(tmpBody, 1, colonPos) || substrb(tmpBody, quotePos);
6598 end if;
6599 end if;
6600
6601 -- first occurence of a single quote after the colon
6602 quotePos := instrb(tmpBody, '''', colonPos);
6603 if (quotePos > 0) then
6604 -- examine the string between the colon the following single quote
6605 -- and replace tab and newline
6606 tmpStr := substrb(tmpBody, colonPos+1, (quotePos-colonPos)-1);
6607 tmpStr := replace(tmpStr, g_tab);
6608 tmpStr := replace(tmpStr, g_newLine);
6609 -- if trim results in NULL, the string need not exist within the email
6610 if (ltrim(rtrim(tmpStr)) IS NULL) then
6611 tmpBody := substrb(tmpBody, 1, colonPos) || substrb(tmpBody, quotePos);
6612 end if;
6613 end if;
6614 colonPos := instrb(tmpBody, ':', colonPos+1);
6615 end loop;
6616 return tmpBody;
6617 exception
6618 when others then
6619 wf_core.context('WF_MAIL', 'RemoveSpace');
6620 raise;
6621 end RemoveSpace;
6622
6623 -- PutMessage
6624 -- Reply processor. Read body of a notification reply, set any
6625 -- response attributes, and complete response.
6626 -- Used by the notification mail response processor.
6627 -- IN
6628 -- notification id
6629 -- mailer node name
6630 -- response body text
6631 -- email 'from' address
6632 procedure PutMessage(
6633 nid in number,
6634 node in varchar2,
6635 resp_body in varchar2,
6636 from_addr in varchar2,
6637 error_result in out NOCOPY varchar2)
6638 as
6639 TYPE stack_t IS TABLE OF
6640 varchar2(32000) INDEX BY BINARY_INTEGER;
6641
6642 stack stack_t;
6643 contentStack stack_t;
6644 resp_attrs resp_attrs_t;
6645
6646 value varchar2(4000);
6647 prompt varchar2(2000);
6648 buffer varchar2(32000);
6649 tmpbuf varchar2(32000);
6650 token varchar2(32000);
6651 loc pls_integer;
6652 stk pls_integer;
6653 i pls_integer;
6654 j pls_integer;
6655 k pls_integer;
6656 l pls_integer;
6657 prompPos pls_integer;
6658 nextPos pls_integer := 0;
6659 tmpPos pls_integer;
6660 dleft number;
6661 dright number;
6662 sleft number;
6663 sright number;
6664 left number;
6665 right number;
6666 msg_name varchar2(30);
6667 msg_type varchar2(8);
6668 stat varchar2(8);
6669 response boolean := FALSE;
6670 lk_type varchar2(100);
6671 lk_meaning varchar2(100);
6672 n_sig_policy varchar2(100);
6673
6674 -- Select msg response attrs.
6675 -- Order-by is to insure longest prompts are processed first to prevent
6676 -- problems where one prompt is a substring of another prompt.
6677 cursor c1 is
6678 select NAME, DISPLAY_NAME, TYPE, FORMAT
6679 from WF_MESSAGE_ATTRIBUTES_VL
6680 where MESSAGE_NAME = msg_name
6681 and MESSAGE_TYPE = msg_type
6682 and SUBTYPE = 'RESPOND'
6683 and TYPE not in ('FORM', 'URL')
6684 order by length(DISPLAY_NAME) desc;
6685
6686 no_program_unit exception;
6687 pragma exception_init(no_program_unit, -6508);
6688
6689 begin
6690 -- Get notification message and status
6691 begin
6692 select MESSAGE_NAME, MESSAGE_TYPE, STATUS
6693 into msg_name, msg_type, stat
6694 from WF_NOTIFICATIONS
6695 where NOTIFICATION_ID = nid;
6696 exception
6697 when no_data_found then
6698 wf_core.token('NID', to_char(nid));
6699 wf_core.raise('WFNTF_NID');
6700 end;
6701 i := 1;
6702 -- collect all the response attributes and their details
6703 -- for the notification
6704 for rec in c1 loop
6705 resp_attrs(i).attr_prompt := rec.display_name;
6706 resp_attrs(i).attr_type := rec.type;
6707 resp_attrs(i).attr_name := rec.name;
6708 resp_attrs(i).attr_format := rec.format;
6709 i := i + 1;
6710 end loop;
6711
6712 -- Bug 2375920 get the signature policy for the notification and
6713 -- raise error is the policy is invalid
6714 Wf_Mail.GetSignaturePolicy(nid, n_sig_policy);
6715 if (n_sig_policy is not NULL and upper(n_sig_policy) <> 'DEFAULT') then
6716 if(upper(n_sig_policy) = 'PSIG_ONLY') then
6717 wf_core.context('WF_MAIL', 'PutMessage', to_char(nid), node, from_addr);
6718 wf_core.token('NID', to_char(nid));
6719 wf_core.raise('WFRSPR_PWD_SIGNATURE');
6720 else
6721 wf_core.context('WF_MAIL', 'PutMessage', to_char(nid), node, from_addr);
6722 wf_core.token('NID', to_char(nid));
6723 wf_core.token('POLICY', n_sig_policy);
6724 wf_core.raise('WFMLR_INVALID_SIG_POLICY');
6725 end if;
6726 end if;
6727
6728 -- all database-friendly RemoveSpace
6729 buffer := RemoveSpace(resp_body, resp_attrs);
6730
6731 if (buffer is not null or buffer <> '') then
6732 -- separate the mail content into tokens based on Content-Type
6733 -- to eliminate v-card interference.
6734 stk := 1;
6735 i := 1;
6736 loc := 1;
6737 token := '';
6738 while (i <= length(buffer)) loop
6739 -- check if we are at the beginning of a Content-Type
6740 prompt := substrb(buffer, i, length('Content-Type'));
6741 if (upper(prompt) = 'CONTENT-TYPE') then
6742 if (token is not null or token <> '') then
6743 -- push the buffer to the stack and start again
6744 contentStack(stk) := token;
6745 stk := stk + 1;
6746 token := '';
6747 loc := i;
6748 end if;
6749 end if;
6750 token := substrb(buffer, loc, (i - loc) + 1);
6751 i := i + 1;
6752 end loop;
6753 if (token is not null or token <> '') then
6754 contentStack(stk) := token;
6755 end if;
6756
6757 -- now look for response attributes within tokens based on
6758 -- Content-Type. Only the body will contain the response though.
6759 stk := 1;
6760 for k in 1..contentStack.count loop
6761 for i in 1..resp_attrs.count loop
6762 prompPos := instrb(contentStack(k), resp_attrs(i).attr_prompt||':', 1);
6763 nextPos := 0;
6764 -- get the position of the next nearest prompt
6765 for j in 1..resp_attrs.count loop
6766 tmpPos := instrb(contentStack(k), resp_attrs(j).attr_prompt||':', prompPos + 1);
6767 if (tmpPos > prompPos + 1) then
6768 if (nextPos = 0) then
6769 nextPos := tmpPos;
6770 elsif (tmpPos <> 0 and tmpPos < nextPos) then
6771 nextPos := tmpPos;
6772 end if;
6773 end if;
6774 end loop;
6775 -- if nextPos is 0, then we are at the last or only response prompt
6776 -- push to stack only if there was a prompt found within the body
6777 -- hoping to avoid v-card here
6778 if (prompPos > 0) then
6779 if (nextPos = 0) then
6780 if (resp_attrs(i).attr_type in ('LOOKUP', 'NUMBER')) then
6781 stack(stk) := substrb(contentStack(k), prompPos,
6782 length(resp_attrs(i).attr_prompt) + 40);
6783 else
6784 stack(stk) := substrb(contentStack(k), prompPos,
6785 length(resp_attrs(i).attr_prompt) + 2000);
6786 end if;
6787 else
6788 stack(stk) := substrb(contentStack(k), prompPos, (nextPos - prompPos) - 1);
6789 end if;
6790 stk := stk + 1;
6791 end if;
6792 end loop;
6793 end loop;
6794 end if;
6795
6796 -- process the response values from the stack
6797 for i in 1..stack.count loop
6798 for j in 1..resp_attrs.count loop
6799 -- check if we are at the beginning of a response prompt
6800 prompt := substrb(stack(i), 1, length(resp_attrs(j).attr_prompt));
6801 if (upper(prompt) = upper(resp_attrs(j).attr_prompt)) then
6802 -- remove all the following occurences of the prompt
6803 -- within the stack
6804 for k in i..stack.count loop
6805 stack(k) := replace(stack(k), resp_attrs(j).attr_prompt||':');
6806 end loop;
6807 -- check for double quotes from both ends
6808 dleft := instrb(stack(i), '"', 1, 1);
6809 dright := instrb(stack(i), '"', -1, 1);
6810
6811 -- check for single quotes from both ends
6812 sleft := instrb(stack(i), '''', 1, 1);
6813 sright := instrb(stack(i), '''', -1, 1);
6814
6815 if (dleft <> 0 and (sleft = 0 or dleft < sleft)) then
6816 left := dleft;
6817 else
6818 left := sleft;
6819 end if;
6820 if (dright > sright) then
6821 right := dright;
6822 else
6823 right := sright;
6824 end if;
6825 if ((right - left) > 1) then
6826 value := substrb(stack(i), left+1, (right - left)-1);
6827 if (resp_attrs(j).attr_type = 'LOOKUP') then
6828 lk_type := resp_attrs(j).attr_format;
6829 lk_meaning := value;
6830 value := GetLovCode(resp_attrs(j).attr_format, value);
6831 end if;
6832
6833 -- Process this notification only if it has a status of 'OPEN'
6834 -- otherwise do nothing. Fix for bug 2202392.
6835 if (stat = 'OPEN') then
6836 -- Save the new attribute value for nid.
6837 Wf_Notification.SetAttrText(nid, resp_attrs(j).attr_name, value);
6838 end if;
6839 response := TRUE;
6840 end if;
6841 end if;
6842 end loop;
6843 end loop;
6844
6845 -- Do not need to preserve context
6846 wf_engine.preserved_context := FALSE;
6847
6848 -- Complete the response.
6849 if response then
6850 Wf_Notification.Respond(nid, NULL, 'email:'||from_addr);
6851 else
6852 wf_core.context('WF_MAIL', 'PutMessage', to_char(nid), node, from_addr);
6853 wf_core.raise('WFRSPR_NORESPONSE');
6854 end if;
6855
6856 exception
6857 when no_program_unit then
6858 wf_core.context('WF_MAIL','PutMessage', to_char(nid));
6859 raise;
6860 when OTHERS then
6861 wf_core.context('WF_MAIL','PutMessage', to_char(nid));
6862 -- Save error message and set status to INVALID so mailer will
6863 -- bounce an "invalid reply" message to sender.
6864 HandleResponseError(nid, lk_type, lk_meaning, error_result);
6865 end PutMessage;
6866
6867 -- PutDirectMessage
6868 -- Direct reply processor. Read body of a notification reply, set any
6869 -- response attributes, and complete response.
6870 -- Used by the notification mail response processor.
6871 -- IN
6872 -- notification id
6873 -- mailer node name
6874 -- response body text
6875 -- email 'from' address
6876 procedure PutDirectMessage(
6877 nid in number,
6878 node in varchar2,
6879 resp_body in varchar2,
6880 from_addr in varchar2,
6881 error_result in out NOCOPY varchar2)
6882 as
6883 buffer varchar2(32000);
6884 msg_name varchar2(30);
6885 msg_type varchar2(8);
6886 stat varchar2(8);
6887 use_default boolean;
6888 first_blank_line boolean := true;
6889 response boolean;
6890
6891 -- Select msg response attrs.
6892 -- Order-by is to insure longest prompts are processed first to prevent
6893 -- problems where one prompt is a substring of another prompt.
6894 cursor c1 is
6895 select WMA.NAME, WMA.TYPE, WMA.FORMAT,
6896 decode(WMA.TYPE,
6897 'VARCHAR2', decode(WMA.FORMAT,
6898 '', WNA.TEXT_VALUE,
6899 substr(WNA.TEXT_VALUE, 1, to_number(WMA.FORMAT))),
6900 'NUMBER', decode(WMA.FORMAT,
6901 '', to_char(WNA.NUMBER_VALUE),
6902 to_char(WNA.NUMBER_VALUE, WMA.FORMAT)),
6903 'DATE', decode(WMA.FORMAT,
6904 '', to_char(WNA.DATE_VALUE),
6905 to_char(WNA.DATE_VALUE, WMA.FORMAT)),
6906 'LOOKUP', WNA.TEXT_VALUE,
6907 WNA.TEXT_VALUE) VALUE
6908 from WF_NOTIFICATION_ATTRIBUTES WNA,
6909 WF_NOTIFICATIONS WN,
6910 WF_MESSAGE_ATTRIBUTES_VL WMA
6911 where WNA.NOTIFICATION_ID = nid
6912 and WN.NOTIFICATION_ID = WNA.NOTIFICATION_ID
6913 and WN.MESSAGE_TYPE = WMA.MESSAGE_TYPE
6914 and WN.MESSAGE_NAME = WMA.MESSAGE_NAME
6915 and WMA.NAME = WNA.NAME
6916 and WMA.SUBTYPE = 'RESPOND'
6917 and WMA.TYPE not in ('FORM', 'URL')
6918 order by WMA.SEQUENCE;
6919
6920 new_value varchar2(4000);
6921 new_start pls_integer;
6922 new_end pls_integer;
6923 no_program_unit exception;
6924 pragma exception_init(no_program_unit, -6508);
6925 -- Bug# 2301881
6926 lk_type varchar2(30);
6927 lk_meaning varchar2(80);
6928 -- Bug 2375920
6929 n_sig_policy varchar2(100);
6930 begin
6931 buffer := resp_body;
6932 response := false;
6933
6934 -- Get notification message and status
6935 begin
6936 select MESSAGE_NAME, MESSAGE_TYPE, STATUS
6937 into msg_name, msg_type, stat
6938 from WF_NOTIFICATIONS
6939 where NOTIFICATION_ID = nid;
6940 exception
6941 when no_data_found then
6942 wf_core.token('NID', to_char(nid));
6943 wf_core.raise('WFNTF_NID');
6944 end;
6945
6946 -- Bug 2375920 get the signature policy for the notification and
6947 -- raise error is the policy is invalid
6948 Wf_Mail.GetSignaturePolicy(nid, n_sig_policy);
6949 if (n_sig_policy is not NULL and upper(n_sig_policy) <> 'DEFAULT') then
6950 if(upper(n_sig_policy) = 'PSIG_ONLY') then
6951 wf_core.context('WF_MAIL', 'PutDirectMessage', to_char(nid), node, from_addr);
6952 wf_core.token('NID', to_char(nid));
6953 wf_core.raise('WFRSPR_PWD_SIGNATURE');
6954 else
6955 wf_core.context('WF_MAIL', 'PutDirectMessage', to_char(nid), node, from_addr);
6956 wf_core.token('NID', to_char(nid));
6957 wf_core.token('POLICY', n_sig_policy);
6958 wf_core.raise('WFMLR_INVALID_SIG_POLICY');
6959 end if;
6960 end if;
6961
6962 -- Process all Response attributes.
6963 -- The first line in the mail body should be the answer for the first
6964 -- response attribute. And the second line should be for the second
6965 -- response attribute....
6966 -- Blank line means take the default value.
6967 -- The mailer is assuming that blank line will be inserted by user
6968 -- when they want to take the default value.
6969 -- When an answer is too long, double quote should be enclosed at both
6970 -- beginning and the end of the answer.
6971 for rec in c1 loop
6972
6973 -- Bug# 2301881 These values are needed in HandleResponseError
6974 -- and FormatErrorMessage to bounce invalid response mail
6975 lk_type := rec.format;
6976 lk_meaning := g_none;
6977
6978 -- GetDirectAnswer() will take the next line from the mail body.
6979 -- GetDirectAnswer() takes care multiple lines answer.(answer enclosed
6980 -- by double quote
6981 use_default := false;
6982 GetDirectAnswer(buffer, new_value);
6983
6984 if (new_value is null) then
6985 -- check if is leading blank line
6986 if (not(first_blank_line)) then
6987 new_value := rec.value;
6988 use_default := true;
6989 else
6990 while (new_value is null) loop
6991 GetDirectAnswer(buffer, new_value);
6992 end loop;
6993 first_blank_line := false;
6994 end if;
6995 else
6996 first_blank_line := false;
6997 end if;
6998
6999 -- Bug# 2301881
7000 lk_meaning := new_value;
7001 -- If this is a lookup, replace displayed meaning with code.
7002 if (rec.type = 'LOOKUP' AND use_default = false) then
7003 new_value := GetLovCode(rec.format, new_value);
7004 end if;
7005
7006 -- Process this notification only if it has a status of 'OPEN'
7007 -- otherwise do nothing. Fix for bug 2202392.
7008
7009 if (stat = 'OPEN') then
7010 -- Save the new attribute value for nid.
7011 Wf_Notification.SetAttrText(nid, rec.name, new_value);
7012 end if;
7013 response := TRUE;
7014 end loop;
7015
7016 -- Do not need to preserve context
7017 wf_engine.preserved_context := FALSE;
7018
7019 -- Complete the response.
7020 if response then
7021 Wf_Notification.Respond(nid, NULL, 'email:'||from_addr);
7022 else
7023 wf_core.context('WF_MAIL', 'PutDirectMessage', to_char(nid),
7024 node, from_addr);
7025 wf_core.raise('WFRSPR_NORESPONSE');
7026 end if;
7027 exception
7028 when no_program_unit then
7029 wf_core.context('WF_MAIL','PutDirectMessage', to_char(nid));
7030 raise;
7031 when OTHERS then
7032 wf_core.context('WF_MAIL','PutDirectMessage', to_char(nid));
7033 -- Save error message and set status to INVALID so mailer will
7034 -- bounce an "invalid reply" message to sender.
7035 HandleResponseError(nid, lk_type, lk_meaning, error_result);
7036 end PutDirectMessage;
7037
7038 -- PutMoreInfoRequest
7039 -- Reply processor. Read body of a request for more information
7040 -- parse the body for the role to send the request to.
7041 -- Used by the notification mail response processor.
7042 -- IN
7043 -- notification id
7044 -- mailer node name
7045 -- response body text
7046 -- email 'from' address
7047 procedure PutMoreInfoRequest(
7048 nid in number,
7049 node in varchar2,
7050 resp_body in varchar2,
7051 from_addr in varchar2,
7052 error_result in out nocopy varchar2)
7053 as
7054 buffer varchar2(32000);
7055 start_pos number;
7056 end_pos number;
7057 prompt varchar2(200);
7058 comment varchar2(200);
7059 to_user varchar2(320);
7060 dummy varchar2(200);
7061 no_program_unit exception;
7062 pragma exception_init(no_program_unit, -6508);
7063 begin
7064 buffer := resp_body;
7065 -- Remove line feeds incase there
7066 -- has been a line wrap on the response
7067 buffer := replace(buffer, g_newLine, '');
7068
7069 -- Locate who the response is to.
7070 prompt := g_moreInfoFrom||': ''';
7071 start_pos := instr(buffer, prompt, 1, 1);
7072 if start_pos <> 0 then
7073 start_pos := start_pos + length(prompt);
7074 end_pos := instr(buffer, '''', start_pos, 1);
7075 to_user := substr(buffer, start_pos, end_pos - start_pos);
7076 else
7077 to_user := '';
7078 end if;
7079
7080 -- More info request can come only from a HTML mail in which
7081 -- a template is provided with single quotes
7082 prompt := '';
7083 start_pos := 0;
7084 end_pos := 0;
7085 prompt := g_moreInfoQPrompt||': ''';
7086
7087 -- checking only for single quote, as the template is generated by the
7088 -- mailer with a single quote on clicking on the link
7089 start_pos := instr(buffer, prompt, 1, 1);
7090 if start_pos <> 0 then
7091 start_pos := start_pos + length(prompt);
7092 end_pos := instr(buffer, '''', start_pos, 1);
7093 if end_pos <> 0 then
7094 comment := substr(buffer, start_pos, end_pos - start_pos);
7095 if comment = g_moreInfoQuestion and
7096 length(comment) =
7097 length(g_moreInfoQuestion) then
7098 comment := '';
7099 end if;
7100
7101 end if;
7102 else
7103 comment := 'NULL';
7104 end if;
7105 -- validate the role before calling updateinfo
7106
7107 -- update wf_notifications and wf_comments in QUESTION mode
7108 if (length(to_user) > 0 and length(comment) > 0) then
7109 wf_notification.UpdateInfo2(nid, to_user, from_addr, comment);
7110 end if;
7111 exception
7112 when no_program_unit then
7113 wf_core.context('WF_MAIL','PutMoreInfoRequest', to_char(nid));
7114 raise;
7115 when OTHERS then
7116 wf_core.context('WF_MAIL','PutMoreInfoRequest', to_char(nid));
7117 -- Save error message and set status to INVALID so mailer will
7118 -- bounce an "invalid reply" message to sender.
7119 HandleResponseError(nid, dummy, dummy, error_result);
7120 end PutMoreInfoRequest;
7121
7122 -- PutMoreInfoMessage
7123 -- Reply processor. Read body of a reply for more information
7124 -- request, parse the body for the comments from the user and
7125 -- update wf_notification and wf_comments apropriately
7126 -- Used by the notification mail response processor.
7127 -- IN
7128 -- notification id
7129 -- mailer node name
7130 -- response body text
7131 -- email 'from' address
7132 procedure PutMoreInfoMessage(
7133 nid in number,
7134 node in varchar2,
7135 resp_body in varchar2,
7136 from_addr in varchar2,
7137 error_result in out nocopy varchar2)
7138 as
7139 buffer varchar2(32000);
7140 start_pos number;
7141 end_pos number;
7142 prompt varchar2(200);
7143 comment varchar2(200);
7144 to_user varchar2(320);
7145 dummy varchar2(200);
7146 no_program_unit exception;
7147 pragma exception_init(no_program_unit, -6508);
7148 begin
7149 buffer := resp_body;
7150 -- Remove line feeds incase there
7151 -- has been a line wrap on the response
7152 buffer := replace(buffer, g_newLine, '');
7153
7154 prompt := '';
7155 start_pos := 0;
7156 end_pos := 0;
7157 prompt := g_moreInfoAPrompt||': ''';
7158
7159 start_pos := instr(buffer, prompt, 1, 1);
7160 if start_pos <> 0 then
7161 start_pos := start_pos + length(prompt);
7162 end_pos := instr(buffer, '''', start_pos, 1);
7163 if end_pos <> 0 then
7164 comment := substr(buffer, start_pos, end_pos - start_pos);
7165 if comment = g_moreInfoAnswer and
7166 length(comment) =
7167 length(g_moreInfoAnswer) then
7168 comment := '';
7169 end if;
7170
7171 end if;
7172 else
7173 prompt := '';
7174 start_pos := 0;
7175 end_pos := 0;
7176 prompt := g_moreInfoAPrompt||': "';
7177 start_pos := instr(buffer, prompt, 1, 1);
7178 if (start_pos <> 0) then
7179 start_pos := start_pos + length(prompt);
7180 end_pos := instr(buffer, '''', start_pos, 1);
7181 if (end_pos <> 0) then
7182 comment := substr(buffer, start_pos, end_pos - start_pos);
7183 if ((comment = g_moreInfoAnswer) and
7184 (length(comment) =
7185 length(g_moreInfoAnswer))) then
7186 comment := '';
7187 end if;
7188 end if;
7189 end if;
7190 end if;
7191 -- update wf_notifications and wf_comments in ANSWER mode
7192 to_user := NULL;
7193 wf_notification.UpdateInfo2(nid, to_user, from_addr, comment);
7194 exception
7195 when no_program_unit then
7196 wf_core.context('WF_MAIL','PutMoreInfoMessage', to_char(nid));
7197 raise;
7198 when OTHERS then
7199 wf_core.context('WF_MAIL','PutMoreInfoMessage', to_char(nid));
7200 -- Save error message and set status to INVALID so mailer will
7201 -- bounce an "invalid reply" message to sender.
7202 HandleResponseError(nid, dummy, dummy, error_result);
7203 end PutMoreInfoMessage;
7204
7205 -- GetURLAttachment - Return the attached URLS as a list on an attachment
7206 -- IN
7207 -- NID Notificaiton ID
7208 -- OUT
7209 -- BUFFER containing the attachment body
7210 -- ERROR_RESULT - Errorstack if requried
7211 procedure GetUrlAttachment (nid in number,
7212 buffer out NOCOPY varchar2,
7213 error_result out NOCOPY varchar2)
7214 is
7215 l_subject varchar2(2000);
7216 l_html_body varchar2(32000);
7217 l_url varchar2(2000);
7218 l_urllist varchar2(32000);
7219 l_urlcount integer;
7220
7221 err_name varchar2(30);
7222 err_message varchar2(2000);
7223 err_stack varchar2(4000);
7224
7225 cursor ntf is
7226 select WMA.TYPE, WMA.DISPLAY_NAME,
7227 decode(WMA.TYPE, 'URL', WF_NOTIFICATION.GetUrlText(WNA.TEXT_VALUE,
7228 GetURLAttachment.nid), WNA.TEXT_VALUE) URL,
7229 WNA.NAME
7230 from WF_NOTIFICATION_ATTRIBUTES WNA, WF_NOTIFICATIONS WN,
7231 WF_MESSAGE_ATTRIBUTES_VL WMA
7232 where WNA.NOTIFICATION_ID = GetURLAttachment.nid
7233 and WN.NOTIFICATION_ID = WNA.NOTIFICATION_ID
7234 and WN.MESSAGE_TYPE = WMA.MESSAGE_TYPE
7235 and WN.MESSAGE_NAME = WMA.MESSAGE_NAME
7236 and (WMA.TYPE = 'URL')
7237 and WMA.ATTACH = 'Y'
7238 and WMA.NAME = WNA.NAME;
7239
7240
7241 no_program_unit exception;
7242 pragma exception_init(no_program_unit, -6508);
7243
7244 begin
7245
7246 -- Get the template.
7247 begin
7248 select SUBJECT, HTML_BODY
7249 into l_subject, l_html_body
7250 from WF_MESSAGES_VL
7251 where NAME = 'ATTACHED_URLS' and TYPE = 'WFMAIL';
7252 exception
7253 when no_data_found then
7254 -- If the template has not been installed, then construct a
7255 -- default, minimem template.
7256 l_html_body := '<HTML><BODY><B><FONT SIZE=+1>'||
7257 'Notificaiton References</FONT></B>'||
7258 '<BR>Default Template<BR>'||
7259 '&'||'URLLIST</BODY><HTML>';
7260
7261 end;
7262
7263 -- Build the list of URLs
7264 l_urlcount := 0;
7265 l_urllist := '<BR>';
7266 for urlattr in ntf loop
7267 l_url := wf_notification.SetFrameworkAgent(urlattr.url);
7268 l_urllist := l_urllist || '<A class="OraLink" HREF="' || l_url || '">' ||
7269 urlattr.display_name || '</A><BR>'||g_newLine;
7270 l_urlcount := l_urlcount + 1;
7271 end loop;
7272
7273
7274 -- Substitute the list
7275 if l_urlcount > 0 then
7276 buffer := substrb(replace(l_html_body, '&'||'URLLIST', l_urllist), 1, 32000);
7277 else
7278 buffer := '';
7279 end if;
7280 exception
7281 when no_program_unit then
7282 wf_core.context('WF_MAIL', 'GetURLAttachment', to_char(nid));
7283 raise;
7284 when others then
7285 -- First look for a wf_core error.
7286 wf_core.get_error(err_name, err_message, err_stack);
7287
7288 -- If no wf_core error look for a sql error.
7289 if (err_name is null) then
7290 err_message := sqlerrm;
7291 end if;
7292
7293 error_result := err_message;
7294 wf_core.context('WF_MAIL', 'GetURLAttachment', to_char(nid));
7295
7296 end;
7297
7298
7299
7300 -- Direct_Response - Return the value of the direct response flag
7301 --
7302 -- OUT
7303 -- Direct Response as [TRUE|FALSE]
7304 function Direct_Response return boolean
7305 is
7306 begin
7307 return g_direct_response;
7308 end;
7309
7310 -- Send_Accesskey - Return the value of the send access key flag
7311 --
7312 -- OUT
7313 -- Direct Response as [TRUE|FALSE]
7314 function Send_Accesskey return boolean
7315 is
7316 enabled varchar2(1);
7317 flag boolean;
7318 begin
7319 if g_install = 'EMBEDDED' then
7320 enabled := FND_PROFILE.Value('WF_VALIDATE_NTF_ACCESS');
7321 if enabled = 'Y' then
7322 flag := TRUE;
7323 else
7324 flag := FALSE;
7325 end if;
7326 else
7327 flag := g_send_accesskey;
7328 end if;
7329
7330 return flag;
7331
7332 end;
7333
7334 -- autoclose_fyi - Return the value of the autoclose fyi flag
7335 --
7336 -- OUT
7337 -- AUTOCLOSE_FYI as [TRUE|FALSE]
7338 function Autoclose_FYI return boolean
7339 is
7340 begin
7341 return g_autoclose_fyi;
7342 end;
7343
7344 -- Direct_Response_On - Set the value of the direct response flag to TRUE
7345 --
7346 procedure Direct_Response_On
7347 is
7348 begin
7349 g_direct_response := TRUE;
7350 end;
7351
7352 -- Direct_Response_Off - Set the value of the direct response flag to FALSE
7353 --
7354 procedure Direct_Response_off
7355 is
7356 begin
7357 g_direct_response := FALSE;
7358 end;
7359
7360 -- send_accesskey_on - Set the value of the send acces key flag to TRUE
7361 --
7362 procedure Send_Access_Key_On
7363 is
7364 begin
7365 g_send_accesskey := TRUE;
7366 end;
7367
7368 -- Send_Accesskey_oOf - Set the value of the send acces key flag to FALSE
7369 --
7370 procedure Send_Access_Key_Off
7371 is
7372 begin
7373 g_send_accesskey := FALSE;
7374 end;
7375
7376 -- Autoclose_FYI_On - Set the value of the autoclose FYI flag to TRUE
7377 --
7378 procedure Autoclose_FYI_On
7379 is
7380 begin
7381 g_autoclose_fyi := TRUE;
7382 end;
7383
7384 -- Autoclose_FYI_Off - Set the value of the autoclose FYI flag to FALSE
7385 --
7386 procedure Autoclose_FYI_Off
7387 is
7388 begin
7389 g_autoclose_fyi := FALSE;
7390 end;
7391
7392 -- set_template - Set the mail template
7393 -- if nothing is specify, it will clear the mail template value.
7394 procedure set_template(name in varchar2)
7395 is
7396 begin
7397 g_template := substr(name, 1, 30);
7398 end set_template;
7399
7400 --
7401 -- GetCharset (PRIVATE)
7402 -- Get the character set base of the language and territory info.
7403 -- NOTE
7404 -- We may do more in the future to find the character set.
7405 --
7406 procedure GetCharset(lang in varchar2,
7407 terr in varchar2,
7408 charset out NOCOPY varchar2)
7409 is
7410 begin
7411 begin
7412 if (terr is null) then
7413 raise NO_DATA_FOUND;
7414 end if;
7415 select NLS_CODESET
7416 into charset
7417 from WF_LANGUAGES
7418 where NLS_LANGUAGE = lang
7419 and NLS_TERRITORY = terr;
7420 exception
7421 when NO_DATA_FOUND then
7422 -- try to find the character set base on language alone
7423 select NLS_CODESET
7424 into charset
7425 from WF_LANGUAGES
7426 where NLS_LANGUAGE = lang
7427 and rownum < 2;
7428 end;
7429 exception
7430 when OTHERS then
7431 wf_core.context('WF_MAIL', 'GetCharset', lang, terr);
7432 raise;
7433 end GetCharset;
7434
7435
7436
7437
7438
7439
7440 -- GetSessionLanguage
7441 -- Get the session language and territory for the
7442 -- current session
7443 --
7444 -- OUT
7445 -- Language
7446 -- Territory
7447 -- codeset
7448 procedure GetSessionLanguage(lang out NOCOPY varchar2,
7449 terr out NOCOPY varchar2,
7450 codeset out NOCOPY varchar2)
7451 is
7452 nls_str varchar2(1000);
7453 underscore integer;
7454 dot integer;
7455 db_override_cs varchar2(30);
7456 begin
7457 GetSessionLanguage(lang, terr, codeset, db_override_cs);
7458
7459 end GetSessionLanguage;
7460
7461 procedure GetSessionLanguage(lang out NOCOPY varchar2,
7462 terr out NOCOPY varchar2,
7463 codeset out NOCOPY varchar2,
7464 db_override_cs out NOCOPY varchar2)
7465 is
7466 nls_str varchar2(1000);
7467 underscore integer;
7468 dot integer;
7469 begin
7470 select userenv('LANGUAGE')
7471 into nls_str
7472 from sys.dual;
7473
7474 underscore := instr(nls_str,'_',1,1);
7475 dot := instr(nls_str, '.',1,1);
7476
7477 lang := substr(nls_str, 1, underscore-1);
7478 terr := substr(nls_str, underscore+1, dot - underscore -1);
7479 codeset := substr(nls_str, dot+1);
7480
7481 --
7482 -- Storing in a different variable because if we store in "codeset" variable
7483 -- then we can not determine (at java layer) whether it is IANA char-set and require to call
7484 -- NLSMapper to get IANA EQ or NOT.
7485 begin
7486 select override_email_charset
7487 into db_override_cs
7488 from wf_languages
7489 where code ='WFCS'
7490 and rownum < 2 ; -- This language code is being used to store
7491 -- overridden DB default char-set, if any.
7492 exception
7493 when no_data_found then
7494 db_override_cs := null;
7495 end;
7496
7497
7498 exception
7499 when others then
7500 wf_core.context('WF_MAIL', 'GetSessionLanguage');
7501 raise;
7502 end GetSessionLanguage;
7503
7504
7505
7506 -- Bug 2375920
7507 -- GetSignaturePolicy (PUBLIC)
7508 -- Get the signature policy for the notification from
7509 -- the notification attribute
7510 -- IN
7511 -- nid - Notification id
7512 -- OUT
7513 -- sig_policy - Signature policy
7514
7515 procedure GetSignaturePolicy(nid in number,
7516 sig_policy out NOCOPY varchar2)
7517 is
7518 begin
7519 -- Get value for signature policy for the notification from
7520 -- notification attribute
7521 sig_policy := Wf_Notification.GetAttrText(nid, '#WF_SIG_POLICY');
7522
7523 exception
7524 when others then
7525 if (wf_core.error_name = 'WFNTF_ATTR') then
7526 wf_core.clear;
7527 sig_policy := 'DEFAULT';
7528 else
7529 raise;
7530 end if;
7531 end GetSignaturePolicy;
7532
7533 -- gets the size of the current LOB table
7534 function getLobTableSize return number
7535 is
7536 begin
7537 return g_LOBTable.COUNT;
7538 end;
7539
7540 --
7541 -- GetSecurityPolicy
7542 --
7543 procedure GetSecurityPolicy(p_nid in number,
7544 p_sec_policy out NOCOPY varchar2)
7545 is
7546 begin
7547 -- Get security policy for the notification
7548 p_sec_policy := Wf_Notification.GetAttrText(p_nid, '#WF_SECURITY_POLICY');
7549 if (p_sec_policy is null) then
7550 p_sec_policy := 'DEFAULT';
7551 end if;
7552 exception
7553 when others then
7554 if (wf_core.error_name = 'WFNTF_ATTR') then
7555 wf_core.clear;
7556 p_sec_policy := 'DEFAULT';
7557 else
7558 raise;
7559 end if;
7560 end GetSecurityPolicy;
7561
7562 --
7563 -- ProcessSecurityPolicy
7564 --
7565 procedure ProcessSecurityPolicy(p_nid in number,
7566 p_email out NOCOPY varchar2,
7567 p_message_name out NOCOPY varchar2)
7568 is
7569 l_sec_policy varchar2(100);
7570 l_email_allowed varchar2(1);
7571 begin
7572 -- Get security policy for the notification
7573 Wf_Mail.GetSecurityPolicy(p_nid, l_sec_policy);
7574
7575 -- If the policy is not seeded, default it to Y to allow email
7576 begin
7577 SELECT email_allowed
7578 INTO l_email_allowed
7579 FROM wf_ntf_security_policies
7580 WHERE policy_name = l_sec_policy;
7581 exception
7582 when others then
7583 Wf_Core.Token('NID', to_char(p_nid));
7584 Wf_Core.Token('POLICY', l_sec_policy);
7585 Wf_Core.Raise('WFMLR_INVALID_SEC_POLICY');
7586 end;
7587
7588 -- There should be a way to avoid hard-coding the values !!!
7589 p_email := l_email_allowed;
7590
7591 -- Policy is either EMAIL_OK or DEFAULT
7592 if (l_email_allowed = 'Y') then
7593 p_message_name := null;
7594
7595 -- Policy NO_EMAIL, the notification is not to be sent by e-mail
7596 elsif (l_email_allowed = 'N') then
7597 p_message_name := 'OPEN_MAIL_SECURE';
7598
7599 -- Policy is ENC_EMAIL_ONLY. Requires the notification to be encrypted. Currently not
7600 -- supported, so inform the user to access the online notification
7601 elsif (l_email_allowed = 'E') then
7602 p_message_name := 'OPEN_MAIL_SECURE';
7603 end if;
7604
7605 exception
7606 when others then
7607 Wf_Core.Context('Wf_Mail', 'ProcessSecurityPolicy', to_char(p_nid));
7608 raise;
7609 end ProcessSecurityPolicy;
7610
7611 -- Set_FYI_Flag (Private)
7612 -- Sets a global flag to identify if the current e-mail being processed is a
7613 -- FYI notification
7614 -- IN
7615 -- p_fyi boolean
7616 procedure Set_FYI_Flag(p_fyi in boolean)
7617 is
7618 begin
7619 g_fyi := p_fyi;
7620 end Set_FYI_Flag;
7621
7622 -- Get_FYI_Flag (Private)
7623 -- Returns a global flag to identify if the current e-mail being processed is
7624 -- a FYI notification
7625 -- OUT
7626 -- Boolean value
7627 function Get_FYI_Flag return boolean
7628 is
7629 begin
7630 return g_fyi;
7631 end Get_FYI_Flag;
7632
7633
7634
7635
7636 -- Get_Ntf_Language (PRIVATE)
7637 -- Overrides the language and territory setting for the notification based
7638 -- on the #WFM_LANGUAGE and #WFM_TERRITORY attributes. If neither user's
7639 -- preference nor the notification level setting are valid, the base NLS
7640 -- setting is used
7641 -- IN
7642 -- p_nid - Notification Id
7643 -- IN OUT
7644 -- p_language - NLS Language
7645 -- p_territory - NLS Territory
7646 -- p_codeset - NLS Codeset
7647 -- p_is_iana_cs - flag to indicate if codeset is IANA
7648 --
7649 procedure Get_Ntf_Language(p_nid in number,
7650 p_language in out nocopy varchar2,
7651 p_territory in out nocopy varchar2,
7652 p_codeset in out nocopy varchar2,
7653 p_is_iana_cs in out nocopy varchar2)
7654 is
7655 l_lang varchar2(64);
7656 l_terr varchar2(64);
7657 l_install varchar2(1);
7658 l_codeset varchar2(30);
7659
7660 l_base_lang varchar2(64);
7661 l_base_terr varchar2(64);
7662 l_base_codeset varchar2(30);
7663
7664 l_base_nlsDateFormat VARCHAR2(64);
7665 l_base_nlsDateLanguage varchar2(64);
7666 l_base_nlsCalendar varchar2(64);
7667 l_base_nlsNumericCharacters varchar2(30);
7668 l_base_nlsSort varchar2(64);
7669 l_base_nlsCurrency varchar2(30);
7670 l_is_iana_cs varchar2(30);
7671
7672 begin
7673
7674 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
7675 wf_log_pkg.string(wf_log_pkg.level_statement, 'wf.plsql.wf_mail.Get_Ntf_Language.BEGIN',
7676 'User preferences. LANG {'||p_language||'} TERR {'||p_territory||'}');
7677 end if;
7678
7679 -- Get notification's language preference
7680 begin
7681 l_lang := upper(Wf_Notification.GetAttrText(p_nid, '#WFM_LANGUAGE'));
7682 exception
7683 when others then
7684 if (wf_core.error_name = 'WFNTF_ATTR') then
7685 wf_core.clear();
7686 l_lang := null;
7687 else
7688 raise;
7689 end if;
7690 end;
7691
7692 l_install := 'N';
7693
7694 -- Message level language is different than user language
7695 if (l_lang is not NULL AND l_lang <> p_language ) then
7696 -- Check for validity of notification's language
7697 begin
7698 select nvl(OVERRIDE_EMAIL_CHARSET,nls_codeset),
7699 installed_flag,
7700 decode(OVERRIDE_EMAIL_CHARSET, null, 'N', 'Y')
7701 into l_codeset, l_install , l_is_iana_cs
7702 from wf_languages
7703 where nls_language = l_lang
7704 AND installed_flag = 'Y';
7705
7706 p_language := l_lang;
7707 p_codeset := l_codeset;
7708 p_is_iana_cs := l_is_iana_cs;
7709 exception
7710 when others then
7711 l_install := 'N'; -- this will be used to determine whether base language should be used.
7712 end;
7713 end if;
7714
7715 if(l_install = 'N') then -- language is different or message level language does not exist / installed.
7716
7717 begin
7718 select nvl(OVERRIDE_EMAIL_CHARSET,nls_codeset),
7719 installed_flag,
7720 decode(OVERRIDE_EMAIL_CHARSET, null, 'N', 'Y')
7721 into l_codeset, l_install , l_is_iana_cs
7722 from wf_languages
7723 where nls_language = p_language
7724 and installed_flag = 'Y';
7725
7726 p_codeset := l_codeset;
7727 p_is_iana_cs := l_is_iana_cs;
7728
7729 exception
7730 when others then
7731 p_language := null;
7732 end;
7733 end if;
7734
7735
7736 -- Get notification's territory preference
7737 begin
7738 l_terr := upper(Wf_Notification.GetAttrText(p_nid, '#WFM_TERRITORY'));
7739 exception
7740 when others then
7741 if (wf_core.error_name = 'WFNTF_ATTR') then
7742 wf_core.clear();
7743 l_terr := null;
7744 else
7745 raise;
7746 end if;
7747 end;
7748
7749 l_install := 'N';
7750 if (l_terr is not null) then
7751 begin
7752 -- sstomar: As per IPG, use fnd_territories
7753 select 'Y'
7754 into l_install
7755 from fnd_territories
7756 where obsolete_flag = 'N'
7757 and nls_territory = p_territory;
7758
7759 p_territory := l_terr;
7760 exception
7761 when others then
7762 l_install := 'N';
7763 p_territory := null;
7764 end;
7765 end if;
7766
7767 -- If at least one of the value is null, use the base NLS setting
7768 if (p_language is null or p_territory is null) then
7769 if (wf_log_pkg.level_statement >= fnd_log.g_current_runtime_level) then
7770 wf_log_pkg.string(wf_log_pkg.level_statement, 'wf.plsql.wf_mail.Get_Ntf_Language.NULL',
7771 'Using base NLS setting because p_language is {'||p_language||
7772 '} and p_territory is {'||p_territory||'}');
7773 end if;
7774
7775 -- <<sstomar>> :
7776 -- WF_MAIL.GetSessionLanguage(l_base_lang, l_base_terr, l_base_codeset);
7777 -- Note: we should AVOID to call below API here
7778 -- use global variables instead .
7779 WF_NOTIFICATION_UTIL.getNLSContext(
7780 l_base_lang ,
7781 l_base_terr ,
7782 l_base_codeset ,
7783 l_base_nlsDateFormat ,
7784 l_base_nlsDateLanguage ,
7785 l_base_nlsNumericCharacters ,
7786 l_base_nlsSort ,
7787 l_base_nlsCalendar
7788 );
7789
7790 if (p_language is null) then
7791 p_language := l_base_lang;
7792 p_codeset := l_base_codeset;
7793 p_is_iana_cs := 'N' ;
7794 end if;
7795
7796 p_territory := nvl(p_territory, l_base_terr);
7797
7798 end if;
7799
7800 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
7801 wf_log_pkg.string(wf_log_pkg.level_procedure, 'wf.plsql.wf_mail.Get_Ntf_Language.END',
7802 'Email Notification LANG {'||p_language||'} TERR {'||p_territory||'}'||
7803 ' CODESET {'||p_codeset||'}');
7804 end if;
7805
7806 exception
7807 when others then
7808 Wf_Core.Context('Wf_Mail', 'Get_Ntf_Language', to_char(p_nid), p_language, p_territory);
7809 raise;
7810 end Get_Ntf_Language;
7811
7812
7813
7814
7815 -- Get_Ntf_Language (PRIVATE)
7816 -- Overrides the language and territory setting for the notification based
7817 -- on the #WFM_LANGUAGE and #WFM_TERRITORY attributes. If neither user's
7818 -- preference nor the notification level setting are valid, the base NLS
7819 -- setting is used
7820 -- IN
7821 -- p_nid - Notification Id
7822 -- IN OUT
7823 -- p_language - NLS Language
7824 -- p_territory - NLS Territory
7825 -- p_codeset - NLS Codeset
7826 procedure Get_Ntf_Language(p_nid in number,
7827 p_language in out nocopy varchar2,
7828 p_territory in out nocopy varchar2,
7829 p_codeset in out nocopy varchar2)
7830 is
7831 l_is_iana_cs varchar2(1);
7832
7833 begin
7834 Get_Ntf_Language(p_nid, p_language, p_territory, p_codeset, l_is_iana_cs);
7835
7836 END Get_Ntf_Language;
7837
7838 --
7839 -- Generic mailer routines
7840 --
7841
7842 -- Send
7843 -- Sends a e-mail notification to the specified list of recipients.
7844 -- This API unlike wf_notification.send does not require workflow
7845 -- message or workflow roles to send a notification.
7846
7847 procedure send(p_subject in varchar2,
7848 p_message in out nocopy clob,
7849 p_recipient_list in wf_recipient_list_t,
7850 p_module in varchar2,
7851 p_idstring in varchar2,
7852 p_from in varchar2,
7853 p_replyto in varchar2,
7854 p_language in varchar2,
7855 p_territory in varchar2,
7856 p_codeset in varchar2,
7857 p_content_type in varchar2,
7858 p_callback_event in varchar2,
7859 p_event_key in varchar2,
7860 p_fyi_flag in varchar2)
7861 is
7862 l_module varchar2(10);
7863 l_str varchar2(4000);
7864 l_attrlist wf_xml.wf_xml_attr_table_type;
7865 l_pos integer;
7866 l_amt number;
7867
7868 l_msg_doc clob;
7869 l_event wf_event_t;
7870 l_agent wf_agent_t;
7871 l_parameter_list wf_parameter_list_t;
7872 l_event_name varchar2(240);
7873 l_event_key varchar2(240);
7874 l_recp_type varchar2(10);
7875 l_name varchar2(360);
7876 l_email varchar2(240);
7877 l_replyto varchar2(240);
7878 l_subject varchar2(2000);
7879 l_from varchar2(360);
7880 l_nodename varchar2(240);
7881 l_idstr varchar2(240);
7882 l_idsize integer;
7883
7884 l_recp_clob clob;
7885 l_recp clob;
7886 l_recp_tmp varchar2(32000);
7887 l_recp_txt varchar2(32000);
7888 l_recp_pos integer;
7889 l_recp_is_lob boolean;
7890 l_recp_len integer;
7891 l_hdr_tmp varchar2(32000);
7892 l_hdr_pos integer;
7893 l_occurance integer := 1;
7894 i integer;
7895
7896
7897 l_messageIdx pls_integer;
7898 l_start_cdata VARCHAR2(10) := '<![CDATA[';
7899 l_end_cdata VARCHAR2(4) := ']]>';
7900 l_fyi_flag boolean;
7901
7902 begin
7903
7904 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
7905 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
7906 'wf.plsql.WF_MAIL.send',
7907 'BEGIN');
7908 end if;
7909
7910 -- Test the FYI flag. If set, then treat this message as FYI
7911 -- i.e. No ID string to be appended. Same is true if the ID string is
7912 -- null irresepective of the p_fyi_flag.
7913 if (p_fyi_flag is not null and upper(p_fyi_flag) = 'Y')
7914 or p_idstring is null then
7915 l_fyi_flag := true;
7916 else
7917 l_fyi_flag := false;
7918 end if;
7919
7920 -- Recipients required
7921 if (p_recipient_list is null) then
7922 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
7923 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
7924 'wf.plsql.WF_MAIL.send',
7925 'Recipient List is empty. ');
7926 end if;
7927
7928 wf_core.raise('WFMLR_NO_RECIPIENTS');
7929 end if;
7930
7931 -- At least subject or body is required
7932 if (p_subject is null and (p_message is null or dbms_lob.GetLength(p_message)=0)) then
7933 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
7934 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
7935 'wf.plsql.WF_MAIL.send',
7936 'Subject and Message Contents are blank or null. ');
7937 end if;
7938
7939 wf_core.raise('WFMLR_MSG_INCOMPLETE');
7940 end if;
7941
7942 -- For all e-mails, respone or FYI, module name is required
7943 if (p_module is null) then
7944 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
7945 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
7946 'wf.plsql.WF_MAIL.send',
7947 'Message module is not specified. ');
7948 end if;
7949
7950 wf_core.raise('WFMLR_NO_MODULE');
7951 end if;
7952
7953 dbms_lob.createTemporary(l_msg_doc, TRUE, dbms_lob.call);
7954 l_str := '<?xml version="1.0" ?>';
7955 l_pos := length(l_str);
7956 dbms_lob.write(l_msg_doc, l_pos, 1, l_str);
7957
7958 -- <NOTIFICATIONGROUP> begin
7959 wf_xml.AddElementAttribute('maxcount', '1', l_attrlist);
7960 l_pos := wf_xml.NewLOBTag(l_msg_doc, l_pos, 'NOTIFICATIONGROUP', '', l_attrlist);
7961 l_attrlist.DELETE;
7962
7963 l_nodename := WF_MAILER_PARAMETER.GetValueForCorr(p_module, 'NODENAME');
7964
7965 -- Id string required for response required alerts.
7966 -- We assume that a null id string constitutes a FYI message
7967 if (p_idstring is not null and l_fyi_flag = false) then
7968 if (trim(p_module) <> g_Alert_Nodename) then
7969 l_module := '#X_'||trim(p_module);
7970 else
7971 l_module := p_module;
7972 end if;
7973 l_idstr := l_module||'['||p_idstring||'/0000@'||l_nodename||']';
7974 else
7975 l_idstr := null;
7976 end if;
7977
7978 -- <NOTIFICATION> begin
7979 wf_xml.AddElementAttribute('nid', '0', l_attrlist);
7980 wf_xml.AddElementAttribute('nidstr', l_idstr, l_attrlist);
7981 wf_xml.AddElementAttribute('language', p_language, l_attrlist);
7982 wf_xml.AddElementAttribute('territory', p_territory, l_attrlist);
7983 wf_xml.AddElementAttribute('codeset', p_codeset, l_attrlist);
7984
7985 -- <<sstomar>>:
7986 -- Setting default parameter's value until ALR team starts to pass
7987 -- below parameter's values.
7988 -- TODO>>
7989 wf_xml.AddElementAttribute('nlsDateformat', wf_core.nls_date_format, l_attrlist);
7990 wf_xml.AddElementAttribute('nlsDateLanguage', wf_core.nls_date_language, l_attrlist);
7991 wf_xml.AddElementAttribute('nlsNumericCharacters', wf_core.nls_numeric_characters, l_attrlist);
7992 wf_xml.AddElementAttribute('nlsSort', wf_core.nls_sort, l_attrlist);
7993
7994 wf_xml.AddElementAttribute('priority', '50', l_attrlist);
7995 wf_xml.AddElementAttribute('accesskey', '0', l_attrlist);
7996 wf_xml.AddElementAttribute('node', l_nodename, l_attrlist);
7997 wf_xml.AddElementAttribute('item_type', 'NULL', l_attrlist);
7998 wf_xml.AddElementAttribute('message_name', 'NULL', l_attrlist);
7999 wf_xml.AddElementAttribute('full-document', 'Y', l_attrlist);
8000
8001 if (p_callback_event is not null) then
8002 wf_xml.AddElementAttribute('callback', p_callback_event, l_attrlist);
8003 end if;
8004
8005 l_pos := wf_xml.NewLOBTag(l_msg_doc, l_pos, 'NOTIFICATION', '', l_attrlist);
8006 l_attrlist.DELETE;
8007
8008 dbms_lob.createTemporary(l_recp_clob, TRUE, dbms_lob.call);
8009
8010 l_recp_pos := 0;
8011 l_recp_tmp := '';
8012
8013 i := p_recipient_list.first;
8014 while (i is not null) loop
8015 l_name := replace(p_recipient_list(i).name, g_newline);
8016 l_recp_type := p_recipient_list(i).recipient_type;
8017
8018 -- <RECIPIENT> begin
8019 wf_xml.AddElementAttribute('name', l_name, l_attrlist);
8020 wf_xml.AddElementAttribute('type', l_recp_type, l_attrlist);
8021 l_recp_pos := wf_xml.NewTag(l_recp_tmp, l_recp_pos, 'RECIPIENT', '', l_attrlist);
8022 l_attrlist.DELETE;
8023
8024 -- <NAME>
8025 l_recp_pos := wf_xml.NewTag(l_recp_tmp, l_recp_pos, 'NAME', l_name, l_attrlist);
8026 l_recp_pos := wf_xml.SkipTag(l_recp_tmp, 'NAME', l_recp_pos, l_occurance);
8027
8028 -- <ADDRESS>
8029 l_email := '<![CDATA['||replace(p_recipient_list(i).address, g_newline)||']]>';
8030 l_recp_pos := wf_xml.NewTag(l_recp_tmp, l_recp_pos, 'ADDRESS', l_email, l_attrlist);
8031 l_recp_pos := wf_xml.SkipTag(l_recp_tmp, 'ADDRESS', l_recp_pos, l_occurance);
8032
8033 -- <RECIPIENT> end
8034 l_recp_pos := wf_xml.SkipTag(l_recp_tmp, 'RECIPIENT', l_recp_pos, l_occurance);
8035 l_attrlist.DELETE;
8036
8037 i := p_recipient_list.next(i);
8038
8039 l_recp_len := length(l_recp_tmp);
8040 if (l_recp_len > 30000) then
8041 dbms_lob.WriteAppend(l_recp_clob, l_recp_len, l_recp_tmp);
8042 l_recp_tmp := '';
8043 l_recp_pos := 0;
8044 l_recp_is_lob := true;
8045 end if;
8046 end loop;
8047
8048 l_recp_len := length(l_recp_tmp);
8049 if(l_recp_len > 0 and l_recp_is_lob) then
8050 dbms_lob.WriteAppend(l_recp_clob, l_recp_len, l_recp_tmp);
8051 end if;
8052
8053 -- <RECIPIENTLIST> start
8054 l_recp_pos := 0;
8055 if (l_recp_is_lob) then
8056 dbms_lob.createTemporary(l_recp, TRUE, dbms_lob.call);
8057 l_recp_pos := wf_xml.NewLOBTag(l_recp, l_recp_pos, 'RECIPIENTLIST', l_recp_clob, l_attrlist);
8058 l_recp_pos := wf_xml.SkipLOBTag(l_recp, 'RECIPIENTLIST', l_recp_pos, l_occurance);
8059 else
8060 l_recp_pos := wf_xml.NewTag(l_recp_txt, l_recp_pos, 'RECIPIENTLIST', l_recp_tmp, l_attrlist);
8061 l_recp_pos := wf_xml.SkipTag(l_recp_txt, 'RECIPIENTLIST', l_recp_pos, l_occurance);
8062 end if;
8063
8064 l_hdr_pos := 0;
8065 l_hdr_tmp := '';
8066
8067 if (p_from is not null or p_replyto is not null) then
8068 -- <FROM> start
8069 l_hdr_pos := wf_xml.NewTag(l_hdr_tmp, l_hdr_pos, 'FROM', '', l_attrlist);
8070
8071 -- <NAME>
8072 if (p_from is not null) then
8073 l_from := replace(p_from, g_newLine);
8074 -- Bug 13786156: Use CDATA for From header value as the XML parser is throwing SAXParseException
8075 -- in java layer when From value is email address of the form "Display Name <name@domain>"
8076 l_from := '<![CDATA['||l_from||']]>';
8077 l_hdr_pos := wf_xml.NewTag(l_hdr_tmp, l_hdr_pos, 'NAME', l_from, l_attrlist);
8078 l_hdr_pos := wf_xml.SkipTag(l_hdr_tmp, 'NAME', l_hdr_pos, l_occurance);
8079 end if;
8080
8081 -- <ADDRESS>
8082 if (p_replyto is not null) then
8083 l_replyto := replace(p_replyto, g_newLine);
8084 l_replyto := '<![CDATA['||l_replyto||']]>';
8085 l_hdr_pos := wf_xml.NewTag(l_hdr_tmp, l_hdr_pos, 'ADDRESS', l_replyto, l_attrlist);
8086 l_hdr_pos := wf_xml.SkipTag(l_hdr_tmp, 'ADDRESS', l_hdr_pos, l_occurance);
8087 end if;
8088
8089 -- <FROM> end
8090 l_hdr_pos := wf_xml.SkipTag(l_hdr_tmp, 'FROM', l_hdr_pos, l_occurance);
8091 end if;
8092
8093 l_subject := replace(p_subject, g_newLine);
8094 l_subject := '<![CDATA['||l_subject||']]>';
8095 l_hdr_pos := wf_xml.NewTag(l_hdr_tmp, l_hdr_pos, 'SUBJECT', l_subject, l_attrlist);
8096 l_hdr_pos := wf_xml.SkipTag(l_hdr_tmp, 'SUBJECT', l_hdr_pos, l_occurance);
8097
8098 if (l_recp_is_lob) then
8099 dbms_lob.WriteAppend(l_recp, length(l_hdr_tmp), l_hdr_tmp);
8100 l_pos := wf_xml.NewLOBTag(l_msg_doc, l_pos, 'HEADER', l_recp, l_attrlist);
8101 else
8102 l_hdr_tmp := l_recp_txt || l_hdr_tmp;
8103 l_pos := wf_xml.NewLOBTag(l_msg_doc, l_pos, 'HEADER', l_hdr_tmp, l_attrlist);
8104 end if;
8105 l_pos := wf_xml.SkipLOBTag(l_msg_doc, 'HEADER', l_pos, l_occurance);
8106 l_attrlist.DELETE;
8107
8108 -- <CONTENT> start
8109 wf_xml.AddElementAttribute('content-type', 'multipart/mixed', l_attrlist);
8110 l_pos := wf_xml.NewLOBTag(l_msg_doc, l_pos, 'CONTENT', '', l_attrlist);
8111 l_attrlist.DELETE;
8112
8113 -- <BODYPART> start
8114 wf_xml.AddElementAttribute('content-type', p_content_type, l_attrlist);
8115 l_pos := wf_xml.NewLOBTag(l_msg_doc, l_pos, 'BODYPART', '', l_attrlist);
8116
8117 -- <MESSAGE>
8118
8119 l_messageIdx := wf_temp_lob.getLOB(g_LOBTable);
8120
8121 dbms_lob.trim(g_LOBTable(l_messageIdx).temp_lob,0);
8122
8123 dbms_lob.writeAppend(g_LOBTable(l_messageIdx).temp_lob,
8124 length(l_start_cdata), l_start_cdata);
8125
8126 dbms_lob.append(dest_lob => g_LOBTable(l_messageIdx).temp_lob,
8127 src_lob => p_message);
8128
8129 if l_idstr is not null and l_fyi_flag = false then
8130 l_idstr := wf_core.newline||l_idstr;
8131 l_idsize := length(l_idstr);
8132 dbms_lob.writeAppend(lob_loc => g_LOBTable(l_messageIdx).temp_lob,
8133 amount => l_idsize,
8134 buffer => l_idstr);
8135 end if;
8136
8137 dbms_lob.writeAppend(g_LOBTable(l_messageIdx).temp_lob,
8138 length(l_end_cdata), l_end_cdata);
8139
8140 -- Alert Message has been appended in XML Payload, can be released now
8141 l_pos := wf_xml.NewLOBTag(l_msg_doc, l_pos, 'MESSAGE',
8142 g_LOBTable(l_messageIdx).temp_lob, l_attrlist);
8143 l_pos := wf_xml.SkipLOBTag(l_msg_doc, 'MESSAGE', l_pos, l_occurance);
8144
8145 l_attrlist.DELETE;
8146
8147 -- <BODYPART> end
8148 l_pos := wf_xml.SkipLOBTag(l_msg_doc, 'BODYPART', l_pos, l_occurance);
8149
8150 -- <CONTENT> end
8151 l_pos := wf_xml.SkipLOBTag(l_msg_doc, 'CONTENT', l_pos, l_occurance);
8152
8153 -- <NOTIFICATION> end
8154 l_pos := wf_xml.SkipLOBTag(l_msg_doc, 'NOTIFICATION', l_pos, l_occurance);
8155
8156 -- <NOTIFICATIONGROUP> end
8157 l_pos := wf_xml.SkipLOBTag(l_msg_doc, 'NOTIFICATIONGROUP', l_pos, l_occurance);
8158
8159 wf_event_t.Initialize(l_event);
8160
8161 l_event.event_name := wf_xml.WF_NTF_SEND_MESSAGE;
8162
8163 -- Create an event key based firstly on the parameter. If that does not
8164 -- exist, then base it on the ID string. If that too is null (FYI for
8165 -- instance) then create a default, non unique key.
8166 if p_event_key is not null then
8167 l_event.event_key := p_event_key;
8168 elsif p_idstring is not null then
8169 l_event.event_key := p_idstring;
8170 else
8171 l_event.event_key := p_module||':FYI';
8172 end if;
8173
8174 l_event.SetEventData(l_msg_doc);
8175
8176 l_agent := wf_agent_t('WF_NOTIFICATION_OUT', wf_event.local_system_name);
8177 l_event.SetFromAgent(l_agent);
8178
8179 -- Generally it would be 'ALR'
8180 if(instr( send.p_module, ':') = 0) then
8181 l_event.addParameterToList('Q_CORRELATION_ID', send.p_module || ':' );
8182 else
8183 l_event.addParameterToList('Q_CORRELATION_ID', send.p_module );
8184 END if;
8185
8186 l_event.addParameterToList('NOTIFICATION_ID', '0');
8187
8188 wf_event.send(l_event);
8189
8190 -- Release allocated temp LOBs back to pool
8191 wf_temp_lob.releaseLob(g_LOBTable, l_messageIdx);
8192
8193 if (wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
8194 wf_log_pkg.string(WF_LOG_PKG.level_procedure,
8195 'wf.plsql.WF_MAIL.send',
8196 'END');
8197 end if;
8198
8199 exception
8200 when others then
8201 -- Release allocated temp LOBs back to pool
8202 if(l_messageIdx > 0 ) then
8203 wf_temp_lob.releaseLob(g_LOBTable, l_messageIdx);
8204 END if;
8205
8206
8207 wf_core.context('Wf_Mail', 'Send', p_idstring, p_subject);
8208 raise;
8209 end Send;
8210
8211
8212 --
8213 -- SendMoreInfoResponseWarning
8214 -- procedure to send a warning notification about the answer for a More
8215 -- Informantion request that has already been answered.
8216 -- IN
8217 -- p_nid - Notification Id
8218 -- p_from_email - Email address of the responder
8219
8220 procedure SendMoreInfoResponseWarning(p_nid NUMBER, p_from_email VARCHAR2)
8221 is
8222 l_to_role VARCHAR2(360);
8223 l_from_role VARCHAR2(360);
8224 l_installed VARCHAR2(64);
8225 l_question VARCHAR2(4000);
8226 l_subject VARCHAR2(360);
8227 l_codeset VARCHAR2(360);
8228 l_orig_lang VARCHAR2(64);
8229 l_orig_terr VARCHAR2(64);
8230 l_orig_chrs VARCHAR2(64);
8231
8232 l_mail_error_message VARCHAR2(1024);
8233
8234 l_msg_type VARCHAR2(8);
8235 l_msg_name VARCHAR2(30);
8236 l_nodename VARCHAR2(240);
8237
8238 l_idstr VARCHAR2(240);
8239 l_str VARCHAR2(64);
8240
8241 l_description VARCHAR2(1000);
8242 l_start_cdata VARCHAR2(10) := '<![CDATA[';
8243 l_end_cdata VARCHAR2(4) := ']]>';
8244
8245 -- l_recp_tmp VARCHAR2(4000);
8246 l_text_body VARCHAR2(32000);
8247 l_html_body VARCHAR2(32000);
8248
8249 --l_recp_clob VARCHAR2(32000);
8250
8251 l_fax varchar2(240);
8252 l_expiration_date date;
8253 l_status varchar2(8);
8254 l_orig_system varchar2(30);
8255 l_orig_system_id number;
8256
8257 l_msg_doc CLOB;
8258 l_attrlist wf_xml.wf_xml_attr_table_type;
8259
8260 l_messageidx pls_integer;
8261 l_pos INTEGER;
8262 l_occurance INTEGER := 1;
8263
8264 l_event wf_event_t;
8265 l_agent wf_agent_t;
8266
8267 l_start pls_integer;
8268 l_end pls_integer;
8269
8270 hdrxml varchar2(32000);
8271 hdrxmlPos integer;
8272
8273
8274 l_display_name wf_roles.display_name%TYPE;
8275 l_to_emailaddress wf_roles.email_address%TYPE;
8276 l_to_ntf_pref wf_roles.notification_preference%TYPE;
8277 l_language wf_roles.LANGUAGE %TYPE;
8278 l_territory wf_roles.territory%TYPE;
8279
8280 CURSOR c_ques IS
8281 SELECT from_role, to_role, user_comment
8282 FROM wf_comments
8283 WHERE notification_id = p_nid
8284 AND action in ('QUESTION', 'QUESTION_WA', 'QUESTION_RULE')
8285 ORDER BY comment_date desc;
8286
8287 BEGIN
8288
8289 IF(wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) THEN
8290 wf_log_pkg.string(wf_log_pkg.level_procedure,
8291 'wf.plsql.WF_MAIL.SendMoreInfoResponseWarning', 'BEGIN');
8292 END IF;
8293
8294 -- Get details of last question asked from WF_COMMENTS table and
8295 -- Get role language, territory and codeset details.
8296
8297 OPEN c_ques;
8298 FETCH c_ques INTO l_from_role, l_to_role, l_question;
8299
8300 if (c_ques%notfound) then
8301 l_question := '';
8302 l_from_role := '';
8303 l_to_role := '';
8304 END if;
8305
8306 CLOSE c_ques;
8307
8308 -- Get role detail.
8309 wf_directory.GetRoleInfoMail(l_to_role, l_display_name, l_to_emailaddress, l_to_ntf_pref,
8310 l_language, l_territory, l_orig_system,
8311 l_orig_system_id,
8312 l_installed);
8313
8314
8315 -- if role not exist in wf_comments or email address exist
8316 -- in wf_comments then use p_from_email to get other details .
8317 --
8318 if( l_to_role = '' OR
8319 instr(l_to_role, '@') > 0 OR
8320 l_to_emailaddress IS null ) then
8321
8322 -- Stripping off unwanted info from email
8323 l_start := instr(p_from_email, '<', 1, 1);
8324
8325 if (l_start > 0) then
8326
8327 l_end := instr(p_from_email, '>', l_start);
8328 l_to_emailaddress := substr(p_from_email, l_start+1, l_end-l_start-1);
8329
8330 end if;
8331
8332 -- Get role detail based on email address.
8333 --
8334 WF_DIRECTORY.GetInfoFromMail(l_to_emailaddress, l_to_role, l_display_name,
8335 l_description, l_to_ntf_pref, l_language,
8336 l_territory, l_fax,l_expiration_date, l_status,
8337 l_orig_system, l_orig_system_id);
8338
8339 end if;
8340
8341
8342 begin
8343 SELECT NLS_CODESET, INSTALLED_FLAG
8344 INTO l_codeset,l_installed
8345 FROM WF_LANGUAGES
8346 WHERE NLS_LANGUAGE = l_language
8347 AND INSTALLED_FLAG = 'Y';
8348 exception
8349 when no_data_found then
8350 l_installed := 'N';
8351 end;
8352
8353 -- << sstomar>: The content of this warning ntf emil
8354 -- are generated by Mailer, so other NLS parameters ( NLS_DATE_FORMAT etc.
8355 -- because we don;t have any such attributes in message body)
8356 -- are not required to SET/ RESET but if we want to use centralized API
8357 -- wf_notification_util.setNLSContext / getNLSContext then we need to modify.
8358 --
8359
8360 -- getting the language for the session
8361 wf_notification.getnlslanguage(l_orig_lang, l_orig_terr, l_orig_chrs);
8362
8363 --
8364 If l_installed = 'Y' then
8365 -- Set user's language
8366 wf_notification.setnlslanguage(l_language, l_territory);
8367
8368 end if;
8369
8370 -- Get message details
8371 SELECT message_type,message_name
8372 INTO l_msg_type,l_msg_name
8373 FROM wf_notifications
8374 WHERE notification_id = p_nid;
8375
8376 -- Get template 'WARNING'
8377 SELECT subject, BODY, HTML_BODY
8378 INTO l_subject,l_text_body,l_html_body
8379 FROM wf_messages_vl
8380 WHERE name = 'MORE_INFO_ANSWERED'
8381 AND type = 'WFMAIL';
8382
8383 -- Get Error message
8384 begin
8385 SELECT TEXT INTO l_mail_error_message
8386 FROM WF_RESOURCES
8387 WHERE NAME = 'WFNTF_CANNOT_REPLY'
8388 AND LANGUAGE = userenv('LANG');
8389 exception
8390 when NO_DATA_FOUND then
8391 wf_core.raise('WFCORE_NO_MESSAGE');
8392 end;
8393
8394 l_nodename := wf_mailer_parameter.getvalueforcorr(
8395 l_msg_type||':'||l_msg_name,'NODENAME');
8396
8397 l_idstr := '';
8398
8399 -- Substitute Tags with values
8400 l_subject := SUBSTR(REPLACE(l_subject,'&NOTIFICATION',p_nid ),1, 360);
8401
8402 l_text_body := SUBSTR(REPLACE(l_text_body,
8403 '&MAIL_ERROR_MESSAGE',l_mail_error_message),1,32000);
8404
8405 l_text_body := SUBSTR(REPLACE(l_text_body,'&NOTIFICATION',p_nid),1,32000);
8406
8407 l_text_body := SUBSTR(REPLACE(l_text_body,'&FROM',l_from_role),1,32000);
8408
8409 l_text_body := SUBSTR(REPLACE(l_text_body,'&QUESTION',l_question),1,32000);
8410
8411 -- HTML BODY
8412 l_html_body := SUBSTR(REPLACE(l_html_body,
8413 '&MAIL_ERROR_MESSAGE',l_mail_error_message),1,32000);
8414
8415 l_html_body := SUBSTR(REPLACE(l_html_body,'&NOTIFICATION',p_nid),1,32000);
8416
8417 l_html_body := SUBSTR(REPLACE(l_html_body,'&FROM',l_from_role),1,32000);
8418
8419 l_html_body := SUBSTR(REPLACE(l_html_body,'&QUESTION',l_question),1,32000);
8420
8421 -- reset the session language
8422 WF_Notification.SetNLSLanguage(l_orig_lang, l_orig_terr);
8423
8424 -- LOB to store message payload.
8425 dbms_lob.createtemporary(l_msg_doc, TRUE,dbms_lob.CALL);
8426
8427 l_str := '<?xml version="1.0" ?>';
8428 l_pos := LENGTH(l_str);
8429 dbms_lob.WRITE(l_msg_doc, l_pos, 1, l_str);
8430
8431 -- <NOTIFICATIONGROUP> begin
8432 wf_xml.AddElementAttribute('maxcount','1',l_attrlist);
8433 l_pos := wf_xml.newlobtag(l_msg_doc,l_pos,'NOTIFICATIONGROUP','',l_attrlist);
8434 l_attrlist.DELETE;
8435
8436
8437 -- <NOTIFICATION> begin , set NID as 0 so that
8438 -- WF_NOTIFICATION.MAIL_STAUTS should not affect to deliver
8439 -- this warning message.
8440 wf_xml.AddElementAttribute('nid','0',l_attrlist);
8441 wf_xml.AddElementAttribute('nidstr',l_idstr,l_attrlist);
8442 wf_xml.AddElementAttribute('language',l_language,l_attrlist);
8443 wf_xml.AddElementAttribute('territory',l_territory,l_attrlist);
8444 wf_xml.AddElementAttribute('codeset',l_codeset,l_attrlist);
8445
8446 -- <<sstomar>>:
8447 -- Setting default parameter's value as for warning, as these parameters
8448 -- won't be used to update AppsContext (non-OAF content)
8449 -- TODO>>
8450 wf_xml.AddElementAttribute('nlsDateformat', wf_core.nls_date_format, l_attrlist);
8451 wf_xml.AddElementAttribute('nlsDateLanguage', wf_core.nls_date_language, l_attrlist);
8452 wf_xml.AddElementAttribute('nlsNumericCharacters', wf_core.nls_numeric_characters, l_attrlist);
8453 wf_xml.AddElementAttribute('nlsSort', wf_core.nls_sort, l_attrlist);
8454
8455 wf_xml.AddElementAttribute('priority','50',l_attrlist);
8456 wf_xml.AddElementAttribute('accesskey','0',l_attrlist);
8457 wf_xml.AddElementAttribute('node',l_nodename,l_attrlist);
8458 wf_xml.AddElementAttribute('item_type',l_msg_type,l_attrlist);
8459 wf_xml.AddElementAttribute('message_name',l_msg_name,l_attrlist);
8460 wf_xml.AddElementAttribute('full-document','Y',l_attrlist);
8461
8462 l_pos := wf_xml.NewLOBTag(l_msg_doc, l_pos,'NOTIFICATION','',l_attrlist);
8463 l_attrlist.DELETE;
8464
8465 -- Below variabkes are just to generate HEADER of
8466 -- xml PAYLOAD
8467 hdrxmlPos := 0;
8468 hdrxml := '';
8469
8470 hdrxmlPos := WF_XML.NewTag(hdrxml, hdrxmlPos, 'RECIPIENTLIST', '', l_attrlist);
8471
8472 -- TO
8473 WF_XML.AddElementAttribute('name', l_to_role, l_attrlist);
8474 WF_XML.AddElementAttribute('type', 'to', l_attrlist);
8475
8476 hdrxmlPos := WF_XML.NewTag(hdrxml, hdrxmlPos, 'RECIPIENT', '', l_attrlist);
8477 l_attrlist.DELETE;
8478
8479
8480 if (l_display_name is not null or l_display_name <> '') then
8481 l_display_name := replace(l_display_name, g_newLine);
8482 l_display_name := '<![CDATA[' || l_display_name ||']]>';
8483 else
8484 l_display_name := '';
8485 end if;
8486
8487 -- attrlist is empty
8488 hdrxmlPos := WF_XML.NewTag(hdrxml, hdrxmlPos, 'NAME', l_display_name, l_attrlist);
8489 hdrxmlPos := WF_XML.SkipTag(hdrxml, 'NAME', hdrxmlPos, l_occurance);
8490
8491 l_to_emailaddress := replace(l_to_emailaddress, g_newLine);
8492 l_to_emailaddress := '<![CDATA['||l_to_emailaddress||']]>';
8493
8494 -- attrlist is empty
8495 hdrxmlPos := WF_XML.NewTag(hdrxml, hdrxmlPos, 'ADDRESS', l_to_emailaddress, l_attrlist);
8496 hdrxmlPos := WF_XML.SkipTag(hdrxml, 'ADDRESS', hdrxmlPos, l_occurance);
8497
8498 hdrxmlPos := WF_XML.SkipTag(hdrxml, 'RECIPIENT', hdrxmlPos, l_occurance);
8499
8500 -- end RECIPIENTLIST tag
8501 hdrxmlPos := WF_XML.SkipTag(hdrxml, 'RECIPIENTLIST', hdrxmlPos, l_occurance);
8502 l_attrlist.DELETE;
8503
8504
8505 -- Use from_role which asked the Question or requested for more info.
8506 -- TODO : we should use Display name of that role.
8507 IF(l_from_role IS NOT NULL AND l_from_role <> '' ) then
8508 -- attrlist is empty
8509 hdrxmlPos := WF_XML.NewTag(hdrxml, hdrxmlPos, 'FROM', '', l_attrlist);
8510
8511 l_from_role := replace(l_from_role, g_newLine);
8512 hdrxmlPos := WF_XML.NewTag(hdrxml, hdrxmlPos, 'NAME', l_from_role, l_attrlist);
8513 hdrxmlPos := WF_XML.SkipTag(hdrxml, 'NAME', hdrxmlPos, l_occurance);
8514
8515 hdrxmlPos := WF_XML.SkipTag(hdrxml, 'FROM', hdrxmlPos, l_occurance);
8516
8517 end if;
8518
8519 l_attrlist.DELETE;
8520 l_subject := replace(l_subject, g_newLine);
8521 l_subject := '<![CDATA['||l_subject||']]>';
8522 hdrxmlPos := WF_XML.NewTag(hdrxml, hdrxmlPos, 'SUBJECT', l_subject, l_attrlist);
8523
8524 -- Add HEADER tag in LOB.
8525 l_pos := WF_XML.NewLOBTag(l_msg_doc, l_pos, 'HEADER', hdrxml, l_attrlist);
8526 l_pos := WF_XML.SkipLOBTag(l_msg_doc, 'HEADER', l_pos, l_occurance);
8527 l_attrlist.DELETE;
8528
8529 -- <CONTENT> start
8530 wf_xml.AddElementAttribute('content-type','multipart/mixed',l_attrlist);
8531 l_pos := wf_xml.NewLOBTag(l_msg_doc,l_pos,'CONTENT','',l_attrlist);
8532 l_attrlist.DELETE;
8533
8534 -- <BODYPART> start
8535 wf_xml.AddElementAttribute('content-type','text/plain', l_attrlist);
8536 l_pos := wf_xml.NewLOBTag(l_msg_doc,l_pos,'BODYPART', '', l_attrlist);
8537
8538
8539 l_messageidx := wf_temp_lob.getlob(g_lobtable);
8540
8541 dbms_lob.TRIM(g_lobtable(l_messageidx).temp_lob,0);
8542
8543 dbms_lob.writeappend(g_lobtable(l_messageidx).temp_lob,
8544 LENGTH(l_start_cdata), l_start_cdata);
8545
8546 dbms_lob.append(dest_lob=>g_lobtable(l_messageidx).temp_lob,
8547 src_lob=>l_text_body);
8548
8549 dbms_lob.writeappend(g_lobtable(l_messageidx).temp_lob,
8550 LENGTH(l_end_cdata),l_end_cdata);
8551
8552 -- l_attrlist content-type='text/plain' will be used same
8553 -- as for BODYPART
8554 -- -- <MESSAGE>
8555 l_pos := wf_xml.NewLOBTag(l_msg_doc,l_pos, 'MESSAGE',
8556 g_lobtable(l_messageidx).temp_lob,
8557 l_attrlist);
8558
8559 l_pos := wf_xml.SkipLOBTag(l_msg_doc,'MESSAGE',l_pos,l_occurance);
8560 l_attrlist.DELETE;
8561
8562 -- <BODYPART> end
8563 l_pos := wf_xml.SkipLOBTag(l_msg_doc,'BODYPART',l_pos,l_occurance);
8564
8565 -- TODO : << sstomar>>
8566 -- Later we will consider to send HTML body part
8567 -- commenting below code as of now.
8568
8569 -- reuse same LOB for html body
8570 -- Check if same can be re-used or not.
8571 --dbms_lob.trim(g_LOBTable(l_messageidx).temp_lob, 0);
8572
8573 --l_attrlist.DELETE;
8574
8575 -- <BODYPART> start
8576 --wf_xml.AddElementAttribute('content-type','text/html', l_attrlist);
8577 --l_pos := wf_xml.NewLOBTag(l_msg_doc,l_pos,'BODYPART', '', l_attrlist);
8578
8579 --dbms_lob.writeappend(g_lobtable(l_messageidx).temp_lob,
8580 -- LENGTH(l_start_cdata), l_start_cdata);
8581
8582 --dbms_lob.append(dest_lob=>g_lobtable(l_messageidx).temp_lob,
8583 -- src_lob=>l_html_body);
8584
8585 --dbms_lob.writeappend(g_lobtable(l_messageidx).temp_lob,
8586 -- LENGTH(l_end_cdata),l_end_cdata);
8587
8588 --l_pos := wf_xml.NewLOBTag(l_msg_doc,l_pos, 'MESSAGE',
8589 -- g_lobtable(l_messageidx).temp_lob,
8590 -- l_attrlist);
8591
8592 --l_pos := wf_xml.SkipLOBTag(l_msg_doc,'MESSAGE',l_pos,l_occurance);
8593 --l_attrlist.DELETE;
8594
8595 -- <BODYPART> end
8596 --l_pos := wf_xml.SkipLOBTag(l_msg_doc,'BODYPART',l_pos,l_occurance);
8597
8598 -- <CONTENT> end
8599 l_pos := wf_xml.skiplobtag(l_msg_doc,'CONTENT',l_pos,l_occurance);
8600 -- <NOTIFICATION> end
8601 l_pos := wf_xml.skiplobtag(l_msg_doc,'NOTIFICATION',l_pos,l_occurance);
8602 -- <NOTIFICATIONGROUP> end
8603 l_pos := wf_xml.skiplobtag(l_msg_doc,'NOTIFICATIONGROUP',l_pos,l_occurance);
8604
8605
8606 if(wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
8607 wf_log_pkg.string(wf_log_pkg.level_procedure,
8608 'wf.plsql.WF_MAIL.SendMoreInfoResponseWarning',
8609 'Initializing ' || wf_xml.wf_ntf_send_message || ' event');
8610 end if;
8611
8612 wf_event_t.initialize(l_event);
8613 l_event.event_name := wf_xml.wf_ntf_send_message;
8614
8615 -- Create an event key : make it as 0 so that this warning message
8616 -- waon't rely on wf_notification TABLE.
8617 l_event.event_key := 0;
8618 l_event.seteventdata(l_msg_doc);
8619
8620 l_agent := wf_agent_t('WF_NOTIFICATION_OUT',wf_event.local_system_name);
8621 l_event.setfromagent(l_agent);
8622
8623 l_event.addparametertolist('Q_CORRELATION_ID',l_msg_type || ':' ||l_msg_name);
8624 l_event.addparametertolist('NOTIFICATION_ID','0');
8625
8626 wf_event.send(l_event);
8627
8628 -- Release allocated temp LOBs back to pool
8629 wf_temp_lob.releaselob(g_lobtable, l_messageidx);
8630
8631 if(wf_log_pkg.level_procedure >= fnd_log.g_current_runtime_level) then
8632 wf_log_pkg.string(wf_log_pkg.level_procedure,
8633 'wf.plsql.WF_MAIL.SendMoreInfoResponseWarning', 'END');
8634 end if;
8635
8636 exception
8637 when others then
8638 --Release allocated temp LOBs back to pool
8639 if (l_orig_lang is not null and l_orig_terr is not null) then
8640 WF_Notification.SetNLSLanguage(l_orig_lang,l_orig_terr);
8641 end IF;
8642
8643 if(l_messageidx > 0) then
8644 wf_temp_lob.releaselob(g_lobtable, l_messageidx);
8645 end if;
8646
8647 raise;
8648 end SendMoreInfoResponseWarning;
8649
8650 -- SetNtfEventsSubStatus
8651 -- This procedure sets the status of seeded subscription to the event group
8652 -- oracle.apps.wf.notification.send.group. This subscription is responsible
8653 -- for notification XML message generation and presenting it to the mailer for
8654 -- e-mail dispatch. Disabling this subscription causes e-mails not to be sent.
8655 --
8656 -- ENABLED - E-mails are sent
8657 -- DISABLED - E-mails are not sent
8658 -- IN
8659 -- p_status - Subscription status (Either ENABLED or DISABLED)
8660 procedure SetNtfEventsSubStatus(p_status in varchar2)
8661 is
8662 begin
8663
8664 if (p_status in ('ENABLED', 'DISABLED')) then
8665 -- Update the notification send event group subscription
8666 -- with the specified status
8667 UPDATE wf_event_subscriptions
8668 SET status = p_status
8669 WHERE rule_data = 'MESSAGE'
8670 AND owner_name = 'Oracle Workflow'
8671 AND owner_tag = 'FND'
8672 AND event_filter_guid
8673 IN (SELECT guid
8674 FROM wf_events
8675 WHERE name = 'oracle.apps.wf.notification.send.group'
8676 AND type = 'GROUP')
8677 AND out_agent_guid
8678 IN (SELECT guid
8679 FROM wf_agents
8680 WHERE name = 'WF_NOTIFICATION_OUT'
8681 AND system_guid = hextoraw(wf_core.translate('WF_SYSTEM_GUID')))
8682 AND customization_level = 'L';
8683
8684 -- Inform BES cache manager that BES meta-data state has changed
8685 wf_bes_cache.SetMetaDataUploaded;
8686 end if;
8687
8688 end SetNtfEventsSubStatus;
8689
8690
8691 -- SetResponseDelimiters
8692 -- Sets the package level variables with one procedure call. The
8693 -- response delimiters are used to determine the free form text
8694 -- values in email notification responses.
8695 --
8696 -- IN
8697 -- open_text - Opening text/plain delimiter
8698 -- close_text - Closing text/plain delimiter
8699 -- open_html - Opening text/html delimiter
8700 -- close_html - Closing text/html delimiter
8701 procedure SetResponseDelimiters(open_text in varchar2,
8702 close_text in varchar2,
8703 open_html in varchar2,
8704 close_html in varchar2)
8705 is
8706 begin
8707 if open_text is null then
8708 wf_mail.g_open_text_delimiter := '"';
8709 else
8710 wf_mail.g_open_text_delimiter := open_text;
8711 end if;
8712
8713 if close_text is null then
8714 wf_mail.g_close_text_delimiter := '"';
8715 else
8716 wf_mail.g_close_text_delimiter := close_text;
8717 end if;
8718
8719 if open_html is null then
8720 wf_mail.g_open_html_delimiter := '''';
8721 else
8722 wf_mail.g_open_html_delimiter := open_html;
8723 end if;
8724
8725 if open_html is null then
8726 wf_mail.g_close_html_delimiter := '''';
8727 else
8728 wf_mail.g_close_html_delimiter := close_html;
8729 end if;
8730
8731 end SetResponseDelimiters;
8732
8733
8734 end WF_MAIL;