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