utils.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import log from "@converse/headless/log";
  2. import { _converse, api, converse } from "../../index.js";
  3. import { initStorage } from '@converse/headless/utils/storage.js';
  4. import { shouldClearCache } from '@converse/headless/utils/core.js';
  5. const { Strophe, $iq, u } = converse.env;
  6. async function onVCardData (jid, iq) {
  7. const vcard = iq.querySelector('vCard');
  8. let result = {};
  9. if (vcard !== null) {
  10. result = {
  11. 'stanza': iq,
  12. 'fullname': vcard.querySelector('FN')?.textContent,
  13. 'nickname': vcard.querySelector('NICKNAME')?.textContent,
  14. 'image': vcard.querySelector('PHOTO BINVAL')?.textContent,
  15. 'image_type': vcard.querySelector('PHOTO TYPE')?.textContent,
  16. 'url': vcard.querySelector('URL')?.textContent,
  17. 'role': vcard.querySelector('ROLE')?.textContent,
  18. 'email': vcard.querySelector('EMAIL USERID')?.textContent,
  19. 'vcard_updated': (new Date()).toISOString(),
  20. 'vcard_error': undefined
  21. };
  22. }
  23. if (result.image) {
  24. const buffer = u.base64ToArrayBuffer(result['image']);
  25. const ab = await crypto.subtle.digest('SHA-1', buffer);
  26. result['image_hash'] = u.arrayBufferToHex(ab);
  27. }
  28. return result;
  29. }
  30. export function createStanza (type, jid, vcard_el) {
  31. const iq = $iq(jid ? {'type': type, 'to': jid} : {'type': type});
  32. if (!vcard_el) {
  33. iq.c("vCard", {'xmlns': Strophe.NS.VCARD});
  34. } else {
  35. iq.cnode(vcard_el);
  36. }
  37. return iq;
  38. }
  39. export function onOccupantAvatarChanged (occupant) {
  40. const hash = occupant.get('image_hash');
  41. const vcards = [];
  42. if (occupant.get('jid')) {
  43. vcards.push(_converse.vcards.get(occupant.get('jid')));
  44. }
  45. vcards.push(_converse.vcards.get(occupant.get('from')));
  46. vcards.forEach(v => (hash && v?.get('image_hash') !== hash) && api.vcard.update(v, true));
  47. }
  48. export async function setVCardOnModel (model) {
  49. let jid;
  50. if (model instanceof _converse.Message) {
  51. if (['error', 'info'].includes(model.get('type'))) {
  52. return;
  53. }
  54. jid = model.get('from');
  55. } else {
  56. jid = model.get('jid');
  57. }
  58. if (!jid) {
  59. log.warn(`Could not set VCard on model because no JID found!`);
  60. return;
  61. }
  62. await api.waitUntil('VCardsInitialized');
  63. model.vcard = _converse.vcards.get(jid) || _converse.vcards.create({ jid });
  64. model.vcard.on('change', () => model.trigger('vcard:change'));
  65. model.trigger('vcard:add');
  66. }
  67. function getVCardForOccupant (occupant) {
  68. const muc = occupant?.collection?.chatroom;
  69. const nick = occupant.get('nick');
  70. if (nick && muc?.get('nick') === nick) {
  71. return _converse.xmppstatus.vcard;
  72. } else {
  73. const jid = occupant.get('jid') || occupant.get('from');
  74. if (jid) {
  75. return _converse.vcards.get(jid) || _converse.vcards.create({ jid });
  76. } else {
  77. log.warn(`Could not get VCard for occupant because no JID found!`);
  78. return;
  79. }
  80. }
  81. }
  82. export async function setVCardOnOccupant (occupant) {
  83. await api.waitUntil('VCardsInitialized');
  84. occupant.vcard = getVCardForOccupant(occupant);
  85. if (occupant.vcard) {
  86. occupant.vcard.on('change', () => occupant.trigger('vcard:change'));
  87. occupant.trigger('vcard:add');
  88. }
  89. }
  90. function getVCardForMUCMessage (message) {
  91. const muc = message?.collection?.chatbox;
  92. const nick = Strophe.getResourceFromJid(message.get('from'));
  93. if (nick && muc?.get('nick') === nick) {
  94. return _converse.xmppstatus.vcard;
  95. } else {
  96. const jid = message.occupant?.get('jid') || message.get('from');
  97. if (jid) {
  98. return _converse.vcards.get(jid) || _converse.vcards.create({ jid });
  99. } else {
  100. log.warn(`Could not get VCard for message because no JID found! msgid: ${message.get('msgid')}`);
  101. return;
  102. }
  103. }
  104. }
  105. export async function setVCardOnMUCMessage (message) {
  106. if (['error', 'info'].includes(message.get('type'))) {
  107. return;
  108. } else {
  109. await api.waitUntil('VCardsInitialized');
  110. message.vcard = getVCardForMUCMessage(message);
  111. if (message.vcard) {
  112. message.vcard.on('change', () => message.trigger('vcard:change'));
  113. message.trigger('vcard:add');
  114. }
  115. }
  116. }
  117. export async function initVCardCollection () {
  118. _converse.vcards = new _converse.VCards();
  119. const id = `${_converse.bare_jid}-converse.vcards`;
  120. initStorage(_converse.vcards, id);
  121. await new Promise(resolve => {
  122. _converse.vcards.fetch({
  123. 'success': resolve,
  124. 'error': resolve
  125. }, {'silent': true});
  126. });
  127. const vcards = _converse.vcards;
  128. if (_converse.session) {
  129. const jid = _converse.session.get('bare_jid');
  130. const status = _converse.xmppstatus;
  131. status.vcard = vcards.get(jid) || vcards.create({'jid': jid});
  132. if (status.vcard) {
  133. status.vcard.on('change', () => status.trigger('vcard:change'));
  134. status.trigger('vcard:add');
  135. }
  136. }
  137. /**
  138. * Triggered as soon as the `_converse.vcards` collection has been initialized and populated from cache.
  139. * @event _converse#VCardsInitialized
  140. */
  141. api.trigger('VCardsInitialized');
  142. }
  143. export function clearVCardsSession () {
  144. if (shouldClearCache()) {
  145. api.promises.add('VCardsInitialized');
  146. if (_converse.vcards) {
  147. _converse.vcards.clearStore();
  148. delete _converse.vcards;
  149. }
  150. }
  151. }
  152. export async function getVCard (jid) {
  153. const to = Strophe.getBareJidFromJid(jid) === _converse.bare_jid ? null : jid;
  154. let iq;
  155. try {
  156. iq = await api.sendIQ(createStanza("get", to))
  157. } catch (iq) {
  158. return {
  159. jid,
  160. 'stanza': iq,
  161. 'vcard_error': (new Date()).toISOString()
  162. }
  163. }
  164. return onVCardData(jid, iq);
  165. }