Odyssey
hcuFunctions.i
1 <?php
2 /*
3  * BIG NOTE: This script is intended as a replacement for cu_common_intl.i and has functions with the
4  * same name. BY ORDER OF THE KING: DO NOT INCLUDE IN THE SAME SCRIPT AS cu_common_intl.i.
5  */
6 /*
7  * Function: setLoginScript
8  * Purpose: This function will determine set the loginscript will be
9  * as well as the information for the currentscript
10  * Parameters: p_hb_env - this is a value by REFERENCE to HB_ENV value
11  *
12  * Returns: no return -- Changes made within are the necessary changes
13  */
14 
15 function setLoginScript(&$p_hb_env) {
16 
17  $loginscript = 'hcuLogin.prg';
18 
19  $lEnvSet = HCU_array_key_value('SYSENV', $p_hb_env);
20 
21  // * Determine if protocol can be http (development env) or https (production)
22  $lHttp = (HCU_array_key_value('require_encryption', $lEnvSet) == 0 && ($_SERVER['REQUEST_SCHEME'] != 'https' && HCU_array_key_value('HTTP_X_FORWARDED_PROTO', $_SERVER) != 'https') ? 'http://' : 'https://');
23 
24  $chome = HCU_array_key_value("chome", $p_hb_env);
25  $p_hb_env['fi_path'] = $lHttp . $_SERVER['HTTP_HOST'] . '/fi/' . $chome . '/';
26 
27  $loginpath = $lHttp . $_SERVER['HTTP_HOST'] . dirname($_SERVER['SCRIPT_NAME']);
28 
29  $p_hb_env['loginscript'] = "${loginpath}/${loginscript}";
30  $p_hb_env['loginpath'] = $loginpath;
31 
32  // ** Home Banking is the MAIN directory for HOMECU
33  // ie https://www6.homecu.net/hculive7 or https://www5.homecu.net/hcubin7
34  $p_hb_env['homebankingpath'] = $lHttp . $_SERVER['HTTP_HOST'] . "/" . returnBaseDirectory($_SERVER['SCRIPT_NAME']);
35 
36  // ** PARSE THE CURRENT
37  parse_str($_SERVER['QUERY_STRING'], $get_vars);
38 
39  // ** SET THIS VALUE TO THE ELEMENTS I WILL USE ON THE COMMAND LINE FOR HOME BANKING
40  // ** allow testmenu
41  $cuAllowGet = array('cu'=>'CU', 'testmenu'=>'Show Test Menu');
42 
43  $cu_query = array_intersect_key($get_vars, $cuAllowGet);
44  $p_hb_env['testmenu'] = intval(HCU_array_key_value('testmenu', $get_vars));
45  // ** ADD A & at the end so I can just add new parameters to the end
46  $p_hb_env['cuquery'] = http_build_query ($cu_query);
47 
48 }
49 
50 // Function: ReturnAddress
51 // Purpose: To record the currently requested page so we can return here after
52  /// a successful login. This should ONLY be called when cookie
53  // validation fails and we may redirect later
54 function recordCurrentAddress ($p_hb_env) {
55 
56 // Called when the cookie is missing, expired, or damaged. Sets return address
57 // to the name of the current script so cu_login knows where to go afterwards.
58 
59 
60  $url_query_string = urlencode($_SERVER['QUERY_STRING']);
61 
62  setcookie("Tx_URI",
63  "https://".$_SERVER['HTTP_HOST'] .
64  $_SERVER['PHP_SELF'] . "?" . $url_query_string,
65  0,
66  "/",
67  $p_hb_env['TicketDomain'],
68  1);
69 }
70 
71 /**
72  * Note 04-2019 "aside" element changed to nav because it's not an aside
73  * @param string $pType {menu, aside} - Do we create the 'menu' on top, or the 'aside' menu
74  * @param array $pmenuDetail - This is the array value of the item to print
75  * menu - The MAIN header array value is passed in which will include all of it's details (the parent in a sense)
76  * aside - The SPECIFIC detail link to print should be passed in (the child)
77  * @param array $phb_env - Current HB_ENV value
78  * @param bool $pactiveLink - is THIS link the active item for it's type? {true, false}
79  * true - the special class identifier should be used to highlight this menu option
80  * false - do nothing
81  *
82  * @return string - this will return the link to print on the screen
83  *
84  */
85 function buildMenuLinkOLD($pType, $pmenuDetail, $phb_env, $pactiveLink) {
86  $menuLink = "";
87 
88  // ** Create the href
89  // * href value always comes from the detail section
90  // * for menu type -- FIND the default link
91  // * for aside type -- USE what is passed in
92  if ($pType == 'menu') {
93  $useMenuDetail = $pmenuDetail['detail'][$pmenuDetail['default']];
94  } else {
95  $useMenuDetail = $pmenuDetail;
96  }
97 
98  /*
99  * SET the beginning of the link. There are issues using the relative URL
100  * IF the href starts with http, then this is already an absolute path, NO
101  * action needed
102  * IF NO http then add the homebankingpath to the beginning
103  *
104  */
105  if (substr($useMenuDetail['href'], 0, 4) != 'http') {
106 
107  $useLinkHref = $phb_env['homebankingpath'] . (substr($phb_env['homebankingpath'], -1) != '/' ? '/' : '') . $useMenuDetail['href'] . "?";
108  } else {
109  $useLinkHref = $useMenuDetail['href'] . "?";
110  }
111  // ** Do we add cuquery or extra parameters?
112  if ($useMenuDetail['hrefUrlQuery'] == 1) {
113  $useLinkHref .= $phb_env['cuquery'];
114  }
115  // * Extra parameters
116  if ($useMenuDetail['hrefExtraParam'] != '') {
117  $useLinkHref .= "&" . $useMenuDetail['hrefExtraParam'];
118  }
119  // ** If this menu option has hrefOverride set, then I need to pass this
120  // * value on the URL so I can set it later
121  if ($useMenuDetail['hrefMultiple'] != '') {
122  $useLinkHref .= "&menuUniq=" . $useMenuDetail['hrefMultiple'];
123  }
124  // ** Create the target
125  if ($useMenuDetail['target'] != '') {
126  $useLinkTarget = $useMenuDetail['target'];
127  }
128 
129  // ** Create the anchor DisplayValue
130  // * menu type should always come from the 'parent' element,
131  // * aside type should always come from the 'child' element
132  // ** NOTE: in both cases this should be the first level 'display' element
133  //
134  // * The language is important here, en_US MUST be defined for proper logic
135  // * if a specific menu item does NOT exist for an alternate language then
136  // * the DEFAULT en_US will be used
137  if ($pmenuDetail['display'][$phb_env['Flang']] != '') {
138  $useLinkDisplay = hcu_displayHtml($pmenuDetail['display'][$phb_env['Flang']]);
139  } else {
140  // ** USE default menu option
141  $useLinkDisplay = hcu_displayHtml($pmenuDetail['display']['en_US']);
142  }
143 
144  // ** create the LINK!
145  if ($pType == 'menu') {
146  $menuLink = "<a href='{$useLinkHref}' target='{$useLinkTarget}'><span class='button " . ($pactiveLink ? "item-active" : "") . "'>{$useLinkDisplay}</span></a>";
147  } else {
148  $menuLink = "<li id='" . ($pactiveLink ? "submenu-active" : "") . "'><a href='{$useLinkHref}' target='{$useLinkTarget}'>{$useLinkDisplay}</a>" . ($pactiveLink ? '<span class="arrow"></span>' : '') . "</li>";
149  }
150 
151  return $menuLink;
152 }
153 
154 /**
155  * This function is used to determine if the string that is passed in qualifies
156  * as a valid PHP serialized value
157  *
158  * @param string $val
159  * @return boolean
160  * true - The value appears to be a valid serialized string
161  * false - Something is wrong with the string
162  */
163 function hcuIsSerializedString($val){
164  if (!is_string($val)){ return false; }
165  if (trim($val) == "") { return false; }
166  if (preg_match("/^(i|s|a|o|d):(.*);/si",$val) !== false) { return true; }
167  return false;
168 }
169 
170 /**
171  *
172  * This function will change only the specified values within the Banking Ticket
173  *
174  * @param array $pHbEnv This is the HB_ENV array for the current environment
175  * @param string $cur This is the current value of the Banking 'Ticket'
176  * @param string $newset This is the string of new values to set.
177  * They are passed into the function in the syntax "key1=val1&key2=val2"
178  *
179  *
180  * @return string Returns the new Ticket value
181  */
182 function SetTicket($pHbEnv, $cur, $newset) {
183 
184  $ResetTicket = BuildSessionTicketStr($pHbEnv, $cur, $newset);
185 
186  $lEnvSet = HCU_array_key_value('SYSENV', $pHbEnv);
187  HCU_setcookie_env($lEnvSet, "Ticket", $ResetTicket, 0);
188 
189  return $ResetTicket;
190 }
191 
192 /**
193  *
194  * Create the Banking Ticket string to be used by a cookie. The parameters are
195  * expected to be passed in as name=value pairs (e.g. name1=value1&name2=value2).
196  *
197  * @param array $pHbEnv This is the HB_ENV array for the current environment
198  * @param string $currSet The current Home Banking 'Ticket' string
199  * @param string $newSet The string of new values to set
200  * They are passed into the function in the syntax "key1=val1&key2=val2"
201  *
202  * @return string Returns the new Ticket session string value
203  */
204 function BuildSessionTicketStr($pHbEnv, $currSet, $newSet) {
205 
206  $secret = HCU_array_key_value('secret', $pHbEnv);
207 
208  $cArray = array();
209  $newArray = array();
210  parse_str( urldecode($currSet), $cArray );
211  parse_str( urldecode($newSet), $newArray );
212 
213  if ( count( $newArray) > 0 ) {
214  foreach ( $newArray as $key => $value) {
215  $cArray[$key] = $value;
216  }
217  }
218 
219  $cArray['Ch'] = MD5($secret . MD5(join(':',
220  [
221  $secret,
222  $cArray['Ctime'], $cArray['Ce'], $cArray['Cu'], $cArray['Cn'], $cArray['Uid'],
223  $cArray['Clw'], urlencode(trim($cArray['Clu'])),
224  urlencode(trim($cArray['Fplog'])), urlencode(trim($cArray['Fflog'])),
225  $cArray['Ffchg'], $cArray['Ffreset'],
226  $cArray['Ffremain'], $cArray['Fmsg_tx'], $cArray['Fset'],
227  $cArray['Fset2'], $cArray['Fset3'], $cArray['Fhdays'],
228  urlencode($cArray['Ml']), trim($cArray["Ca"]), trim($cArray["platform"]), $cArray["sid"]
229  ]
230  )));
231 
232  $delim = '';
233  $newTicket = '';
234  foreach ($cArray as $key => $value) {
235  $value = urlencode($value);
236  $newTicket .="${delim}${key}=${value}";
237  $delim = '&';
238  }
239 
240  return $newTicket;
241 } // end BuildSessionTicketStr
242 
243 /**
244  *
245  * Create the base Banking Ticket string to be used by a cookie. All the values
246  * this function builds are in HB_ENV.
247  *
248  * @param array $pHbEnv This is the HB_ENV array for the current environment
249  * @param string $currSet The current Home Banking 'Ticket' string
250  * @param string $newSet The string of new values to set
251  * They are passed into the function in the syntax "key1=val1&key2=val2"
252  *
253  * @return string Returns the new Ticket session string value
254  */
255 function BuildBaseSessionTicket( $pHbEnv ) {
256 
257  $ticket = "Cu={$pHbEnv["cu"]}&Ce={$pHbEnv['Ce']}&Clw={$pHbEnv['Clw']}"
258  . "&Clu={$pHbEnv['Clu']}"
259  . "&Fplog={$pHbEnv['Fplog']}&Fflog={$pHbEnv['Fflog']}"
260  . "&Ffchg={$pHbEnv['Ffchg']}&Ffreset={$pHbEnv['Ffreset']}"
261  . "&Ffremain={$pHbEnv['Ffremain']}&Fmsg_tx={$pHbEnv['Fmsg_tx']}"
262  . "&Fset={$pHbEnv['Fset']}&Fset2={$pHbEnv['Fset2']}"
263  . "&Fhdays={$pHbEnv['Fhdays']}&Fset3={$pHbEnv['Fset3']}&Ca=";
264  // these may not exist in HB_ENV yet
265  $userName = isset( $pHbEnv["Cn"] ) ? $pHbEnv["Cn"] : "";
266  $ticket .= "&Cn=$userName";
267 
268  $userId = isset( $pHbEnv["Uid"] ) ? $pHbEnv["Uid"] : "";
269  $ticket .= "&Uid=$userId";
270 
271  $userEmail = isset( $pHbEnv["Ml"] ) ? $pHbEnv["Ml"] : "";
272  $ticket .= "&Ml=$userEmail";
273 
274  // Add the platform to the Ticket cookie. Use the name "platform" so
275  // it overwrites the HB_ENV value in scripts after login.
276  $ticket .= "&platform={$pHbEnv["platform"]}";
277 
278  // Add the sid to the Ticket cookie.
279  $ticket .= "&sid={$pHbEnv["sid"]}";
280 
281  return $ticket;
282 } // end BuildBaseSessionTicket
283 
284 /**
285  * ReturnUnconfirmedTransactions
286  *
287  * @uses return all transactions awaiting confirmation
288  * @param pDbh object database access
289  * @param pHbEnv object banking environment values
290  *
291  * @return retData array list of transactions awaiting
292  * confirmation.
293  */
294 function ReturnUnconfirmedTransactions($pDbh, $pHbEnv) {
295  $retData = array();
296  $uId = $pHbEnv["Uid"];
297  $cu = $pHbEnv['Cu'];
298 
299  // posted/create _date is only selected so the UNION
300  // will not combine multiple rows that have the same values;
301  // i.e. multiple ACHPMT or TRN.
302  $sql = "
303  SELECT
304  t.user_id AS user_id, t.approved_status, t.feature_code, t.create_date
305  FROM cu_scheduledtxn t
306  INNER JOIN {$cu}user u
307  ON u.user_id = t.user_id
308  WHERE
309  u.group_id = (SElECT group_id FROM {$cu}user where user_id = $uId)
310  AND
311  u.user_id != $uId
312  AND
313  (t.approved_status IS NULL OR t.approved_status = 0)
314  UNION
315  SELECT
316  h.posted_by AS user_id, h.approved_status, h.feature_code, h.posted_date
317  FROM {$cu}transhdr h
318  INNER JOIN {$cu}user u
319  ON u.user_id = h.posted_by
320  WHERE
321  u.group_id = (SElECT group_id FROM {$cu}user where user_id = $uId)
322  AND
323  u.user_id != $uId
324  AND
325  (h.approved_status IS NULL OR h.approved_status = 0)";
326  $sqlRs = db_query($sql, $pDbh);
327  $retData = db_fetch_all($sqlRs);
328 
329  return $retData;
330 }
331 
332  function ReturnUnreadSecureMsg ($p_dbh, $p_hb_env) {
333  $retValue = 0;
334 
335  $sql = "SELECT count(*) as UnreadMsgCount
336  FROM cuadmeco
337  WHERE cu = '{$p_hb_env['Cu']}'
338  AND user_id = '{$p_hb_env['Uid']}'
339  AND origination = 0
340  AND unread;";
341 
342  $unreadRs = db_query($sql, $p_dbh);
343  if($unreadRs) {
344  list($retValue) = db_fetch_array($unreadRs, 0);
345  }
346  return $retValue;
347  }
348 
349  /**
350  * Function: PostSecureMessage
351  * This function will get information for the secure form, build and place the file in the specified
352  * location, and send an email to the specfied address using the specified information.
353  * If no email then it won't be sent.
354  *
355  * @param array $formDataArray - holds the information as described below
356  * @param string $securePathFileName - path and file name for secure message
357  * @param string $secureFormTitle - title for the form
358  * @param array $emailData - information to create and send the notification email
359  * @param array $pHbEnv - The HB_ENV environment array
360  *
361  * $formDataArray has the following elements:
362  * class - (optional) hold the class name for the <label>
363  * label - holds the label the credit union member will see in the secure message
364  * value - hold the value for the label
365  *
366  * $emailData has the following elements
367  * target - (required) destination email address
368  * reply - address for reply
369  * subject - email subject (should have message code as part of it - eg ccpmt for Credit Card Payment)
370  * body - (required) email body
371  *
372  * RETURN VALUE
373  * retVal - 0 on success, non-zero if error
374  */
375  function PostSecureMessage( $formDataArray, $securePathFileName, $secureFormTitle, $emailData, $pHbEnv ) {
376 
377  $retVal = 0;
378 
379  try {
380  /*
381  * Create the form string
382  */
383  // ** Write the header section of the file
384  $secureFormData = <<< printblock
385 <?xml version="1.0"?><!doctype html>
386 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
387  <head>
388  <title>$secureFormTitle</title>
389  <link href="https://{$pHbEnv['cloudfrontDomainName']}/homecu/css/KendoUI/{$pHbEnv['homecuKendoVersion']}/kendo.common.min.css" rel="stylesheet">
390  <link href="https://{$pHbEnv['cloudfrontDomainName']}/homecu/css/KendoUI/{$pHbEnv['homecuKendoVersion']}/kendo.default.min.css" rel="stylesheet">
391 
392  <script type="text/javascript" src="https://{$pHbEnv['cloudfrontDomainName']}/jquery/js/jquery-1.9.1.min.js.gz"></script>
393  <script src="https://{$pHbEnv['cloudfrontDomainName']}/homecu/js/KendoUI/{$pHbEnv['homecuKendoVersion']}/kendo.web.min.js"></script>
394  </head>
395  <style>
396  .k-block {width: 500px}
397  .field-label-wrapper { margin: 0px 5px 5px 5px; padding: 0px 5px 5px 20px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; }
398  .field-label-wrapper label { display: block; padding: 10px 0 6px 4px; color: #333333; font-size:1.2em; margin-left: -10px; width: 100%; }
399  .field-label-wrapper label.note {color: red;font-weight: bold;}
400  .field-label-wrapper label.note:before {content: "NOTE: "}
401  .field-label-wrapper label.field:after {content: ":"}
402  .field-label-wrapper label hr { z-index: 0; display:inline-block; width: 100%; position:relative; top:-24px;background-color:#000000; }
403  </style>
404  <body>
405  <div class='k-content'>
406  <div class="k-block"><div class="k-header k-shadow">$secureFormTitle</div>
407 printblock;
408 
409  // ** Loop through the fields and print
410  foreach ($formDataArray as $dataIdx => $dataAttr) {
411 
412  $printLabel = ($dataAttr['label'] != '' ? "<label class='{$dataAttr['type']}'>{$dataAttr['label']}</label>" : '');
413  $secureFormData .= <<< printblock
414  <div class='field-label-wrapper'>
415  {$printLabel}
416  <div class='field-value'>{$dataAttr['value']}</div>
417  </div>
418 printblock;
419  }
420  // ** Set the ending of the file
421  $secureFormData .= <<< printblock
422  </div>
423  </div>
424  </body>
425  </html>
426 printblock;
427 
428  /*
429  * Open and Write the data to the secure form
430  */
431  $secureFormFileHdl = fopen($securePathFileName, 'w');
432  if ($secureFormFileHdl) {
433  fwrite($secureFormFileHdl, $secureFormData);
434  fclose($secureFormFileHdl);
435  } else {
436  // ** ERROR
437  throw new Exception();
438  }
439 
440  // see if caller wants an email sent
441  if ( $emailData && $emailData["target"] && $emailData["body"] ) {
442  /*
443  * SEND E-mail
444  */
445  $notify = new ErrorMail;
446  $notify->mailto = $emailData["target"];
447  $notify->replyto = $emailData["reply"];
448  $notify->subject = $emailData["subject"];
449  $notify->msgbody = $emailData["body"];
450  $notify->callingfunction = __FUNCTION__;
451  $notify->file = __FILE__;
452  $notify->SendMail();
453  }
454 
455  } catch (Exception $ex) {
456  // some error occurred
457  $retVal = 1;
458  }
459 
460 
461  return $retVal;
462  }
463 
464  /**
465  * Function: GetConfirmCode
466  * Generate a confirmation code based on the current time.
467  * Confirmation code is julian day . Seconds since midnight as 7digits,
468  * then converted to hex and formatted as 2-2-2-2 to minimize hex swearing.
469  *
470  * RETURN VALUE
471  * retVal - confirmation id
472  */
473 function GetConfirmCode() {
474  $conDate = getdate();
475  $conCode = sprintf('%08s',dechex(($conDate['yday'] + 1 .
476  sprintf('%07u',(
477  $conDate['hours'] * 3600 +
478  $conDate['minutes'] * 60 +
479  $conDate['seconds'] )))));
480 
481  $confirmId = sprintf('%s-%s-%s-%s',substr($conCode,0,2),substr($conCode,2,2),substr($conCode,4,2),substr($conCode,6,2));
482 
483  return $confirmId;
484 }
485 
486 
487  /*
488  Purpose: This function will do double duty. It will validate
489  a date that is passed in one variable such as MM/DD/YYYY
490  AND it should also be able to accept the date in pieces in
491  three separte parameters
492 */
493 function validateDate() {
494  # renamed copy of dms_checkdate out of cu_common_intl.i
495 
496  $retval = true; // START THE FUNCTION TO RETURN TRUE
497 
498  // ** FIRST -- Determine if we are assuming 3 pieces or 1 full date piece
499  if (func_num_args() == 1) {
500  $date_arg = func_get_arg(0);
501  // ** EXPECT THE DATE TO BE ONE FULL DATE in the month variable MM/DD/YYYY -- separator may be [/-.]
502  // ** BREAK THE PIECES APART
503  if (preg_match("#^([0-9]{1,2})[/-]{1}([0-9]{1,2})[/-]{1}([0-9]{2,4})$#", $date_arg, $regs)) {
504  $m_val = $regs[1];
505  $d_val = $regs[2];
506  $y_val = $regs[3];
507  } else {
508  $retval = false;
509  }
510  } elseif (func_num_args() == 3) {
511  $arg_date = func_get_args();
512  // ** Expect the date to be parsed into the 3 different parameters -- verify the pieces match and contain no string
513  if ((strval(intval($arg_date[0])) != strval($arg_date[0])) || (strval(intval($arg_date[1])) != strval($arg_date[1])) || (strval(intval($arg_date[2])) != strval($arg_date[2]))) {
514  $retval = false;
515  } else {
516  $m_val = $arg_date[0];
517  $d_val = $arg_date[1];
518  $y_val = $arg_date[2];
519  }
520  } else {
521  // ALL OTHER CASES -- RETURN FALSE
522  $retval = false;
523  }
524  // ** If the return value is true then we have the values we want, now check the date
525  if ($retval) {
526  // Seemed to pass the first exercise, now test to see if the actual checkdate is correct
527  $retval = checkdate(intval($m_val), intval($d_val), intval($y_val));
528  }
529 
530  return $retval;
531 }
532 
533 /**
534  *
535  * This function will expect a date in the pCalDate parameter and then it will convert
536  * this into a timestamp and then in to a compatible string for the JSON date object.
537  * AT THIS TIME, I believe I can simply add '000' to the end of a UNIX EPOCH for the
538  * valid JSON date value of the same day
539  *
540  * Need the timestamp returned in UTC -- To do this, I want to
541  * get the current timezone,
542  * set the timezone to UTC
543  * create the timestamp
544  * set the timezone back to current
545  *
546  * @param string $pCalDate
547  *
548  * returns string
549  *
550  */
551 function returnJsonDateValue($pCalDate) {
552 
553  // ** Get the CURRENT timezone
554  $curTZ = date_default_timezone_get();
555  // ** Set the timezone to UTC
556  date_default_timezone_set('UTC');
557  // * Get the EPOCH in UTC
558  $strTimestamp = gmdate('U', strtotime($pCalDate)) * 1000;;
559  // * Set the timezone back to what it was on entry of function
560  date_default_timezone_set($curTZ);
561 
562  // * Return the result
563  return $strTimestamp;
564 }
565 
566 /**
567  *
568  * This function will encode the packetStatus array and store in a cookie
569  *
570  * @param array $phb_env - The HB_ENV environment array
571  *
572  * @return NO RETURN VALUE
573  *
574  */
575 function savePacketStatusCookie($phb_env) {
576  $bolPacketMod = false;
577  $logger = $phb_env['SYSENV']['logger'];
578  /*
579  * 3 array elements returned from the live appliance
580  * status - The code to identify the current packet status
581  * asofdate - This is the end date of the data in the packet. a 1 is returned for bad packet
582  * reason - For errors this will contain the error information from the appliance
583  *
584  * check the status is != 0, 0 is returned for the status when the request is processed too son
585  * The problem is the too soon response will return an 'asofdate', which is the last date of the data
586  * but this is not accurate and we do NOT want to update the status in this case
587  *
588  * This function will encode the values and save the information in
589  * the packet status cookie
590  *
591  */
592 
593  /*
594  * Take a second to determine if the information has changed, if so, we notify
595  * user -- ONLY checkthe asofdate -- This will help ensure we do NOT overwrite
596  * the status and reason when the result is 'too soon to ask again'
597  */
598  $curPktStatus = decodePacketStatusCookie($phb_env);
599  if ((trim($curPktStatus['asofdate']) != trim($phb_env['packetStatus']['asofdate'])) && $phb_env['packetStatus']['status'] != '900') {
600  $bolPacketMod = true;
601  // ** ONLY save if different -- NOT found should come back as blank in curPktStatus
602  // ** Also, when creating the the cookie, add another element 'r', the real
603  // * purpose is to add a number that isn't shown anywhere in the system and is random
604  $phb_env['packetStatus']['r'] = rand(11111, 99999);
605  $encodedValue = hcu_encrypturl(json_encode($phb_env['packetStatus']), $phb_env['historyHash']);
606 
607  HCU_setcookie_env($phb_env['SYSENV'], $phb_env['livePacketStatusCookie'], $encodedValue, 0);
608 
609  }
610 
611  return $bolPacketMod;
612 }
613 
614 /**
615  *
616  * This function will retrieve the packetStatus from the packetStatus Cookie
617  * and store in the HB_ENV packetStatus element.
618  *
619  * @param array $phb_env - Passed by reference, the HB_ENV environment array.
620  * it will be directly modified if the status is found
621  *
622  * @return NO RETURN
623  */
624 function retrievePacketStatusCookie(&$phb_env) {
625 
626  $logger = $phb_env['SYSENV']['logger'];
627 
628  if (HCU_array_key_value($phb_env['livePacketStatusCookie'], $_COOKIE)) {
629 
630  $phb_env['packetStatus'] = decodePacketStatusCookie($phb_env);
631  $phb_env['lastupdate'] = $phb_env['packetStatus']['asofdate'];
632  }
633  // ** NO RETURN
634 }
635 
636 /**
637  *
638  * Purpose: this function will return the decoded packetStatus array from the
639  * packetStatus cookie. It will return an array of the form
640  * 'status'
641  * 'asofdate'
642  * 'reason'
643  *
644  * @param type $phb_env
645  *
646  * @return array
647  status - Code returned from the appliance
648  asofdate - the date returned from the appliance
649  reason - A description from appliance, normally used for errors
650 
651  */
652 function decodePacketStatusCookie($phb_env) {
653 
654  $retPktStatusAry = Array (
655  'status' => '',
656  'asofdate' => '',
657  'reason' => ''
658  );
659 
660  if (HCU_array_key_exists($phb_env['livePacketStatusCookie'], $_COOKIE)) {
661  if ($_COOKIE[$phb_env['livePacketStatusCookie']]) {
662  $cookieValue = $_COOKIE[$phb_env['livePacketStatusCookie']];
663  $statusAry = json_decode(hcu_decrypturl($cookieValue, $phb_env['historyHash']), true);
664  switch (json_last_error()) {
665  case JSON_ERROR_NONE:
666  /*
667  * SUCCESS
668  * Set the return array
669  */
670  // * Assign the values by array element
671  if (is_array($statusAry)) {
672  // ** Validate the decoded value is an array
673  if (array_key_exists('status', $statusAry) && array_key_exists('asofdate', $statusAry) && array_key_exists('reason', $statusAry)) {
674  $retPktStatusAry['status'] = substr(preg_replace('/[^0-9]/', '', $statusAry['status']), 0, 3);
675  $retPktStatusAry['asofdate'] = substr(preg_replace('/[^0-9A-Za-z:\s]/', '', $statusAry['asofdate']), 0, 30);
676  $retPktStatusAry['reason'] = substr(preg_replace('/[^0-9A-Za-z\s]/', '', $statusAry['reason']), 0, 30);
677  }
678  }
679  break;
680  }
681  }
682  }
683  return $retPktStatusAry;
684 }
685 
686 /**
687  *
688  * This function is used to UPDATE the cookie and set the current HB_ENV['Fmsg_tx']
689  * value. When calling TX_list, the function may return Fmsg_tx in the status
690  *
691  * This function is meant to evaluate the array RETURNED from TX_list, if the value
692  * is set, then it will UPDATE the cookie and SET Fmsg_tx in HB_ENV
693  *
694  * @param aray $phb_env - HB_ENV environment array
695  * @param array $pTransferListAry - This is the ARRAY that is returned from TX_list
696  *
697  * NO RETURN
698  */
699 function setFmsgTxCookie(&$phb_env, $pTransferListAry) {
700 
701  /*
702  * Process status TX_list
703  *
704  * The function TX_list can return back an extra element in [status]
705  * [Fmsg_tx]
706  * If this value is set AND the value is different than what I have in HB_ENV['Fmsg_tx']
707  * THEN
708  * Rebake the cookie with this new value, and UPDATE HB_ENV
709  */
710  if (isset($pTransferListAry['status']['Fmsg_tx']) && $phb_env['live']) {
711  if (intval($pTransferListAry['status']['Fmsg_tx']) != $phb_env['Fmsg_tx']) {
712  // We have a new value --
713  // ** SET COOKIE
714  SetTicket($phb_env, $_COOKIE['Ticket'],"Fmsg_tx=" . intval($pTransferListAry['status']['Fmsg_tx']));
715  // ** SET HB_ENV
716  $phb_env['Fmsg_tx'] = intval($pTransferListAry['status']['Fmsg_tx']);
717  }
718  }
719 
720 }
721 
722 /**
723  *
724  * check_alias_format
725  *
726  * This function will check the format of the alias to see if it meets the
727  * criteria
728  *
729  * @param string $p_useralias
730  * @return boolean {True, False} Did the alias PASS verification
731  */
732 function check_alias_format($p_useralias) {
733  $pass_val = false;
734  // The expression checks for starting with an alpha
735  // followed by anything except the disallowed bad guys
736  if (preg_match("/^[a-zA-Z][^\\`,\"'\+\&\s;]*$/", $p_useralias) && strlen($p_useralias) > 5) {
737  $pass_val = true;
738  } else {
739  $pass_val = false;
740  }
741  return $pass_val;
742 }
743 
744 /**
745  *
746  * hcu_array_key_exists
747  *
748  * This function will check if a key exists in an array. BUT first it makes sure
749  * the Haystack is a valid array. If it is not, then the function will fail
750  *
751  * Returns: true - the needle exists in the haystack
752  * false - the haystack was NOT an array, or the key does not exist
753  *
754  * @param string $pNeedleKey
755  * @param array $pAryHaystack
756  *
757  * @return boolean
758  *
759  */
760 /**
761  * 2/1 mws Deprecated -- moved to hcuCommon.i
762 
763 function hcu_array_key_exists($pNeedleKey, $pAryHaystack) {
764  $retVal = false; // ** Assume, it is NOT found
765 
766  if (is_array($pAryHaystack)) {
767  $retVal = array_key_exists($pNeedleKey, $pAryHaystack);
768  }
769 
770 
771  return $retVal;
772 }
773 */
774 function validateEmail($email_addr) {
775  # renamed copy of check_email out of cu_common_intl.i
776  $pass_val = false;
777  // Check the email for a qualified address
778  // The first expression checks for double instances of @'s and .'s and other hard to express errors
779  // The second expression checks for the common email syntax XYZ@host.gov -- the value host may be broken down with periods
780  if (
781  (!preg_match("/(@.*@)|(\.\.)|(@\.)|(\.@)|(^\.)/", $email_addr))
782  &&
783  (preg_match("/^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/", $email_addr))
784  ) {
785  $pass_val = true;
786  } else {
787  $pass_val = false;
788  }
789  return $pass_val;
790 }
791 
792 /**
793  *
794  * Build up the payload and target for apps to call for if the menu item is
795  * "Open in a new window".
796  *
797  * @param array $pHBEnv - HB_ENV environment array
798  * @param array $pMenuID - This is the ARRAY that is returned from TX_list
799  * @param string $pCurrentTicketCookie - The current ticket cookie string
800  *
801  * @return string with complete url target and parameters
802  */
803 function GetLandingMenuTarget( $pHBEnv, $pMenuID, $pCurrentTicketCookie ) {
804  $target = "";
805 
806  try {
807  // get the menu entry
808  if ( $pMenuID > 0 ) {
809  $menuInfo = FetchFeatureMenu( $pHBEnv["dbh"], $pHBEnv["Cu"] );
810  if ( $menuInfo["code"] != "000" ) {
811  throw new Exception("Error Reading Menu", 1);
812  }
813 
814  // get the menu entry
815  $menuEntry = array();
816  for ( $i = 0; $i < count( $menuInfo["data"] ); $i++ ) {
817  if ( $menuInfo["data"][$i]["MenuItemId"] == $pMenuID ) {
818  $menuEntry = $menuInfo["data"][$i];
819  break;
820  }
821  }
822 
823  if ( !count( $menuEntry ) ) {
824  throw new Exception("Unable to find menu entry", 2);
825  }
826 
827  // get what is needed to build up the parameter list
828  // build this up as GET url parameters
829  $params = "";
830  if ( $menuEntry["details_hrefUrlQuery"] === 1 ) {
831  $params .= ( strlen( $params ) > 0 ) ? "&" : "";
832 
833  $params .= "cu=" . $pHBEnv['Cu'];
834  }
835 
836  if ( strlen( $menuEntry["details_hrefExtraParam"] ) > 0 ) {
837  $params .= ( strlen( $params ) > 0 ) ? "&" : "";
838 
839  $params .= $menuEntry["details_hrefExtraParam"];
840  }
841 
842  // set all the cookies
843  $cookies = array( "Ticket" => $pCurrentTicketCookie );
844 
845  // build up the parts
846  // NOTE: the cookie is already urlencoded but the parameters will need to be urlencoded
847  $payload = array( "url" => $menuEntry["details_href"],
848  "parameters" => urlencode( $params ),
849  "cookies" => $cookies
850  );
851 
852  $payloadJSON = HCU_JsonEncode( $payload );
853 
854  // encrypt the string
855  $payloadKey = GetPayloadEncryptionKey(32);
856 
857  $payloadEncrypted = EncryptPayloadData( $payloadJSON, $payloadKey );
858 
859  $payloadString = "&payload=$payloadEncrypted";
860 
861  } else {
862  $payloadString = "";
863  }
864 
865  // Set the "cu=" because the web landing page expects it. Return the target as one
866  // complete string
867  $target = $pHBEnv["homebankingpath"] . "/webLanding.prg?cu=" . $pHBEnv["Cu"] . $payloadString;
868  } catch( Exception $e ) {
869  // don't do anything since the default result will indicate an error without leaking info
870  }
871 
872  return $target;
873 } // end GetLandingMenuTarget
874 
875 /**
876  *
877  * Build up the payload and target for apps to call for if the menu item is
878  * "Open in a new window".
879  *
880  * @param array $pHBEnv - HB_ENV environment array
881  * @param array $pMenuID - This is the ARRAY that is returned from TX_list
882  * @param string $pCurrentTicketCookie - The current ticket cookie string
883  *
884  * @return string with complete url target and parameters
885  */
886 function GetLandingURL( $pHBEnv, $pURL, $pCurrentTicketCookie ) {
887  $target = "";
888 
889  try {
890  if ( !empty($pURL) ) {
891 
892  // break the URL into component pieces
893  $pURL = urldecode($pURL);
894  $urlparts = parse_url($pURL);
895  if ( !is_array($urlparts) || !count( $urlparts ) ) {
896  throw new Exception("Invalid URL", 1);
897  }
898  if ( !HCU_array_key_value('scheme', $urlparts) ||
899  !HCU_array_key_value('host', $urlparts) ||
900  !HCU_array_key_value('path', $urlparts) ) {
901  throw new Exception("Invalid URL", 1);
902  }
903 
904  $url = $urlparts['scheme'] . "://" . $urlparts['host'];
905  if (HCU_array_key_value('port', $urlparts) ) {
906  $url .= ":{$urlparts['port']}";
907  }
908  $url .= $urlparts['path'];
909 
910  $params = HCU_array_key_value('query', $urlparts);
911  // set all the cookies
912  $cookies = array( "Ticket" => $pCurrentTicketCookie );
913 
914  // build up the parts
915  // NOTE: the cookie is already urlencoded but the parameters will need to be urlencoded
916  $payload = array( "url" => $url,
917  "parameters" => urlencode( $params ),
918  "cookies" => $cookies
919  );
920 
921  $payloadJSON = HCU_JsonEncode( $payload );
922 
923  // encrypt the string
924  $payloadKey = GetPayloadEncryptionKey(32);
925 
926  $payloadEncrypted = EncryptPayloadData( $payloadJSON, $payloadKey );
927 
928  $payloadString = "&payload=$payloadEncrypted";
929 
930  } else {
931  $payloadString = "";
932  }
933 
934  // Set the "cu=" because the web landing page expects it. Return the target as one
935  // complete string
936  $target = $pHBEnv["homebankingpath"] . "/webLanding.prg?cu=" . $pHBEnv["Cu"] . $payloadString;
937  } catch( Exception $e ) {
938  // don't do anything since the default result will indicate an error without leaking info
939  }
940 
941  return $target;
942 } // end GetLandingURL
943 
944 /**
945  *
946  * Return the information used to build the message and links for user profile
947  * updates. This is callable by browswer-based and apps, so don't include any
948  * visual formatting. For the browswer-based we want a fully qualified path url;
949  * for apps just the script name.
950  *
951  * @param array $pHBEnv - HB_ENV environment array
952  *
953  * @return JSON string with sections for email, password (optional), and security (optional)
954  */
955 function GetUserProfileUpdates( $pHBEnv ) {
956  // some globals
957  global $MEM_FORCE_RESET;
958 
959  $returnInfo = array();
960 
961  // get a pointer to the dictionary
962  $MC = $pHBEnv["MC"];
963 
964  // check if the password needs updating
965  if ( HCU_array_key_exists("Ffchg", $pHBEnv) && $pHBEnv['Ffchg'] == 'Y' ) {
966  if ( $pHBEnv['Ffremain'] > 1 ) {
967  $expireMessage = $MC->combo_msg("Login Expiring", HCU_DISPLAY_AS_HTML, "#REMAIN#", $pHBEnv['Ffremain']);
968  $icon = "exclamation";
969  $level = "warning";
970  } else {
971  $expireMessage = $MC->combo_msg("Login Expired");
972  $icon = "exclamation-triangle";
973  $level = "error";
974  }
975 
976  $url = $pHBEnv["platform"] == "ADA" || $pHBEnv["platform"] == "APP" ? "hcuProfilePwd.prg" : $pHBEnv['loginpath'] . "/hcuProfilePwd.prg?" . $pHBEnv['cuquery'];
977 
978  $returnInfo["password"] = array( "title" => $MC->msg("Important"),
979  "message" => $expireMessage,
980  "icon" => $icon,
981  "level" => $level,
982  "link" => $MC->msg("Update Now"),
983  "url" => $url
984  );
985  }
986 
987  // check if the creds needs updating
988  if ( HCU_array_key_exists("Ffreset", $pHBEnv) && (($pHBEnv['Ffreset'] & $MEM_FORCE_RESET) > 0) ) {
989  if ( $pHBEnv['Ffremain'] > 1 ) {
990  $expireMessage = $MC->combo_msg("Challenge Update", HCU_DISPLAY_AS_HTML, "#REMAIN#", $pHBEnv['Ffremain']);
991  $icon = "exclamation";
992  $level = "warning";
993  } else {
994  $expireMessage = $MC->combo_msg("Challenge Expired");
995  $icon = "exclamation-triangle";
996  $level = "error";
997  }
998 
999  $url = $pHBEnv["platform"] == "ADA" || $pHBEnv["platform"] == "APP" ? "hcuProfileSecurity.prg" : $pHBEnv['loginpath'] . "/hcuProfileSecurity.prg?" . $pHBEnv['cuquery'];
1000 
1001  $returnInfo["security"] = array( "title" => $MC->msg("Important"),
1002  "message" => $expireMessage,
1003  "icon" => $icon,
1004  "level" => $level,
1005  "link" => $MC->msg("Update Now"),
1006  "url" => $url
1007  );
1008  }
1009 
1010  // either show the email or the update email
1011  if ( HCU_array_key_exists("Fmsg_tx", $pHBEnv) && (($pHBEnv['Fmsg_tx'] & GetMsgTxValue('MSGTX_FORCE_EM')) !== 0) ) {
1012  $emailTitle = $MC->msg("Bad Email Flag");
1013  $icon = "exclamation-triangle";
1014  $level = "warning";
1015  } else {
1016  $emailTitle = $MC->msg("Current email Part 1");
1017  $icon = "envelope";
1018  $level = "info";
1019  }
1020 
1021  $url = $pHBEnv["platform"] == "ADA" || $pHBEnv["platform"] == "APP" ? "hcuProfileEmail.prg" : $pHBEnv['loginpath'] . "/hcuProfileEmail.prg?" . $pHBEnv['cuquery'];
1022 
1023  $returnInfo["email"] = array( "title" => $emailTitle,
1024  "message" => HCU_array_key_exists("Ml", $pHBEnv) ? $pHBEnv['Ml'] : "",
1025  "icon" => $icon,
1026  "level" => $level,
1027  "link" => $MC->msg("Update Now"),
1028  "url" => $url
1029  );
1030 
1031  // make a JSON string
1032  $returnString = HCU_JsonEncode( $returnInfo );
1033 
1034  return $returnString;
1035 } // end GetUserProfileUpdates
1036 
1037 /**
1038  * #2647 Design JSON for Compass Menus to use. Composes a JSON string for digestion
1039  * by apps or web apps for the upper right menu represented by the "quick menu"
1040  * in the web app. Clients/consumers decide presentation.
1041  * https://docs.google.com/document/d/1I4f_uFYx03ZrZfl3YRhnEAjNG3XK-20B9Bjoy42lGMk
1042  * @param array $HB_ENV
1043  * @param object $dbh
1044  * @return string (JSON)
1045  *
1046  { "logout":{
1047  "display":"string", // dictionary entry
1048  "icon":"string",
1049  "action":"exit"
1050  },
1051  "activity":{
1052  "display":"string", // dictionary entry
1053  "icon":"string",
1054  "count":"number",
1055  "menuid":"number",
1056  "script":"script name",
1057  "action":"menu"
1058  },
1059  "messages":{
1060  "display":"string", // name from menu (monitor->banking menu)
1061  "icon":"string",
1062  "count":"number",
1063  "menuid":"number",
1064  "script":"script name",
1065  "action":"menu"
1066  },
1067  "status": {
1068  "display":"string", // dictionary entry
1069  "icon":"string",
1070  "count":"number",
1071  "endpoint":"url", // this url will return the formatted web content to display
1072  "action":"popup"
1073  },
1074  "user": {
1075  "display":"string", // dictionary entry
1076  "icon":"string",
1077  "count":"number",
1078  "action":"popup",
1079  "password": {
1080  "title": "string",
1081  "message": "string",
1082  "icon": "string",
1083  "level": "string",
1084  "link": "string",
1085  "script":"script name",
1086  "menuid":"number",
1087  "action":"menu"
1088  },
1089  "email": {
1090  "title": "string",
1091  "message": "string",
1092  "icon": "string",
1093  "level": "string",
1094  "link": "string",
1095  "script":"script name",
1096  "menuid":"number",
1097  "action":"menu"
1098  },
1099  "security": {
1100  "title": "string",
1101  "message": "string",
1102  "icon": "string",
1103  "level": "string",
1104  "link": "string",
1105  "script":"script name",
1106  "menuid":"number",
1107  "action":"menu"
1108  }
1109  }
1110 }
1111  */
1112 function CompassMenuJson($HB_ENV, $dbh) {
1113 
1114  $menu = [];
1115  $items = ['logout', 'activity', 'messages', 'status', 'user'];
1116  $menu_list = CompassGetBankingMenu($HB_ENV, $dbh);
1117 
1118  foreach ($items as $item) {
1119 
1120  if (! CompassValidMenuItem($item, $HB_ENV, $dbh)) {
1121  continue;
1122  }
1123 
1124  $node = CompassMenuItem($item, $HB_ENV, $dbh, $menu_list);
1125  if ($item) {
1126  $menu[$item] = $node;
1127  }
1128  }
1129 
1130  return HCU_JsonEncode($menu);
1131 }
1132 
1133 /**
1134  * Get the banking menu configured in monitor ONCE as it is referred to for menu ID's and
1135  * titles throughout. We are doing an include here as it is only needed **here**, and
1136  * shouldn't be carried around by the other functions in this file.
1137  * @param array $HB_ENV
1138  * @param object $dbh
1139  * @return array
1140  */
1141 function CompassGetBankingMenu($HB_ENV, $dbh) {
1142 
1143  require_once('sFeatureMnu.i');
1144  return FetchFeatureMenu($dbh, $HB_ENV['cu']);
1145 }
1146 
1147 /**
1148  * Don't show these items if they are not enabled.
1149  * @param string $item
1150  * @param array $HB_ENV
1151  * @param object $dbh
1152  * @return bool
1153  */
1154 function CompassValidMenuItem($item, $HB_ENV, $dbh) {
1155 
1156  if ($item === 'messages') {
1157  return CompassValidateSecureMessages($HB_ENV);
1158  }
1159 
1160  if ($item == 'activity') {
1161  return CompassValidateUserMenu($HB_ENV, $dbh);
1162  }
1163 
1164  return true;
1165 }
1166 
1167 /**
1168  * Validate secure messages are enabled.
1169  * @param array $HB_ENV
1170  * @return bool
1171  */
1172 function CompassValidateSecureMessages($HB_ENV) {
1173 
1174  if (
1175  ($HB_ENV['Fset2'] & GetFlagsetValue("CU2_ALLOWMESSAGE")) !=
1176  GetFlagsetValue("CU2_ALLOWMESSAGE")
1177  ) {
1178  return false;
1179  }
1180 
1181  return true;
1182 }
1183 
1184 /**
1185  * Validate transfers are enabled. This is all this menu node is for, AT's are account transfers.
1186  * @param object $dbh
1187  * @param array $HB_ENV
1188  * @return bool
1189  */
1190 function CompassValidateUserMenu($HB_ENV, $dbh) {
1191 
1192  $tx_types = Get_HaveTrans($dbh,$HB_ENV);
1193  return in_array('AT', array_keys($tx_types));
1194 }
1195 
1196 /**
1197  * Call appropriate function to output menu item by key. This is loosely constructed after
1198  * the Mediator or Strategy pattern: give me the item name and I will return the
1199  * appropriate chunk of data for the node.
1200  * @param string $item
1201  * @param array $HB_ENV
1202  * @param object $dbh
1203  * @param array $menu_list, array of items from the monitor banking menu
1204  * @return array|null
1205  */
1206 function CompassMenuItem($item, $HB_ENV, $dbh, $menu_list)
1207 {
1208  switch ($item) {
1209  case 'logout':
1210  return CompassLogout($HB_ENV, $menu_list);
1211  case 'activity':
1212  return CompassActivity($HB_ENV, $dbh, $menu_list);
1213  case 'messages':
1214  return CompassMessages($HB_ENV, $dbh, $menu_list);
1215  case 'status':
1216  return CompassStatus($HB_ENV, $menu_list);
1217  case 'user':
1218  return CompassUser($HB_ENV, $menu_list);
1219  default:
1220  return null;
1221  }
1222 }
1223 
1224 /**
1225  * Helper for CompassMenuJson(), generate the logout node.
1226  * @param $HB_ENV
1227  * @param array $menu_list, array of banking items from monitor banking menu
1228  * @return array
1229  */
1230 function CompassLogout($HB_ENV, $menu_list) {
1231 
1232  list (, $title) = CompassGetMenuIdAndTitle($HB_ENV, $menu_list, 'hcuLogout.prg', 'Sign Out');
1233 
1234  return [
1235  'display' => $title,
1236  'icon' => 'power-off',
1237  'action' => 'exit',
1238  // Useless to web front end without, ignore if not needed
1239  'script' => 'hcuLogout.prg'
1240  ];
1241 }
1242 
1243 /**
1244  * Used by all Compass functions to set title and menu item ID. Returning an array so we only
1245  * walk through this large array once for each menu item. To get id and title individually
1246  * would require walking this large array twice.
1247  * @param array $HB_ENV
1248  * @param array $menu_list, array of banking menu items from monitor
1249  * @param string $script, the closest we get to a unique identifier for monitor banking menu
1250  * @param string $default
1251  * @param bool $banking_menu - if true = get from Monitor->Banking Menu, false = dictionary entry
1252  * @return array
1253  */
1254 function CompassGetMenuIdAndTitle(
1255  $HB_ENV,
1256  $menu_list,
1257  $script = 'hcuAccounts.prg',
1258  $default = 'Menu Item',
1259  $banking_menu = false
1260  ) {
1261 
1262  $lang = ($HB_ENV['MC']->lang)?? ($HB_ENV['Flang'])?? 'en_US';
1263 
1264  if ($banking_menu) {
1265  return CompassBankingMenuTitle($menu_list, $script, $lang, $default);
1266  }
1267 
1268  if (isset($HB_ENV['MC'])) {
1269 
1270  $title = $HB_ENV['MC']->msg($default, HCU_DISPLAY_AS_HTML);
1271 
1272  if (empty($title)) {
1273  return [0, $default];
1274  }
1275 
1276  return [0,$title];
1277  }
1278 
1279  return [0, $default];
1280 }
1281 
1282 /**
1283  * A bit of fuzzy logic: there is no unique identifier in cu_featuremenu that is immutable
1284  * either by admin or by CU ID. The closest we have is a match on script (href) and
1285  * possibly extra params. In the context of the compass menu, this will work for
1286  * now, but the possibility exists that future additions to the compass menu
1287  * may break it.
1288  * @param array $menu_list
1289  * @param string $script
1290  * @param string $lang
1291  * @param string $default (always overwritten; this placeholder alerts us to a problem
1292  * without interruption of service)
1293  * @return array
1294  */
1295 function CompassBankingMenuTitle($menu_list, $script, $lang = 'en_US', $default = 'Menu Item') {
1296 
1297  if (! isset($menu_list['data'])) {
1298  return [0, $default];
1299  }
1300 
1301  foreach ($menu_list['data'] as $menu_arr) {
1302  // @TODO: There is a typo in the DB JSON: for SCRUBCU 'Secure Message' instead of 'Secure Messages'
1303  // @TODO The fallout is that the Compass menu will now read singular and there will be no value
1304  // @TODO for Polish.
1305  $arr = [
1306  'en_US' => 'details_display_en_US',
1307  'es_US' => 'details_display_es_US',
1308  'pl_US' => 'details_display_pl_US'
1309  ];
1310 
1311  if ($menu_arr['details_href'] == $script) {
1312  return [$menu_arr['MenuItemId'], $menu_arr[$arr[$lang]]];
1313  }
1314  }
1315 
1316  return [0, $default];
1317 }
1318 
1319 /**
1320  * Helper for CompassMenuJson(), compose the user activity node.
1321  * @param array $HB_ENV
1322  * @param $dbh, database object
1323  * @param array $menu_list, monitor banking menu list.
1324  * @return array
1325  */
1326 function CompassActivity($HB_ENV, $dbh, $menu_list) {
1327 
1328  list ($menu_id, $title) = CompassGetMenuIdAndTitle($HB_ENV, $menu_list, 'hcuUserActivity.prg', 'User Activity', true);
1329  return [
1330  'display' => $title,
1331  'icon' => 'bell',
1332  'count' => CompassCountUserActivity($HB_ENV, $dbh),
1333  'menuid' => $menu_id,
1334  'script' => 'hcuUserActivity.prg',
1335  'action' => 'menu'
1336  ];
1337 }
1338 
1339 /**
1340  * Helper for CompassMenuJson(), count the relevant items for user activity.
1341  * Note that "count" should translate to "+9" in GUI if more than 8.
1342  * @param array $HB_ENV
1343  * @param $dbh, database object
1344  * @return int
1345  */
1346 function CompassCountUserActivity($HB_ENV, $dbh)
1347 {
1348  $count = 0;
1349  $ucTransactions = ReturnUnconfirmedTransactions($dbh, $HB_ENV);
1350 
1351  if (is_array($ucTransactions)) {
1352  foreach ($ucTransactions as $key => $value) {
1353 
1354  $canConfirm = Perm_AccessRights($dbh, $HB_ENV, ["feature" => $value['feature_code']]);
1355 
1356  if ($canConfirm['confirm']) {
1357  $count++;
1358  }
1359  }
1360  }
1361 
1362  return $count;
1363 }
1364 
1365 /**
1366  * Helper for CompassMenuJson(), secure messages. Note that "count" should translate
1367  * to "+9" in the GUI if more than 8.
1368  * @param array $HB_ENV
1369  * @param $dbh, database object
1370  * @param array $menu_list, array of banking items from monitor banking menu
1371  * @return array
1372  */
1373 function CompassMessages($HB_ENV, $dbh, $menu_list) {
1374 
1375  list ($menu_id, $title) = CompassGetMenuIdAndTitle($HB_ENV, $menu_list, 'hcuSecureMail.prg', 'Secure Messages', true);
1376 
1377  return [
1378  'display' => $title,
1379  'icon' => 'comments',
1380  'count' => ReturnUnreadSecureMsg($dbh, $HB_ENV),
1381  'menuid' => $menu_id,
1382  'script' => 'hcuSecureMail.prg',
1383  'action' => 'menu'
1384  ];
1385 }
1386 
1387 /**
1388  * Helper for CompassMenuJson(), compose user status node.
1389  * @param array $HB_ENV
1390  * @param array $menu_list, array of banking items from monitor banking menu
1391  * @return array
1392  */
1393 function CompassStatus($HB_ENV, $menu_list) {
1394 
1395  list ($menu_id, $title) = CompassGetMenuIdAndTitle($HB_ENV, $menu_list, 'hcuAccountStatus.prg', 'Login Status');
1396 
1397  $stat_arr = [
1398  'display' => $title,
1399  'icon' => 'tasks',
1400  'count' => 0,
1401  'endpoint' => "{$HB_ENV['homebankingpath']}/hcuAccountStatus.prg?{$HB_ENV['cuquery']}",
1402  'action' => 'popup'
1403  ];
1404 
1405  // These are not used by the mobile app, but are useFUL for the web render. They are
1406  // also used to update the parent status count.
1407  $failed = CompassLastFailedLogin($HB_ENV, $menu_list);
1408  $prior = CompassPriorLogin($HB_ENV, $menu_list);
1409  $sys = CompassSystemStatus($HB_ENV, $menu_list);
1410 
1411  if ($prior) {
1412  $stat_arr['prior'] = $prior;
1413  }
1414 
1415  if ($failed) {
1416  $stat_arr['fail'] = $failed;
1417  }
1418 
1419  $stat_arr['system'] = $sys;
1420 
1421  // Update count after we've compiled the child arrays.
1422  $stat_arr['count'] = CompassCountWarnings($stat_arr);
1423 
1424  return $stat_arr;
1425 }
1426 
1427 /**
1428  * Helper for CompassStatus(), compose last failed login node.
1429  * @param array $HB_ENV
1430  * @param array $menu_list
1431  * @return array|null
1432  */
1433 function CompassLastFailedLogin($HB_ENV, $menu_list) {
1434 
1435  list ($menu_id, $title) = CompassGetMenuIdAndTitle($HB_ENV, $menu_list, '', 'Failed Login');
1436 
1437  if (isset($HB_ENV['Fflog']) && ! empty($HB_ENV['Fflog'])) {
1438 
1439  $log_level = (isFailedExceedsPrior($HB_ENV))? 'error' : 'info';
1440 
1441  return [
1442  'title' => $title,
1443  'date' => date("D M d, Y h:ia", strtotime($HB_ENV['Fflog'])),
1444  'level' => $log_level
1445  ];
1446  }
1447 
1448  return null;
1449 }
1450 
1451 /**
1452  * Helper for CompassLastFailedLogin(). If failed login exceeds previous successful login,
1453  * used to modify log level.
1454  * @param array $HB_ENV
1455  * @return bool
1456  */
1457 function isFailedExceedsPrior($HB_ENV) {
1458 
1459  if (strtotime($HB_ENV['Fflog']) > strtotime($HB_ENV['Fplog'])) {
1460  return true;
1461  }
1462 
1463  return false;
1464 }
1465 
1466 /**
1467  * Helper for CompassStatus(), set prior successful login node.
1468  * @param array $HB_ENV
1469  * @param array $menu_list
1470  * @return array|null
1471  */
1472 function CompassPriorLogin($HB_ENV, $menu_list) {
1473 
1474  list ($menu_id, $title) = CompassGetMenuIdAndTitle($HB_ENV, $menu_list, '', 'Last Login');
1475 
1476  if (isset($HB_ENV['Fplog']) && ! empty($HB_ENV['Fplog'])) {
1477  return [
1478  'title' => $title,
1479  'date' => date("D M d, Y h:ia", strtotime($HB_ENV['Fplog'])),
1480  'level' => 'info'
1481  ];
1482  }
1483 
1484  return null;
1485 }
1486 
1487 /**
1488  * Helper for CompassStatus(), compose current user status node.
1489  * @param array $HB_ENV
1490  * @param array $menu_list
1491  * @return array
1492  */
1493 function CompassSystemStatus($HB_ENV, $menu_list) {
1494 
1495  list ($sys_msg, $level) = DisplayLastDataMsg($HB_ENV);
1496  list (, $title) = CompassGetMenuIdAndTitle($HB_ENV, $menu_list, '', 'Account Status as of');
1497  return [
1498  'title' => $title,
1499  'date' => $sys_msg,
1500  'level' => $level
1501  ];
1502 }
1503 
1504 /**
1505  * Nicked from hcuPreContent, display status message. Generally this will just
1506  * be a date.
1507  * @param array $HB_ENV
1508  * @return array
1509  */
1510 function DisplayLastDataMsg($HB_ENV) {
1511 
1512  $level = 'info';
1513  $infoDataNotify = GetInfoDataNotify($HB_ENV);
1514 
1515  if ($infoDataNotify) {
1516  $level = 'error';
1517 
1518  if ($HB_ENV['packetStatus']['status'] == '999') {
1519 
1520  $msg =
1521  <<< DATAMSG
1522  {$HB_ENV['MC']->msg('Unable to load')}:
1523  <!--<br/>
1524  {$HB_ENV['MC']->msg('Credit Union responded')}:
1525  {$HB_ENV['packetStatus']['reason']} ({$HB_ENV['packetStatus']['status']})-->
1526  <br>
1527  {$HB_ENV['MC']->msg('Please try again later')}
1528 DATAMSG;
1529  } else {
1530  $msg = $HB_ENV['MC']->msg('Credit Union not responding');
1531  }
1532  } else {
1533  $msg = isset($HB_ENV['lastupdate']) ?date("D M d, Y h:ia", strtotime($HB_ENV['lastupdate'])) : null;
1534  }
1535 
1536  return [$msg, $level];
1537 }
1538 
1539 /**
1540  * Nicked from hcuPreContent, because there is no function for it.
1541  * @param array $HB_ENV
1542  * @return bool
1543  */
1544 function GetInfoDataNotify($HB_ENV) {
1545 
1546  if ($HB_ENV['live']) {
1547  $curPacketStatusAry = HCU_array_key_value('packetStatus', $HB_ENV);
1548  if (in_array(HCU_array_key_value('status', $curPacketStatusAry), ['999'])) {
1549  return true;
1550  }
1551  }
1552 
1553  return false;
1554 }
1555 
1556 /**
1557  * Use GetUserProfileUpdates() to get items for the user node of the JSON.
1558  * @param $HB_ENV
1559  * @param array $menu_list, array of banking items from monitor banking menu
1560  * @return array
1561  */
1562 function CompassUser($HB_ENV, $menu_list) {
1563 
1564  // Default URL for user profile is empty in DB, but we are using dictionary here.
1565  list ($menu_id, $utitle) = CompassGetMenuIdAndTitle($HB_ENV, $menu_list, '', 'User Info');
1566  $user_data = HCU_JsonDecode(GetUserProfileUpdates($HB_ENV));
1567 
1568  $nodes = [
1569  'password' => 'hcuProfilePwd.prg',
1570  'security' => 'hcuProfileSecurity.prg',
1571  'email' => 'hcuProfileEmail.prg',
1572  ];
1573 
1574  $user_arr = [
1575  'display' => $utitle,
1576  'icon' => 'user',
1577  'count' => CompassCountWarnings($user_data),
1578  'action' => 'popup'
1579  ];
1580 
1581  foreach ($nodes as $node => $script) {
1582 
1583  if (isset($user_data[$node])) {
1584  $user_arr[$node] = CompassUserSubItems($HB_ENV, $menu_list, $script, $node, $user_data);
1585  }
1586  }
1587 
1588  return $user_arr;
1589 }
1590 
1591 /**
1592  * Helper for CompassUser(), compile the child array members for the user node.
1593  * @param array $HB_ENV
1594  * @param array $menu_list
1595  * @param string $script
1596  * @param string $node password|email|security
1597  * @param array $user_data
1598  * @return array
1599  */
1600 function CompassUserSubItems($HB_ENV, $menu_list, $script, $node, $user_data) {
1601 
1602  // Spec does not indicate using banking menu for title, but uses ID.
1603  // Leaving title from GetUserProfileUpdates(). To overwrite simply
1604  // add the line $user_arr['title'] = $title
1605  list ($menu_id, $title) = CompassGetMenuIdAndTitle(
1606  $HB_ENV,
1607  $menu_list,
1608  $script,
1609  ($user_data['email']['title'])?? null,
1610  true
1611  );
1612 
1613  // Don't need with scriptname in place
1614  unset($user_data['url']);
1615 
1616  $user_arr = $user_data[$node];
1617  $user_arr['script'] = $script;
1618  $user_arr['menuid'] = $menu_id;
1619  $user_arr['action'] = 'menu';
1620 
1621  return $user_arr;
1622 }
1623 
1624 /**
1625  * Helper for Compass[x] functions, count warning messages to save to array. Used to
1626  * display the "badge" in the GUI (with count)
1627  * @param $data
1628  * @return int
1629  */
1630 function CompassCountWarnings($data) {
1631 
1632  $count = 0;
1633 
1634  foreach ($data as $arr) {
1635  if (IsCompassErrorWarning($arr)) {
1636  $count++;
1637  }
1638  }
1639 
1640  return $count;
1641 }
1642 
1643 /**
1644  * Check the level array member, if there is one, for warning or error. Used to increment
1645  * the count of notices for each node to display the "badge" in the GUI (with count)
1646  * @param array $arr
1647  * @return bool
1648  */
1649 function IsCompassErrorWarning($arr = [])
1650 {
1651  return
1652  is_array($arr) &&
1653  isset($arr['level']) &&
1654  ! empty($arr['level']) &&
1655  in_array($arr['level'], ['warning', 'error']);
1656 }
1657 
SendMail()
Definition: errormail.i:111