aboutsummaryrefslogblamecommitdiffstats
path: root/data/lib/rhbzpage.js
blob: 9af0127f188f242ef6abaf2a63a969da336c9cf0 (plain) (tree)
1
2
3
4
5
6
7
8
9
10


                                                     
                                                                      



                                                     

                                                                           






                                                                            
                            


                                                                          
                                                       
                       

























                                                                                                                                                                 

  
                            

                             







                                                                              






















                                                               

 

                        





                                                       
                               

                                                     

 





                                                                       
                               








                                                        
 

   
                                                            
   
                             



















                                                                    
 



                                                                             
                                                        
























                                                                                   
 
 
                                      


                                                                               

 




                                                                                 
                                               
                  
 





















                                                                          
 
 
                                
   
  
   
                                         
















                                                                       
                                    
 































                                                                    
             










                                                   
 
 





                                                      
                             

                                                                         
 
 




                                                        
                                   


                                                                 
 
 
   
                                                         
   
                                     




                                                                         
 




                                                                     
 


                                                                                
 

                                                                                   
 






                                                                                                      
     





                                                                      
 


                                                        
 
                                                                        
 
 
   
                                                                
  


                                              
   
                                            
                                                        
  




                                                                                              
  
 
 
   
                                                                           
  
                                             
               
   
                                   





















                                                                               
       
   
 





                                           
                         



                                                                 
 





                                                                
                      
                                 
 








                                                                          
                        



























































                                                                                      
 
 
   


                                      







                                                                                 


   


                                                                             
   
                          










                                                                 
 

   
                                                          
  
               
   
                            



                                                                           
 





                                                                   
 
 




                                                  
                                       







                                                                     
 
 



                                                                        
                                            

                                                       


                                               
                                        


























                                                                          
 





                                                                              
                                     

               
                                  
                                                   
 
 
                                            













                                                                   
 
 
                               














                                                   
 





                                                                          


                                            




                                                                                  


                                                 



















                                          
 
 
   




                                                                             
                                       








                                                     
 









                                                                  
                           





                                   
 







                                                                               
                                 













                                                                              
                                         

























                                                                   
 

   





                                                  
                           



                                                 
 






                                                                   
                               










































                                                                            
 
 
                           





                                                                           
 



   
                               
































                                                                            

 
                     















                                                               
       
 

























































                                                                               
 



                                                                   
                    
                                    
                  






                                                                               
 
// Released under the MIT/X11 license
// http://www.opensource.org/licenses/mit-license.php
"use strict";
var titleParsedAttachment = "Part of the thread where crash happened";


// For identification of graphics card
var manuChipStrs = [ [ "ATI Radeon", "ATI", "1002" ],
    [ "ATI Mobility Radeon", "ATI", "1002" ],
    [ "Intel Corporation", "INTEL", "8086" ], [ "NVIDIA", "NV", "10de" ] ];

// http://en.wikipedia.org/wiki/HSL_color_space
// when only the value of S is changed
// stupido!!! the string is value in hex for each color
var RHColor = new Color(158, 41, 43); // RGB 158, 41, 43; HSL 359, 1, 39
var FedoraColor = new Color(0, 40, 103); // RGB 0, 40, 103; HSL 359, 1, 39
var RawhideColor = new Color(0, 119, 0); // or "green", or RGB 0, 119, 0, or
                      // HSL
// 120, 0, 23
var RHITColor = new Color(102, 0, 102); // RGB 102, 0, 102; HSL 300, 0, 20

// [   126.386] (--) NOUVEAU(0): Chipset: "NVIDIA NVaf"
var logAnalyzeLogic = {
  "AnalyzeInterestingLine": {
  /*
  [   126.378] (--) PCI:*(0:4:0:0) 10de:08a0:106b:00c2 rev 162, Mem @ 0xd2000000/16777216, \
  0xc0000000/268435456, 0xd0000000/33554432, I/O @ 0x00001000/128, BIOS @ 0x????????/131072
  */
    re: [
      "^(\\[[ .0-9]+\\])?\\s*\\(--\\) PCI:\\*\\([0-9:]+\\)\\s*" +
        "([0-9a-f:]+).*$",
      "^\\s*\\[?[ 0-9.]*\\]?\\s*\\(--\\) "+
        "([A-Za-z]+)\\([0-9]?\\): Chipset: (.*)$",
        ],
    func: chipsetMagic
  },
  /*
  [   126.385] (WW) Falling back to old probe method for vesa
  [   126.385] (WW) Falling back to old probe method for fbdev
  [   126.386] (--) NOUVEAU(0): Chipset: "NVIDIA NVaf"
  Backtrace:

  [  33.158] Kernel command line: ro root=LABEL=root rd_NO_LUKS rd_NO_LVM rd_NO_MD rd_NO_DM LANG=en_US.UTF-8 SYSFONT=latarcyrheb-sun16 KEYTABLE=us drm.debug=0x04

  */
  "AnalyzeXorgLogBacktrace": {
    re:  "^\\s*(\\[[0-9 .]*\\])?\\s*(\\((EE|WW)\\)|.* [cC]hipset:.*)|\\s*(Backtrace|Kernel command line)",
    func: analyzeXorg
  }
};

var ProfessionalProducts = [
  "Red Hat Enterprise Linux",
  "Red Hat Enterprise MRG"
];

// END OF CONSTANTS

var btSnippet = null;
var reqCounter = 0; // TODO should be probably a dict indexed by called method

function RHOnMessageHandler(msg) {
  switch (msg.cmd) {
  case "Error":
    alert("Error " + msg.data);
    break;
  case "Unhandled":
    break;
  case "AddAttachmentCallback":
    addAttachmentCallback(msg.data);
    break;
  case "FixAttachmentMIMECallback":
    XMLRPCcallback();
    break;
  case "AnalyzeInterestingLine":
  case "AnalyzeXorgLogBacktrace":
    findInterestingLine(msg.data, msg.cmd);
    break;
  case "queryUpstream":
    queryUpstreamCallback(msg.data);
    break;
  default:
    console.error("Error: unknown RPC call " + msg.toSource());
    break;
  }
}

// RHBugzillaPage object

/**
 * Find default assignee based on the current component
 *
 * @return String what would be a default assignee if
 * we haven't set it up.
 */
function getDefaultAssignee() {
  return filterByRegexp(constantData.defaultAssignee,
    getComponent()).toLowerCase();
}

/**
 * Set default assignee
 *
 * @return none
 * sets this.defaultAssignee property according to defaultAssignee list
 */
function setDefaultAssignee() {
  var defAss = getDefaultAssignee();

  // Add setting default assignee
  if ((defAss.length > 0) && (defAss !== getOwner())) {
    createNewButton("bz_assignee_edit_container",true, {
      "name": "Def. Assignee",
      "assignee": "default"
    });
  }
}

/**
 * Auxiliary function to compute more complicated resolution
 */
function closeSomeRelease() {
  // for RAWHIDE close as RAWHIDE,
  // if active selection -> CURRENTRELEASE
  // and put the release version to
  // "Fixed in Version" textbox
  // otherwise -> NEXTRELEASE
  selectOption("bug_status", "CLOSED");
  var text = getSelection();
  var resolution = "";

  if (text.length > 0) {
    resolution = "CURRENTRELEASE";
    document.getElementById("cf_fixed_in").value = text;
  }
  else if (document.getElementById("version").value === "rawhide") {
    resolution = "RAWHIDE";
  }
  else {
    resolution = "NEXTRELEASE";
  }
  centralCommandDispatch("resolution", resolution);
}

/**
 * Additional commands specific for this subclass, overriding superclass one.
 */
function RHcentralCommandDispatch(cmdLabel, cmdParams) {
  switch (cmdLabel) {
  // Set up our own commands
  case "closeUpstream":
    addClosingUpstream();
    break;
  case "computeResolution":
    closeSomeRelease();
    break;
  case "queryStringUpstreamBugzilla":
    queryUpstream();
    break;
  case "sendBugUpstream":
    sendBugUpstream();
    break;
  case "markTriaged":
    markBugTriaged();
    break;
  case "chipMagic":
    fillInWhiteBoard(cmdParams);
    break;
  // If we don't have it here, call superclass method
  default:
    console.error("Unknown command:\n" + cmdLabel + "\nparameters:\n" + cmdParams);
    break;
  }
}

function addAttachmentCallback(resp) {
  var newAttachID = parseInt(resp.params.param.value.array.data.value.int, 10);
  console.log("attachID = " + newAttachID);
  // FIXME callback.call(param, newAttachID, data.length);
}

/**
 *
 * This has to stay in RHBugzillaPage because upstream doesn't have addAttachment
 * XML-RPC call yet.
 */
function addAttachment(data, callback, param) {
  var params = [];

  if (!constantData.passwordState.passAvailable) {
    console.error("addAttachment : No password, no XML-RPC calls; sorry");
    return null;
  }

  params.push(getBugNo());
  params.push({
    description: titleParsedAttachment,
    filename: "parsed-backtrace.txt",
    contenttype: "text/plain",
    data: window.btoa(data),
    nomail: true
  });

  postMessage(new Message("MakeXMLRPCall", {
    url: constantData.XMLRPCData[window.location.hostname].url,
    login: getLogin(),
    method: "bugzilla.addAttachment",
    params: params,
    callRPC: "AddAttachmentCallback"
  }));
  reqCounter++;
}

/* === Bugzilla functions === */
/**
 *
 */
function pasteBacktraceInComments(atts) {
  /*
  Let's comment it out, and we'll see if anything breaks.
  TODO This paragraph looks suspicous ... what is it?
  Does it belong to this function?
  var notedLabel = document.querySelector("label[for='newcc']");
  while (notedLabel.firstChild) {
    var node = notedLabel.removeChild(notedLabel.firstChild);
    notedLabel.parentNode.insertBefore(node, notedLabel);
  }
  notedLabel.parentNode.removeChild(notedLabel);
  */

  // FIXME BROKEN and its depending functions are even more broken
  return null;

  var abrtQueryURL = "https://bugzilla.redhat.com/buglist.cgi?" +
    "cmdtype=dorem&remaction=run&namedcmd=all%20NEW%20abrt%20crashes&"+
		  "sharer_id=74116";

  var mainTitle = document
      .getElementsByClassName("bz_alias_short_desc_container")[0];

  createDeadLink ("callAbrtQuery_link",
    "Abrt bugs", mainTitle, abrtQueryURL, [], false, null, "a");

  if (idContainsWord("cf_devel_whiteboard", 'btparsed')) {
    addStuffToTextBox('status_whiteboard', 'btparsed');
  }

  if (!(isTriaged() || idContainsWord("status_whiteboard",
      'btparsed') || (atts.length > 0))) {
    var btAttachments = atts
        .filter(function(att) {
          return (/File: backtrace/.test(att[0]));
      });
    // TODO we need to go through all backtrace attachments, but
    // just the first one will do for now, we would need to do async
    // parsing
    btAttachments.forEach(function(x) {
      var attURL = "https://bugzilla.redhat.com/attachment.cgi?id="
          + x[1];
      if ((!btSnippet) && // ???? FIXME
          (!idContainsWord("status_whiteboard", 'btparsed'))) {
        Request({
          url: attURL,
          onComplete: function(response) {
            if (response.status == 200) {
              btSnippet = parseBacktrace(response.text);
              if (btSnippet) {
                addCheckShowLink(x,btSnippet);
              }
            }
          }
        }).get();
      }
    }, this);
  }
  // Add "show BT" links
  if (parsedAttachments.length > 0) {
    this.parsedAttachments.forEach(function (att) {
      addShowParsedBTLink(att);
    });
  }
}

/**
 * Open new window with the content of the attachment.
 *
 * @param id Number of the attachment id
 * @return none
 */
function showAttachment(id) {
  postMessage(new Message("OpenURLinPanel",
    "https://" + window.location.hostname + "/attachment.cgi?id=" + id));
}

/**
 * add a link opening a window with the parsed backtrace
 *
 * @param att Attachment object
 */
function addShowParsedBTLink(att) {
  var elem = att[4].querySelector("td:last-of-type");
  createDeadLink("showParsedBacktraceWindow-" + att[1], "showBT",
    elem, showAttachment, att[1], true);
}

/**
 * Unfinished ... see above FIXME BROKEN AND DOESN'T WORK
 */
function addNewAttachmentRow(origAtt,
    newAttId, newAttSize) {
  var that = this;
  var oldAddBTLink = document.getElementById("attachBacktraceActivator");
  oldAddBTLink.parentNode.removeChild(oldAddBTLink);
  var newTRElem = origAtt[4].cloneNode(true);

  // fix number of the attachment
  Array.forEach(newTRElem.getElementsByTagName("a"), function (aEl) {
    aEl.setAttribute("href",
      aEl.getAttribute("href").replace(origAtt[1], newAttId));
  });

  var aElements = newTRElem.getElementsByTagName("a");
  aElements[0].setAttribute("name","parsed-backtrace.txt");
  aElements[0].getElementsByTagName("b")[0].textContent = titleParsedAttachment;

  var sizeSpan = newTRElem.getElementsByClassName("bz_attach_extra_info")[0];
  sizeSpan.textContent = "(" + (newAttSize / 1024).toFixed(2) + " KB, text/plain)";

  // aElements[1].textContent = new Date().toString(); TODO we should add eventually, but not pressing

  var vcardSpan = newTRElem.getElementsByClassName("vcard")[0];
  if (vcardSpan !== undefined) {
    var vcardSpanClassList = vcardSpan.classList;
    if (/@redhat\.com/.test(this.login) && !vcardSpanClassList.contains("redhat_user")) {
      vcardSpanClassList.add("redhat_user");
    }
    var vcardAElem = vcardSpan.getElementsByTagName("a")[0];
    vcardAElem.setAttribute("title", this.login);
    vcardAElem.setAttribute("href", "mailto:" + this.login);
    vcardAElem.className = "email";
    vcardAElem.innerHTML="<span class='fn'>" + this.login + "</span>";
  }

  var elem = newTRElem.querySelector("td:last-of-type");
  this.createDeadLink("showBacktrace", "show BT", elem,
    this.showAttachment, newAttId, false);

  origAtt[4].parentNode.insertBefore(newTRElem, origAtt[4].nextSibling);
}

/**
 * Add a link to create a new attachment with a parsed backtrace
 *
 * @param oldAtt Object with an attachment row
 * @param snippet String with parsed backtrace
 * @return none
 */
function addCheckShowLink(oldAtt, snippet) {
  var elem = oldAtt[4].querySelector("td:last-of-type");
/*
  createDeadLink("attachBacktraceActivator", "add parsed BT", elem, function(x) {
    // pass function and parameters as two separate parameters, the function to be called from
    // addAttachment
    addAttachment(snippet, addNewAttachmentRow, oldAtt);
    }, [], true);
*/
}

/**
 * Make it sailent that the some attachments with bad MIME type are present
 *
 * @param atts Array of attachments subarrays
 * @return none
 */
function markBadAttachments(atts) {
  var badMIMEArray = [ "application/octet-stream", "text/x-log", "undefined" ];
  if (!constantData.passwordState.passAvailable) {
    console.log("markBadAttachments : No password, no XML-RPC calls; sorry");
    return null;
  }

  var badAttachments = atts.filter(function(att) {
    return (isInList(att[2], badMIMEArray));
  });

  if (badAttachments.length > 0) {
    var titleElement = document.
        getElementsByClassName("bz_alias_short_desc_container")[0];
    titleElement.style.backgroundColor = "olive";

    createDeadLink("fixAllButton", "Fix all", titleElement, function() {
      Array.forEach(badAttachments, function(x) {
        fixAttachById(x[1]);
      });
    }, [], false, null, "f");
    badAttachments.forEach(function(x, i, a) {
      addTextLink(x);
    });
  }
}

/**
 * Is this bug a RHEL bug?
 *
 * @return Boolean true if it is a RHEL bug
 */
function isEnterprise() {
  var result = ProfessionalProducts.some(function(elem,idx,arr) {
    return new RegExp(elem).test(getProduct());
  });
  return result;
}

/**
 * Find out whether the bug is needed an attention of bugZappers
 *
 * @return Boolean whether the bug has been triaged or not
 */
function isTriaged() {
    return hasKeyword("Triaged");
}

/**
 * Set branding colours to easily distinguish between Fedora and RHEL bugs
 *
 * @param brand String with product of the current bug
 * @param version String with the version of the bug
 * @param its String with the IsueTracker numbers
 * @return none
 */
function setBranding() {
  var brandColor = {};
  var TriagedColor = {};

  var ITbutton = document.getElementById("cf_issuetracker");
  var its = ITbutton ? ITbutton.value.trim() : "";

  if (isEnterprise()) {
    if (its && (its.length > 0)) {
      brandColor = RHITColor;
    }
    else {
      brandColor = RHColor;
    }
  }
  else if (new RegExp("Fedora").test(document.getElementById("product").value)) {
    if (document.getElementById("version").value === "rawhide") {
      brandColor = RawhideColor;
    }
    else {
      brandColor = FedoraColor;
    }
  }

  // Comment each of the following lines to get only partial branding
  document.getElementsByTagName("body")[0].style.background = brandColor
      .toString()
      + " none";
  document.getElementById("titles").style.background = brandColor.toString()
      + " none";

  // Remove "Bug" from the title of the bug page, so we have more space with
  // plenty of tabs
  var titleElem = document.getElementsByTagName("title")[0];

  titleElem.textContent = titleElem.textContent.slice(4);
  var bodyTitleParent = document.getElementById("summary_alias_container").parentNode;
  var bodyTitleElem = bodyTitleParent.getElementsByTagName("b")[0];
  bodyTitleElem.textContent = bodyTitleElem.textContent.slice(4);

  // Make background-color of the body of bug salmon pink
  // for security bugs.
  if (hasKeyword("Security")) {
    document.getElementById("bugzilla-body").style.background = SalmonPink
        .toString() + ' none';
  }

  // Make it visible whether the bug has been triaged
  if (isTriaged()) {
    document.getElementById("bz_field_status").style.background = brandColor
        .lightColor().toString()
        + " none";
  }

  var compElems;
  if (config.suspiciousComponents
      && isInList(getComponent(), config.suspiciousComponents)
      && (compElems = document
          .getElementById("bz_component_edit_container"))) {
    compElems.style.background = "red none";
  }
}

/**
 *
 */
function queryUpstreamCallback(text) {
  var searchData = filterByRegexp(constantData.queryUpstreamBug, getComponent());
  var urlBase = searchData.url;
  text = searchData.searchBy+":"+searchData.fillIn+" "+text.trim();
  if (searchData.fillIn == "$$$") {
    text = text.replace("$$$", getComponent());
  }
  text = encodeURIComponent(text).replace("%20","+");
  postMessage(new Message("OpenURLinTab", urlBase + text));
}

/**
 * Search simple query in the upstream bugzilla appropriate for the component
 *
 * @return none
 */
function queryUpstream() {
  if (!constantData.queryUpstreamBug) {
    alert("We don't have constantData.queryUpstreamBug set up!");
    return null;
  }
  var text = getSelection();
  if (!text) {
    postMessage(new Message("GetClipboard", "queryUpstream"));
  }
  else {
    queryUpstreamCallback(text);
  }
}

/**
 * Open a tab in the upstream bugzilla to create a new bug
 *
 * @return none
 */
function sendBugUpstream() {
  var urlStr = filterByRegexp(constantData.newUpstreamBug, getComponent());
  if (!urlStr) {
    return null;
  }

  postMessage(new Message("OpenBugUpstream", {
    url: urlStr,
    subject: document.getElementById("short_desc_nonedit_display").
      textContent.trim(),
    comment: collectComments()
  }));
}

/**
 * Add a link opening selected lines of Xorg.0.log
 *
 * @return none
 */
function addCheckXorgLogLink(attList) {
  if (config.xorglogAnalysis) {
    attList.forEach(function (row) {
      var elemS = row[4].getElementsByTagName("td");
      var elem = elemS[elemS.length - 1];
      createDeadLink("xorgLogAnalyzeLink", "check", elem,
          analyzeXorgLog, [row[1], "AnalyzeXorgLogBacktrace"], "br");
    });
  }
}

/**
 * Given line to be parsed, find out which chipset it is and fill in the
 * whiteboard
 *
 * @param PCIidArrObj object with two fields
 *    id Array manufacturer-ID and product-ID (PCI IDs)
 *    chipsetLine RE
 * @param driverStr String with the driver name
 * @return None
 */
function fillInWhiteBoard(PCIidArrObj) {
  var outStr = "";
  var cardIDStr = "";
  var cardIDArr = [];
  var cardName = "";
  var PCIid = (PCIidArrObj.id[0] + "," + PCIidArrObj.id[1]).toUpperCase();

  if (PCIidArrObj.id[0].toLowerCase() == "10de") {
    cardName = PCIidArrObj.chipsetLine[2].replace(/\s*nvidia\s*/ig,"").
      replace('"','','g');
  }
  else {
    try {
      cardName = constantData.chipNames[PCIid][0];
    } catch (e if e instanceof TypeError)  {
      PCIid = PCIid.toLowerCase().replace(",",":");
      postMessage(new Message("SetClipboard", PCIid.toString()));
      alert("PCI ID " + PCIid + " is not known!");
      return ; // early termination
    } catch (e) {
      throw e;
    }
  }

  clickMouse("editme_action");
  var titleElem = document.getElementById('short_desc');
  titleElem.value = '[' + cardName + ']\u00A0' + titleElem.value;
  document.getElementById("fillin_btn").style.display = "none";
}

/**
 * Get attached Xorg.0.log, parse it and find the value of chip. Does not fill
 * the whiteboard itself, just adds button to do so,paramList so that slow
 * XMLHttpRequest is done in advance.
 *
 * @param log array of XorgLogAttList
 * @return None
 */
function fillInChipMagic(XlogID) {
  analyzeXorgLog(XlogID, "AnalyzeInterestingLine");
}

function chipsetMagic (interestingLineArr) {
  // parse Xorg.0.log
  if (interestingLineArr.length >0) {
    var interestingArray = interestingLineArr[0];
    if (interestingArray.length > 1) {
      var interestingPCIID = interestingArray[2].trim().split(":");
      createNewButton("short_desc_nonedit_display", false, {
        "name": "Fill In",
        "chipMagic": {
          "id": interestingPCIID,
          "chipsetLine": interestingLineArr[1]
        },
      });
    }
  }
}

function analyzeXorg(results) {
  var innerString = "";

  if (results.length > 0) {
    results.splice(0, 1); // remove headers
    results.sort();

    results.forEach(function(lRE) {
      innerString += lRE.input + "<br>\n";
    });
    innerString += "----------<br>\n" +
      results.length + " interesting lines found.";
  }
  else {
    innerString += "No matching lines found!";
  }

  document.body.style.cursor = "auto";
  postMessage(new Message("OpenStringInPanel",
    '<!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN">' +
    "<html><head><title>Xorg.0.log analysis</title></head><body><pre>\n" +
    innerString.trim() +
    "\n</pre></body></html>"));
}

function analyzeXorgLog(attachID, backMsg) {
  document.body.style.cursor = "wait";
  postMessage(new Message("GetURL", {
    url: "https://" + window.location.hostname + "/attachment.cgi?id=" + attachID,
    backMessage: backMsg
  }));
}

function findInterestingLine(wholeLog, backMsg) {
  var REstr = logAnalyzeLogic[backMsg].re;
  var REarr = [];
  if (typeof REstr == "string") {
    REarr = [new RegExp(REstr)];
  }
  else if (Array.isArray(REstr)) {
    REarr = REstr.map(function (reone) {
      return new RegExp(reone);
    });
  }
  var results = [];
  wholeLog.split("\n").
    forEach(function(line) {
      REarr.forEach(function (re, reIdx) {
        if (re.test(line)) {
          results.push(re.exec(line));
        }
      });
    });
  logAnalyzeLogic[backMsg].func(results);
}

/**
 * Return string with the ID for the external_id SELECT for external bugzilla
 *
 * @param URLhostname String hostname of the external bugzilla
 * @return String with the string for the external_id SELECT
 */
function getBugzillaName(URLhostname) {
  var bugzillaID = "";
  var bzLabelNames = constantData.bugzillaLabelNames;
  if (bzLabelNames[URLhostname]) {
    bugzillaID = bzLabelNames[URLhostname];
  }
  else {
    bugzillaID = "";
  }
  return bugzillaID;
}

/**
 * Callback function for the XMLRPC request
 *
 * @param ret Object with xmlhttprequest response with attributes:
 * + status -- int return code
 * + statusText
 * + responseHeaders
 * + responseText
 */
function XMLRPCcallback() {
  reqCounter--;
  if (reqCounter <= 0) {
    setTimeout(function () {
      window.location.reload(true);
    }, 1000);
  }
}

/**
 * The worker function -- call XMLRPC to fix MIME type of the particular
 * attachment
 *
 * @param id Integer with the attachment id to be fixed
 * @param type String with the new MIME type, optional defaults to "text/plain"
 * @param email Boolean whether email should be sent to appropriate person;
 *      option, defaults to false
 *
 * updateAttachMimeType($data_ref, $username, $password)
 *
 * Update the attachment mime type of an attachment. The first argument is a
 * data hash containing information on the new MIME type and the attachment id
 * that you want to act on.
 *
 * $data_ref = { "attach_id" => "<Attachment ID>", # Attachment ID to perform
 * MIME type change on. "mime_type" => "<New MIME Type Value>", # Legal MIME
 * type value that you want to change the attachment to. "nomail" => 0, #
 * OPTIONAL Flag that is either 1 or 0 if you want email to be sent or not for
 * this change };
 *
 */
function fixAttachById(id, type, email) {
  var params = [];

  if (type === undefined) {
    type = "text/plain";
  }
  if (email === undefined) {
    email = false;
  }

  // https://bugzilla.redhat.com/\
  // docs/en/html/api/extensions/compat_xmlrpc/code/webservice.html
  // test on https://bugzilla.redhat.com/show_bug.cgi?id=485145
  params.push({
    'attach_id' : id,
    'mime_type' : type,
    'nomail' : !email
  });

  postMessage(new Message("MakeXMLRPCall", {
    url: constantData.XMLRPCData[window.location.hostname].url,
    login: getLogin(),
    method: "bugzilla.updateAttachMimeType",
    params: params,
    callRPC: "FixAttachmentMIMECallback"
  }));
  reqCounter++;
}

/**
 * Add a link to the bad attachment for fixing it.
 *
 * @param
 * <TR> DOM jQuery element with a bad attachment
 * @return none
 */
function addTextLink(row) {
  var elemS = row[4].getElementsByTagName("td");
  var elem = elemS[elemS.length - 1];
  createDeadLink("addFix2TextLink", "text", elem,
      fixAttachById, row[1], "br");
}

/**
 * Add information about the upstream bug upstream, and closing it.
 *
 * @param evt Event which called this handler
 * @return none
 */
function addClosingUpstream() {
  var refs = document.getElementById("external_bugs_table")
      .getElementsByTagName("tr");

  // that's a bad id, if there is a one. :)
  var inputBox = document.getElementById("inputbox");
  var externalBugID = 0;
  var wholeURL = "";

  // Fix missing ID on the external_id SELECT
   document.getElementsByName("external_id")[0].setAttribute("id",
      "external_id");

  if (inputBox.value.match(/^http.*/)) {
    externalBugID = getBugNoFromURL(inputBox.value);
    if (externalBugID) {
      inputBox.value = externalBugID;
    }
    // get bugzillaName and set the label
    var bugzillaName = getBugzillaName(wholeURL.host);
    selectOptionByLabel("external_id", bugzillaName);
  }
  else if (!isNaN(inputBox.value)) {
    externalBugID = parseInt(inputBox.value, 10);
    var bugzillaHostname = document.getElementById("external_id").value;
    wholeURL = bugzillaHostname+"show_bug.cgi?id="+externalBugID;
  }
  else {
    // no inputBox.value -- maybe there is an external bug from
    // the previous commit?
  }

  // It is not good to close bug as UPSTREAM, if there is no reference
  // to the upstream bug.
  if ((externalBugID > 0) || (refs.length > 2)) {
    var msgStr = constantData.commentStrings.sentUpstreamString;
    msgStr = msgStr.replace("§§§", wholeURL);
    centralCommandDispatch("comment",msgStr);
    centralCommandDispatch("status", "CLOSED");
    centralCommandDispatch("resolution", "UPSTREAM");
  }
  else {
    console.log("No external bug specified among the External References!");
  }
}

function markBugTriaged() {
  // https://fedoraproject.org/wiki/BugZappers/Meetings/Minutes-2009-Oct-27
  // http://meetbot.fedoraproject.org/fedora-meeting/2009-11-24\
  // /fedora-meeting.2009-11-24-15.11.log.html
  // http://meetbot.fedoraproject.org/fedora-meeting/2009-11-24\
  // /fedora-meeting.2009-11-24-15.11.log.html
  addStuffToTextBox("keywords","Triaged");
}

/**
 *
 */
function parseBacktrace (ret) {
  var signalHandler = new RegExp("^\\s*#[0-9]*\\s*<signal handler called>");
  var frameNo = new RegExp("^\\s*#([0-9]*)\\s");

  var splitArray = ret.split("\n");
  var i = 0, ii = splitArray.length;
  var outStr = "", curLine = "", numStr = "";
  var lineCounter = 0, endLineNo = 0;

  // TODO shouldn't we just cut off and analyze whole thread?
  while (i < ii) {
    if (signalHandler.test(splitArray[i])) {
      break;
    }
    i++;
  }

  if (i < ii) {
    lineCounter = parseInt(frameNo.exec(splitArray[i])[1], 10);
    endLineNo = lineCounter + NumberOfFrames;
    curLine = splitArray[i];
    while ((lineCounter < endLineNo) && (curLine.trim().length > 0)
        && (i < ii)) {
      outStr += curLine + '\n';
      numStr = frameNo.exec(curLine);
      if (numStr) {
        lineCounter = parseInt(numStr[1], 10);
      }
      i++;
      curLine = splitArray[i];
    }
    return outStr;
  }
  return "";
}

function RHBZinit() {
  // inheritance ... call superobject's constructor
  var AbrtRE = new RegExp("^\\s*\\[abrt\\]");
  var FillMagicDoneRE = new RegExp("^\\s*\\[[0-9a-zA-Z_]*\\]");
  var btSnippet = "";

  var signaturesCounter = 0;
  var chipMagicInterestingLine = "";

  // getBadAttachments
  var XorgLogAttList = [];
  var XorgLogAttListIndex = 0;
  var attachments = getAttachments();
  markBadAttachments(attachments);

  var parsedAttachments = attachments.filter(function (att) {
      return (new RegExp(titleParsedAttachment).test(att[0]));
    });

  if (constantData.defaultAssignee) {
    setDefaultAssignee();
  }

  // Dig out backtrace protection against double-firing?
  btSnippet = "";

  var parseAbrtBacktraces = config.parseAbrtBacktraces;
  if (parseAbrtBacktraces && AbrtRE.test(getSummary())) {
    pasteBacktraceInComments(parsedAttachments);
  }

  // Find out Xorg.0.log attachment URL
  XorgLogAttList = attachments.filter(function (value) {
    // Xorg.0.log must be text, otherwise we cannot parse it
    return (/[xX].*log/.test(value[0]) && /text/.test(value[2]));
  });
  // Just add a link to every Xorg.0.log link analyzing it.
  addCheckXorgLogLink(XorgLogAttList);

  var maintCCAddr = "";
  if (constantData.CCmaintainer) {
    maintCCAddr = filterByRegexp(constantData.CCmaintainer,
      getComponent())[0]; // filterByRegexp returns array, not string
  }

  // TODO Get compiz bugs as well
  if ((constantData.chipNames) &&
      (XorgLogAttList[0]) &&
      (!FillMagicDoneRE.test(getSummary())) &&
      (maintCCAddr === "xgl-maint@redhat.com")) {
    // Add find chip magic button
    var whiteboard_string = document.getElementById("status_whiteboard").value;
    if (!/card_/.test(whiteboard_string)) {
      fillInChipMagic(XorgLogAttList[0][1]);
    }
  }

  // we should make visible whether maintCCAddr is in CCList
  if (maintCCAddr && isInList(maintCCAddr, getCCList())) {
    var ccEditBoxElem = document.getElementById("cc_edit_area_showhide");
    ccEditBoxElem.style.color = "navy";
    ccEditBoxElem.style.fontWeight = "bolder";
    ccEditBoxElem.style.textDecoration = "underline";
  }

  // Take care of signature for Fedora bugzappers
  if (config.signature && config.signature.length > 0) {
    var signatureFedoraString = config.signature;
    document.forms.namedItem("changeform").addEventListener("submit",
        function(aEvt) {
          if (signaturesCounter < 1) {
            addStuffToTextBox("comment", signatureFedoraString);
            signaturesCounter += 1;
          }
        }, false);
  }
  setBranding();

  // set default assignee on change of the component
  var compElement = document.getElementById("component");
  if (compElement && (compElement.options)) {
    document.getElementById("component").addEventListener("change",
        function() {
          changeAssignee("default");
        }, false);
  }

  // Uncheck "set default assignee" when the assignee is changed by other means
  document.getElementById("assigned_to").addEventListener("change",
    function() {
      changeAssignee(null);
    }, false);
}