19 package org.sleuthkit.autopsy.contentviewers.artifactviewers;
21 import java.awt.Component;
22 import java.awt.GridBagConstraints;
23 import java.awt.GridBagLayout;
24 import java.awt.Insets;
25 import java.awt.event.ActionListener;
26 import java.awt.image.BufferedImage;
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.HashMap;
33 import java.util.List;
35 import java.util.concurrent.CancellationException;
36 import java.util.concurrent.ExecutionException;
37 import java.util.logging.Level;
38 import java.util.stream.Collectors;
39 import javax.imageio.ImageIO;
40 import javax.swing.ImageIcon;
41 import javax.swing.JButton;
42 import javax.swing.JLabel;
43 import javax.swing.JScrollPane;
44 import javax.swing.SwingWorker;
45 import org.apache.commons.lang.StringUtils;
46 import org.openide.util.NbBundle;
47 import org.openide.util.lookup.ServiceProvider;
70 @ServiceProvider(service = ArtifactContentViewer.class)
74 private static final long serialVersionUID = 1L;
76 private GridBagLayout m_gridBagLayout =
new GridBagLayout();
77 private GridBagConstraints m_constraints =
new GridBagConstraints();
85 private List<BlackboardAttribute> phoneNumList =
new ArrayList<>();
86 private List<BlackboardAttribute> emailList =
new ArrayList<>();
87 private List<BlackboardAttribute> nameList =
new ArrayList<>();
88 private List<BlackboardAttribute> otherList =
new ArrayList<>();
89 private List<BlackboardAttribute> accountAttributesList =
new ArrayList<>();
91 private final static String DEFAULT_IMAGE_PATH =
"/org/sleuthkit/autopsy/images/defaultContact.png";
95 private final List<CentralRepoAccount> contactUniqueAccountsList =
new ArrayList<>();
99 private final Map<Persona, ArrayList<CentralRepoAccount>> contactUniquePersonasMap =
new HashMap<>();
117 @SuppressWarnings(
"unchecked")
119 private
void initComponents() {
122 setLayout(
new java.awt.GridBagLayout());
130 if (artifact == null) {
135 extractArtifactData(artifact);
136 }
catch (TskCoreException ex) {
137 logger.log(Level.SEVERE, String.format(
"Error getting attributes for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
143 this.setLayout(this.m_gridBagLayout);
151 return new JScrollPane(
this, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
156 return (artifact != null)
157 && (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID());
168 this.contactArtifact = artifact;
170 phoneNumList =
new ArrayList<>();
171 emailList =
new ArrayList<>();
172 nameList =
new ArrayList<>();
173 otherList =
new ArrayList<>();
174 accountAttributesList =
new ArrayList<>();
177 for (BlackboardAttribute bba : contactArtifact.getAttributes()) {
178 if (bba.getAttributeType().getTypeName().startsWith(
"TSK_PHONE")) {
179 phoneNumList.add(bba);
180 accountAttributesList.add(bba);
181 }
else if (bba.getAttributeType().getTypeName().startsWith(
"TSK_EMAIL")) {
183 accountAttributesList.add(bba);
184 }
else if (bba.getAttributeType().getTypeName().startsWith(
"TSK_NAME")) {
188 if (bba.getAttributeType().getTypeName().equalsIgnoreCase(
"TSK_ID")) {
189 accountAttributesList.add(bba);
194 datasourceName = contactArtifact.getDataSource().getName();
203 updateContactDetails();
209 initiatePersonasSearch();
217 "ContactArtifactViewer_phones_header=Phone",
218 "ContactArtifactViewer_emails_header=Email",
219 "ContactArtifactViewer_others_header=Other",})
223 updateContactImage(m_gridBagLayout, m_constraints);
224 updateContactName(m_gridBagLayout, m_constraints);
227 updateContactMethodSection(phoneNumList, Bundle.ContactArtifactViewer_phones_header(), m_gridBagLayout, m_constraints);
228 updateContactMethodSection(emailList, Bundle.ContactArtifactViewer_emails_header(), m_gridBagLayout, m_constraints);
229 updateContactMethodSection(otherList, Bundle.ContactArtifactViewer_others_header(), m_gridBagLayout, m_constraints);
240 "ContactArtifactViewer.contactImage.text=",})
241 private void updateContactImage(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
243 Insets savedInsets = contactPanelConstraints.insets;
244 contactPanelConstraints.gridy = 0;
245 contactPanelConstraints.gridx = 0;
246 contactPanelConstraints.insets =
new Insets(0, 0, 0, 0);
248 javax.swing.JLabel contactImage =
new javax.swing.JLabel();
249 contactImage.setIcon(getImageFromArtifact(contactArtifact));
250 contactImage.setText(Bundle.ContactArtifactViewer_contactImage_text());
253 CommunicationArtifactViewerHelper.addComponent(
this, contactPanelLayout, contactPanelConstraints, contactImage);
254 CommunicationArtifactViewerHelper.addLineEndGlue(
this, contactPanelLayout, contactPanelConstraints);
255 contactPanelConstraints.gridy++;
257 contactPanelConstraints.insets = savedInsets;
268 "ContactArtifactViewer_contactname_unknown=Unknown",})
269 private void updateContactName(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
271 boolean foundName =
false;
272 for (BlackboardAttribute bba : this.nameList) {
273 if (StringUtils.isEmpty(bba.getValueString()) ==
false) {
274 contactName = bba.getDisplayString();
276 CommunicationArtifactViewerHelper.addHeader(
this, contactPanelLayout, contactPanelConstraints, contactName);
281 if (foundName ==
false) {
282 CommunicationArtifactViewerHelper.addHeader(
this, contactPanelLayout, contactPanelConstraints, Bundle.ContactArtifactViewer_contactname_unknown());
297 "ContactArtifactViewer_plural_suffix=s",})
298 private void updateContactMethodSection(List<BlackboardAttribute> sectionAttributesList, String sectionHeader, GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
301 if (sectionAttributesList.isEmpty()) {
305 String sectionHeaderString = sectionHeader;
306 if (sectionAttributesList.size() > 1) {
307 sectionHeaderString = sectionHeaderString.concat(Bundle.ContactArtifactViewer_plural_suffix());
309 CommunicationArtifactViewerHelper.addHeader(
this, contactPanelLayout, contactPanelConstraints, sectionHeaderString);
310 for (BlackboardAttribute bba : sectionAttributesList) {
311 CommunicationArtifactViewerHelper.addKey(
this, contactPanelLayout, contactPanelConstraints, bba.getAttributeType().getDisplayName());
312 CommunicationArtifactViewerHelper.addValue(
this, contactPanelLayout, contactPanelConstraints, bba.getDisplayString());
320 "ContactArtifactViewer_heading_Source=Source",
321 "ContactArtifactViewer_label_datasource=Data Source",})
323 CommunicationArtifactViewerHelper.addHeader(
this, this.m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_heading_Source());
324 CommunicationArtifactViewerHelper.addKey(
this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_label_datasource());
325 CommunicationArtifactViewerHelper.addValue(
this, m_gridBagLayout, m_constraints, datasourceName);
334 "ContactArtifactViewer_persona_header=Persona",
335 "ContactArtifactViewer_persona_searching=Searching...",
336 "ContactArtifactViewer_cr_disabled_message=Enable Central Repository to view, create and edit personas.",
337 "ContactArtifactViewer_persona_unknown=Unknown"
342 JLabel personaHeader = CommunicationArtifactViewerHelper.addHeader(
this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_persona_header());
344 m_constraints.gridy++;
348 ? Bundle.ContactArtifactViewer_persona_searching()
349 : Bundle.ContactArtifactViewer_persona_unknown();
351 this.personaSearchStatusLabel =
new javax.swing.JLabel();
352 personaSearchStatusLabel.setText(personaStatusLabelText);
354 m_constraints.gridx = 0;
356 CommunicationArtifactViewerHelper.addComponent(
this, m_gridBagLayout, m_constraints, personaSearchStatusLabel);
361 personaSearchTask.execute();
363 personaHeader.setEnabled(
false);
364 personaSearchStatusLabel.setEnabled(
false);
366 CommunicationArtifactViewerHelper.addBlankLine(
this, m_gridBagLayout, m_constraints);
367 m_constraints.gridy++;
368 CommunicationArtifactViewerHelper.addMessageRow(
this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_cr_disabled_message());
369 m_constraints.gridy++;
371 CommunicationArtifactViewerHelper.addPageEndGlue(
this, m_gridBagLayout, this.m_constraints);
382 this.
remove(personaSearchStatusLabel);
384 m_constraints.gridx = 0;
385 if (contactUniquePersonasMap.isEmpty()) {
387 showPersona(null, 0, Collections.emptyList(), this.m_gridBagLayout, this.m_constraints);
389 int matchCounter = 0;
390 for (Map.Entry<
Persona, ArrayList<CentralRepoAccount>> entry : contactUniquePersonasMap.entrySet()) {
391 List<CentralRepoAccount> missingAccounts =
new ArrayList<>();
392 ArrayList<CentralRepoAccount> personaAccounts = entry.getValue();
397 if (personaAccounts.contains(account) ==
false) {
398 missingAccounts.add(account);
402 showPersona(entry.getKey(), matchCounter, missingAccounts, m_gridBagLayout, m_constraints);
403 m_constraints.gridy += 2;
408 CommunicationArtifactViewerHelper.addPageEndGlue(
this, m_gridBagLayout, this.m_constraints);
411 this.setLayout(this.m_gridBagLayout);
429 "ContactArtifactViewer_persona_label=Persona ",
430 "ContactArtifactViewer_persona_no_match=No matches found",
431 "ContactArtifactViewer_persona_button_view=View",
432 "ContactArtifactViewer_persona_button_new=Create",
433 "ContactArtifactViewer_persona_match_num=Match ",
434 "ContactArtifactViewer_missing_account_label=Missing contact account",
435 "ContactArtifactViewer_found_all_accounts_label=All accounts found."
437 private void showPersona(
Persona persona,
int matchNumber, List<CentralRepoAccount> missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints) {
440 Insets savedInsets = constraints.insets;
443 Insets extraIndentInsets =
new java.awt.Insets(0, 2 * CommunicationArtifactViewerHelper.LEFT_INSET, 0, 0);
446 constraints.gridx = 0;
447 javax.swing.JLabel matchNumberLabel = CommunicationArtifactViewerHelper.addKey(
this, gridBagLayout, constraints, String.format(
"%s %d", Bundle.ContactArtifactViewer_persona_match_num(), matchNumber));
449 javax.swing.JLabel personaNameLabel =
new javax.swing.JLabel();
450 javax.swing.JButton personaButton =
new javax.swing.JButton();
453 String personaButtonText;
454 ActionListener personaButtonListener;
455 if (persona != null) {
456 personaName = persona.
getName();
457 personaButtonText = Bundle.ContactArtifactViewer_persona_button_view();
460 matchNumberLabel.setVisible(
false);
461 personaName = Bundle.ContactArtifactViewer_persona_no_match();
462 personaButtonText = Bundle.ContactArtifactViewer_persona_button_new();
468 personaNameLabel.setText(personaName);
469 gridBagLayout.setConstraints(personaNameLabel, constraints);
470 CommunicationArtifactViewerHelper.addComponent(
this, gridBagLayout, constraints, personaNameLabel);
476 personaButton.setText(personaButtonText);
477 personaButton.addActionListener(personaButtonListener);
480 personaButton.setMargin(
new Insets(0, 5, 0, 5));
481 gridBagLayout.setConstraints(personaButton, constraints);
482 CommunicationArtifactViewerHelper.addComponent(
this, gridBagLayout, constraints, personaButton);
483 CommunicationArtifactViewerHelper.addLineEndGlue(
this, gridBagLayout, constraints);
485 constraints.insets = savedInsets;
488 if (persona != null) {
489 if (missingAccountsList.isEmpty()) {
491 constraints.gridx = 1;
494 javax.swing.JLabel accountsStatus =
new javax.swing.JLabel(Bundle.ContactArtifactViewer_found_all_accounts_label());
495 constraints.insets = extraIndentInsets;
496 CommunicationArtifactViewerHelper.addComponent(
this, gridBagLayout, constraints, accountsStatus);
497 constraints.insets = savedInsets;
499 CommunicationArtifactViewerHelper.addLineEndGlue(
this, gridBagLayout, constraints);
504 constraints.gridx = 0;
508 constraints.insets = extraIndentInsets;
509 CommunicationArtifactViewerHelper.addKeyAtCol(
this, gridBagLayout, constraints, Bundle.ContactArtifactViewer_missing_account_label(), 1);
510 constraints.insets = savedInsets;
512 CommunicationArtifactViewerHelper.addValueAtCol(
this, gridBagLayout, constraints, missingAccount.getIdentifier(), 2);
518 constraints.insets = savedInsets;
526 contactArtifact = null;
528 datasourceName = null;
530 contactUniqueAccountsList.clear();
531 contactUniquePersonasMap.clear();
533 phoneNumList.clear();
537 accountAttributesList.clear();
539 if (personaSearchTask != null) {
540 personaSearchTask.cancel(Boolean.TRUE);
541 personaSearchTask = null;
546 this.setLayout(null);
548 m_gridBagLayout =
new GridBagLayout();
549 m_constraints =
new GridBagConstraints();
551 m_constraints.anchor = GridBagConstraints.FIRST_LINE_START;
552 m_constraints.gridy = 0;
553 m_constraints.gridx = 0;
554 m_constraints.weighty = 0.0;
555 m_constraints.weightx = 0.0;
556 m_constraints.insets =
new java.awt.Insets(0, CommunicationArtifactViewerHelper.LEFT_INSET, 0, 0);
557 m_constraints.fill = GridBagConstraints.NONE;
570 ImageIcon imageIcon = defaultImage;
572 if (artifact == null) {
576 BlackboardArtifact.ARTIFACT_TYPE artifactType = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
577 if (artifactType != BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) {
582 for (Content content : artifact.getChildren()) {
583 if (content instanceof AbstractFile) {
584 AbstractFile file = (AbstractFile) content;
587 BufferedImage image = ImageIO.read(
new File(file.getLocalAbsPath()));
588 imageIcon =
new ImageIcon(image);
590 }
catch (IOException ex) {
597 }
catch (TskCoreException ex) {
598 logger.log(Level.WARNING, String.format(
"Unable to load image for contact: %d", artifact.getId()), ex);
611 private final List<CentralRepoAccount> uniqueAccountsList =
new ArrayList<>();
620 this.artifact = artifact;
624 protected Map<Persona, ArrayList<CentralRepoAccount>>
doInBackground() throws Exception {
626 Map<Persona, ArrayList<CentralRepoAccount>> uniquePersonas =
new HashMap<>();
629 List<Account> contactAccountsList = commManager.getAccountsRelatedToArtifact(artifact);
631 for (Account account : contactAccountsList) {
633 return new HashMap<>();
637 if (personaAccounts != null && !personaAccounts.isEmpty()) {
640 Collection<CentralRepoAccount> accountCandidates
644 .collect(Collectors.toList());
646 if (uniqueAccountsList.contains(crAccount) ==
false) {
647 uniqueAccountsList.add(crAccount);
652 Collection<Persona> personas
656 .collect(Collectors.toList());
659 for (
Persona persona : personas) {
660 if (uniquePersonas.containsKey(persona) ==
false) {
664 .collect(Collectors.toList());
666 ArrayList<CentralRepoAccount> personaAccountsList =
new ArrayList<>(accounts);
667 uniquePersonas.put(persona, personaAccountsList);
673 return uniquePersonas;
679 Map<Persona, ArrayList<CentralRepoAccount>> personasMap;
681 personasMap = super.get();
683 if (this.isCancelled()) {
687 contactUniquePersonasMap.clear();
688 contactUniquePersonasMap.putAll(personasMap);
689 contactUniqueAccountsList.clear();
690 contactUniqueAccountsList.addAll(uniqueAccountsList);
694 }
catch (CancellationException ex) {
695 logger.log(Level.INFO,
"Persona searching was canceled.");
696 }
catch (InterruptedException ex) {
697 logger.log(Level.INFO,
"Persona searching was interrupted.");
698 }
catch (ExecutionException ex) {
699 logger.log(Level.SEVERE,
"Fatal error during Persona search.", ex);
721 this.personaNameLabel = personaNameLabel;
722 this.personaActionButton = personaActionButton;
731 return personaNameLabel;
740 return personaActionButton;
758 this.personaUIComponents = personaUIComponents;
759 this.parentComponent = parentComponent;
763 "ContactArtifactViewer_persona_account_justification=Account found in Contact artifact"
775 if (contactName != null) {
803 this.persona = persona;
804 this.parentComponent = parentComponent;
819 private final Component parentComponent;
820 private final PersonaUIComponents personaUIComponents;
827 PersonaCreateCallbackImpl(Component parentComponent, PersonaUIComponents personaUIComponents) {
828 this.parentComponent = parentComponent;
829 this.personaUIComponents = personaUIComponents;
833 public void callback(Persona persona) {
835 if (persona != null) {
838 personaUIComponents.getPersonaNameLabel().setText(persona.getName());
839 personaUIComponents.getPersonaActionButton().setText(Bundle.ContactArtifactViewer_persona_button_view());
842 for (ActionListener act : personaButton.getActionListeners()) {
843 personaButton.removeActionListener(act);
845 personaButton.addActionListener(
new ViewPersonaButtonListener(parentComponent, persona));
849 personaButton.getParent().revalidate();
850 personaButton.getParent().repaint();
857 class PersonaViewCallbackImpl
implements PersonaDetailsDialogCallback {
860 public void callback(Persona persona) {
boolean addAccount(CentralRepoAccount account, String justification, Persona.Confidence confidence)
JButton getPersonaActionButton()
static Collection< PersonaAccount > getPersonaAccountsForAccount(long accountId)
void actionPerformed(java.awt.event.ActionEvent evt)
Collection< PersonaAccount > getPersonaAccounts()
void showPersona(Persona persona, int matchNumber, List< CentralRepoAccount > missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints)
final ImageIcon defaultImage
final JButton personaActionButton
void updateContactName(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
void updateContactImage(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
PersonaDetailsPanel getDetailsPanel()
void initiatePersonasSearch()
Map< Persona, ArrayList< CentralRepoAccount > > doInBackground()
final PersonaUIComponents personaUIComponents
JLabel personaSearchStatusLabel
void updateContactDetails()
void updateContactMethodSection(List< BlackboardAttribute > sectionAttributesList, String sectionHeader, GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
void actionPerformed(java.awt.event.ActionEvent evt)
final BlackboardArtifact artifact
BlackboardArtifact contactArtifact
SleuthkitCase getSleuthkitCase()
void setPersonaName(String name)
static Case getCurrentCase()
synchronized static Logger getLogger(String name)
final JLabel personaNameLabel
CentralRepoAccount getAccount()
final Component parentComponent
ContactPersonaSearcherTask personaSearchTask
boolean isSupported(BlackboardArtifact artifact)
final Component parentComponent
ImageIcon getImageFromArtifact(BlackboardArtifact artifact)
static boolean isEnabled()
void setArtifact(BlackboardArtifact artifact)
JLabel getPersonaNameLabel()
void extractArtifactData(BlackboardArtifact artifact)