{"id":146,"date":"2012-01-12T16:50:11","date_gmt":"2012-01-12T20:50:11","guid":{"rendered":"http:\/\/www.joshmatthews.net\/blog\/?p=146"},"modified":"2012-01-12T16:51:42","modified_gmt":"2012-01-12T20:51:42","slug":"answering-questions","status":"publish","type":"post","link":"https:\/\/www.joshmatthews.net\/blog\/2012\/01\/answering-questions\/","title":{"rendered":"Answering questions by looking at code"},"content":{"rendered":"<p>A contributor recently asked a question in #introduction that I couldn&#8217;t answer immediately, but I suspected that I could find the answer without too much work. I also decided to write down the steps I took and the reasons I took them, with the intent of creating a worked example of finding answers in the Firefox code.<\/p>\n<p>The question: <b>how do I determine if a given URI pointing to an RSS feed is subscribed as a live bookmark?<\/b><\/p>\n<p>My first instinct when looking for code I have never touched before is to start with the visible strings in the Firefox interface. In this case, I went to slashdot.org and clicked on the RSS feed button to take me to the RSS feed viewer. Under the options for possible subscriptions, there is the &#8220;Live Bookmarks&#8221; choice. I&#8217;m going to find the code that handles subscribing a live bookmark, which should lead me to the way to find out if a feed is currently subscribed.<\/p>\n<p>So, off to MXR: <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/search?string=Live+Bookmarks&#038;find=&#038;findi=&#038;filter=^[^\\0]*%24&#038;hitlimit=&#038;tree=mozilla-central\" title=\"http:\/\/mxr.mozilla.org\/mozilla-central\/search?string=Live+Bookmarks&#038;find=&#038;findi=&#038;filter=^[^\\0]*%24&#038;hitlimit=&#038;tree=mozilla-central\">http:\/\/mxr.mozilla.org\/mozilla-central\/search?string=Live+Bookmarks&#038;find=&#038;findi=&#038;filter=^[^\\0]*%24&#038;hitlimit=&#038;tree=mozilla-central<\/a><\/p>\n<p>Strings are usually stored in special localized files, where the actual string is referred to by a unique name. In this case, we&#8217;re looking at subscribe.properties, which shows us that some code should be using the name <code>liveBookmarks<\/code> to show the localized string in the feed viewer window.<\/p>\n<p>Let&#8217;s look that up: <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/search?string=livebookmarks&#038;find=&#038;findi=&#038;filter=^[^\\0]*%24&#038;hitlimit=&#038;tree=mozilla-central\n\">http:\/\/mxr.mozilla.org\/mozilla-central\/search?string=livebookmarks&#038;find=&#038;findi=&#038;filter=^[^\\0]*%24&#038;hitlimit=&#038;tree=mozilla-central<\/a><\/p>\n<p>Out of the results, <code>subscribe.xml<\/code> sounds like something I want to read: <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/content\/subscribe.xml#53\">http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/content\/subscribe.xml#53<\/a><\/p>\n<p>Unfortunately, that line turns out to be not very interesting. However, let&#8217;s see what we can find for <code>liveBookmarksMenuItem<\/code>, which sounds like it might be the item for the live bookmarks option in the dropdown: <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/ident?i=liveBookmarksMenuItem\">http:\/\/mxr.mozilla.org\/mozilla-central\/ident?i=liveBookmarksMenuItem<\/a><\/p>\n<p>Let&#8217;s look at FeedWriter.js from the results: <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/src\/FeedWriter.js\">http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/src\/FeedWriter.js<\/a><\/p>\n<p>Woah, that&#8217;s a lot of code!  Let&#8217;s take a step back &#8211; we care about the subscribing action right now. Going back to subscribe.xml (<a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/content\/subscribe.xml\">http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/content\/subscribe.xml<\/a>), notice that the button is called <code>subscribeButton<\/code>. That sounds really useful! Let&#8217;s look in feedwriter.js again for that (just a regular ctr+f operation): <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/src\/FeedWriter.js#859\">http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/src\/FeedWriter.js#859<\/a><\/p>\n<p>Now, let&#8217;s find the function subscribe (ctr+f for <code>subscribe:<\/code>, as that&#8217;s commonly how member functions are defined in the Firefox source): <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/src\/FeedWriter.js#1241\">http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/src\/FeedWriter.js#1241<\/a><\/p>\n<p>Reading the source of <code>subscribe()<\/code>, we come to<br \/>\n<a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/src\/FeedWriter.js#1293>http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/src\/FeedWriter.js#1293<\/a>. This is related to the <code>anonid<\/code> class in <code>subscribe.xml<\/code> that was saw, so we&#8217;re on the right track!<\/p>\n<p>Ooh, further down, there&#8217;s something called a feed service &#8211; that sounds handy. We can find its definition by looking for <code>addToClientReader<\/code> (I just clicked the linked name): <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/ident?i=addToClientReader>http:\/\/mxr.mozilla.org\/mozilla-central\/ident?i=addToClientReader<\/a><\/p>\n<p>We can see the definition of <code>addToClientReader<\/code> at <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/src\/FeedConverter.js#390\">http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/src\/FeedConverter.js#390<\/a>. Let&#8217;s look at what else is defined here &#8211; this seems to be implementing the nsIFeedResultService interface, so we can look up the <code>nsIFeedResultService.idl<\/code> file in MXR: <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/public\/nsIFeedResultService.idl\">http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/public\/nsIFeedResultService.idl<\/a>.<\/p>\n<p>Unfortunately, the service seems to be dealing with actual feed contents, and it doesn&#8217;t look like there&#8217;s a direct function to help us &#8211; let&#8217;s step back and see how <code>addToClientReader<\/code> is implemented.<\/p>\n<p><a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/src\/FeedConverter.js#448\">http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/components\/feeds\/src\/FeedConverter.js#448<\/a> is an important line &#8211; let&#8217;s look at <code>addLiveBookmark<\/code> (I just clicked the name again): <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/ident?i=addLiveBookmark\">http:\/\/mxr.mozilla.org\/mozilla-central\/ident?i=addLiveBookmark<\/a><\/p>\n<p>Take a look at <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/base\/content\/browser-places.js#457\">http:\/\/mxr.mozilla.org\/mozilla-central\/source\/browser\/base\/content\/browser-places.js#457<\/a>.  This shows us how a bookmark dialog is created, but not the actual subscription process. However, the important part is line 471, which shows us the type <code>\"livemark\"<\/code>. Let&#8217;s search for that string and see what other code uses it: <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/search?string=livemark\">http:\/\/mxr.mozilla.org\/mozilla-central\/search?string=livemark<\/a><\/p>\n<p>Woah! There are a lot of results! Since I&#8217;m not certain what I&#8217;m looking for at this point, I find the best thing to do here is to scan all the results quickly, looking for interesting snippets or filenames before opening any particular file. Partway down, there&#8217;s a file called <code>test_bug636917_isLivemark.js<\/code> (<a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/toolkit\/components\/places\/tests\/unit\/test_bug636917_isLivemark.js<\/a>) &#8211; that sounds like something interesting. Since it refers to the <code>PlacesUtils.livemarks.isLivemark<\/code> function, let&#8217;s find the PlacesUtils file: <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/toolkit\/components\/places\/PlacesUtils.jsm\">http:\/\/mxr.mozilla.org\/mozilla-central\/source\/toolkit\/components\/places\/PlacesUtils.jsm<\/a><\/p>\n<p>Searching for <code>livemarks<\/code> in this file, we find line 2234 which defines the <code>livemarks<\/code> object as the <code>nsILivemarkService<\/code> service. Let&#8217;s look that up!<\/p>\n<p>First the idl definition, to see if this service will be useful: <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/toolkit\/components\/places\/nsILivemarkService.idl\">http:\/\/mxr.mozilla.org\/mozilla-central\/source\/toolkit\/components\/places\/nsILivemarkService.idl<\/a>. There&#8217;s a method called <code>getLivemarkIdForFeedURI<\/code> (<a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/toolkit\/components\/places\/nsILivemarkService.idl#107\">http:\/\/mxr.mozilla.org\/mozilla-central\/source\/toolkit\/components\/places\/nsILivemarkService.idl#107<\/a>), which looks to be exactly what we want &#8211; it gives us a -1 result for a non-registered feed and another number for a registered one.<\/p>\n<p>So, to sum up &#8211; we have found a service that will take a URI and return a value that can be used to determine whether a given feed is a subscribed livemark, and we have learned that livemarks are the internal name for Live Bookmarks. The only bit remaining now is to get access to this service, but we can either use <code>PlacesUtils.livemarks<\/code> for that (if we import PlacesUtils.jsm), or just use a normal <code>getService<\/code> call. These are just details; the hard part of answering the original question is complete!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A contributor recently asked a question in #introduction that I couldn&#8217;t answer immediately, but I suspected that I could find the answer without too much work. I also decided to write down the steps I took and the reasons I &hellip; <a href=\"https:\/\/www.joshmatthews.net\/blog\/2012\/01\/answering-questions\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[15],"tags":[],"class_list":["post-146","post","type-post","status-publish","format-standard","hentry","category-mozilla"],"_links":{"self":[{"href":"https:\/\/www.joshmatthews.net\/blog\/wp-json\/wp\/v2\/posts\/146","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.joshmatthews.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.joshmatthews.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.joshmatthews.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.joshmatthews.net\/blog\/wp-json\/wp\/v2\/comments?post=146"}],"version-history":[{"count":3,"href":"https:\/\/www.joshmatthews.net\/blog\/wp-json\/wp\/v2\/posts\/146\/revisions"}],"predecessor-version":[{"id":149,"href":"https:\/\/www.joshmatthews.net\/blog\/wp-json\/wp\/v2\/posts\/146\/revisions\/149"}],"wp:attachment":[{"href":"https:\/\/www.joshmatthews.net\/blog\/wp-json\/wp\/v2\/media?parent=146"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.joshmatthews.net\/blog\/wp-json\/wp\/v2\/categories?post=146"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.joshmatthews.net\/blog\/wp-json\/wp\/v2\/tags?post=146"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}