Updating the Powerline adapters in my home network

I have blogged previously about a couple of problems with using Powerline adapters in my home network:

As my NETGEAR XAV1301 (200 Mbps) Powerline adapters bought in 2012 apparently do not fully support IPv6, and as my NETGEAR XAV5221 (500 Mbps) adapters bought in 2016 are no longer manufactured either, I decided to invest in some new Powerline adapters that would guarantee IPv6 support. My Web searches did not confirm that the current models of NETGEAR Powerline adapters support IPv6, so I decided to try TP-Link Powerline adapters because the TP-Link Web site states that all current TP-Link Powerline adapters support IPv6. I wanted Powerline adapters for five devices (router, smart TV and three computers), plus the ability to use a mains plug on at least two of those (i.e. so-called ‘pass-through’ adapters). I also wanted to avoid buying different models, in order to minimise the possibility of any problems. TP-Link have a range of 600 Mbps adapters under the name ‘AV600’, so I plumped for two TP-PL4010 adapters (single Ethernet port per adapter), one TP-PL4010P adapter (single Ethernet port and one mains pass-through socket) and one TP-PL4020P (two Ethernet ports and one mains pass-through socket). These all use the Qualcomm Atheros QCA7420 Powerline chipset (which happens to be the same chipset used in my old NETGEAR XAV5221 500 Mbps adapters).

Like NETGEAR, TP-Link does not have a Powerline utility program for Linux, so I had to install TP-Link’s tpPLC utility program in Windows 10 running in a VM (virtual machine) in order to configure the four TP-Link adapters and set the ‘Powerline network name’ to avoid crosstalk with my neighbour’s Powerline adapters that use the factory default network name (‘HomePlugAV’).

Anyway, I got everything set up and working, but soon noticed that there were quite frequent dropouts of the connection to my router and the Internet. Some dropouts did occur when I was using the old NETGEAR Powerline adapters, but I was surprised to find that the performance of the new TP-Link adapters was much worse. The dropouts typically lasted a minute or two. This was annoying, to say the least.

I started searching the Web, and ‘TP-Link’ and ‘dropout’ occur together a lot. I had already disabled Power Saving Mode in the adapters, so knew that was not the cause. I happen to know someone who also uses TP-Link adapters, and he mentioned that he also experienced frequent dropouts. In addition to turning off Power Saving Mode, he had implemented a shell script on his machines to ping an Internet site periodically to try and keep the connection from dropping out, but this did not appear to make any difference. I wrote the script below to try the same thing, and it did not cure the dropouts either:

#!/bin/bash
#
# Script to try to keep the Powerline adapter connected to this machine
# from dropping the connection to the router
#
FIRSTPASS=1
PREVIOUS=2
while true
do
    ping -W 2 -c 1 8.8.8.8 >>/dev/null 2>&1
    STATUS=$?
    if [ $PREVIOUS -ne 0 ] && [ $STATUS -eq 0 ]; then
        logger "Ping successful: connection to Internet is up."
#        echo "Ping successful: connection to Internet is up."
    elif [ $PREVIOUS -eq 0 ] && [ $STATUS -ne 0 ]; then
        logger "Ping unsuccessful: connection to Internet may be down."
#        echo "Ping unsuccessful: connection to Internet may be down."
    elif [ $FIRSTPASS -eq 1 ] && [ $STATUS -ne 0 ]; then
        logger "Ping unsuccessful: connection to Internet may be down."
#        echo "Ping unsuccessful: connection to Internet may be down."
    fi
    PREVIOUS=$STATUS
    FIRSTPASS=0
    sleep 10
done

In my Web searches I came across a a thread in the TP-Link SOHO Community forums with a URL for a new version of firmware for TP-Link Powerline adapters that use the Qualcomm Atheros QCA7420 chipset. I learned from the TP-Link forums that the firmware in NVM (Non-Volatile Memory) depends on the chipset manufacturer’s chipset, not on the Powerline manufacturer’s adapter model, whereas the adapter’s PIB (Parameter Information Block) does change depending on the model (including the country). So I started searching online for a PIB file for the three models of TP-Link adapter that I am using, but I could not find them. However, the Linux open-plc-tools command ‘plctool‘ enabled me to read the PIB from each adapter and store it as a file:

user $ sudo plctool -i eth0 -p TL-PA4010P.pib <MAC address printed on the adapter>
user $ sudo plctool -i eth0 -p TL-PA4010_TV.pib <MAC address printed on the adapter>
user $ sudo plctool -i eth0 -p TL-PA4010_HOME-HUB.pib <MAC address printed on the adapter>
user $ sudo plctool -i eth0 -p TL-PA4020P.pib <MAC address printed on the adapter>

The Ethernet interface in the computer I used is named ‘eth0′, so change it accordingly. You can give any name to the PIB files.

It is also easy to find out the adapters’ MAC addresses and current firmware by using another open-plc-tools command:

user $ plcstat -t -i eth0

The TP-Link tpPLC utility for Windows also shows the firmware version. I was surprised to see that the firmware version was different in the three models I had just bought:

  • TL-PA4010P firmware version: 1.4.0.20-00_401115_191120_901
  • TL-PA4010 firmware version: 1.3.1.2141-00_401013_171025_901
  • TL-PA4020P firmware version: 1.4.0.20-00_402114_191120_901

The command to update the firmware in an adapter using the NVM file I downloaded from the URL in the above-mentioned TP-Link Community forum thread and the PIB file read from the relevant adapter, is as follows:

user $ sudo plctool -i <interface> -P <PIB file> -N <NVM file> -R <MAC address of adapter>

For example:

user $ sudo plctool -i eth0 -P TL-PA4010P.pib -N FW-QCA7420-1.5.0.0026-02-CS-20200114.nvm -R 15:B3:D2:D8:5F:BA

I am fortunate in that the three models of TP-Link Powerline adapter I bought all use the Qualcomm Atheros QCA7420 chipset, so I could use the same NVM file for all four adapters that I bought. I only needed to repeat the command with a different PIB file for each adapter model. The plcstat command can be used to check that the firmware version is different from the factory original version:

user $ plcstat -t -i eth0

Actually, the tpPLC utility in Windows 10 also has the ability to upload an NVM file and a PIB file to an adapter, so, as I have tpPLC installed in a VM, I can use that instead to update firmware in my TP-Link Powerline adapters.

And what difference did upgrading the firmware in my new TP-Link adapters make? A big difference. There are no more dropouts; the connection is now stable and I no longer get interruptions while browsing the Internet. It’s a pity that TP-Link does not supply every chipset’s latest firmware file and every model’s PIB file on their support Web site so that users can update their Powerline adapters.

Jitsi Meet, my favourite video conferencing platform (and a way to share audio when using it in Linux)

During the current COVID-19 lockdown I have been using video conferencing platforms a lot for family virtual meet-ups, quizzes and multi-player games by Jackbox Games. Zoom seems to be the most popular video conference platform at the moment, although several articles in the media have pointed out some of its security limitations (see, e.g., ‘‘Zoom is malware’: why experts worry about the video conferencing platform‘). Although many people like Zoom, my favourite video conferencing platform is Jitsi Meet.

For an excellent third-party video introduction to Jitsi Meet, watch the video: ‘Using Jitsi: A free, no-registration video conferencing site‘. WIRED Magazine’s recent article on Jitsi Meet is also worth reading: ‘Want to Ditch Zoom? Jitsi Offers an Open-Source Alternative‘.

The reasons I prefer Jitsi Meet to Zoom include the following:

  1. no subscriptions are required to use all the features of Jitsi Meet;
  2. unlike Zoom, Jitsi Meet does not require you to sign up;
  3. unlike Zoom, Jitsi Meet does not require the installation of an application — it runs in Google Chrome or Firefox;
  4. unlike the free version of Zoom, Jitsi Meet does not impose a time limit on the length of the meeting;
  5. unlike the free version of Zoom, Jitsi Meet does not have a limit on the number of meeting attendees;
  6. Jitsi Meet provides end-to-end encryption for one-to-one video calls*;
  7. I find the performance of Jitsi Meet better than Zoom, which seems to be corroborated in basic benchmarking by Jitsi Meet’s developers (‘WebRTC vs. Zoom – A Simple Congestion Test‘);
  8. I find image quality better in Jitsi Meet;
  9. I find Jitsi Meet on a desktop/laptop more intuitive and easier to use than Zoom;
  10. if I share audio in Zoom for Linux, the audio is very distorted**;
  11. I find the UI of the Jitsi Meet app for Android easy to use (the app can be installed via Google Play);
  12. Jitsi Meet is open-source, so anyone can inspect the source code;
  13. if I wanted to, I could download the Jitsi software to my own server and set up a Jitsi Meet server to handle meetings instead of using the Cloud server provided by 8×8, Inc. (the company that develops the Jitsi Meetings software).

* Neither platform currently provides end-to-end encryption for group meetings, although the developers of Jitsi Meet are apparently working on implementing end-to-end encryption for group meetings using a new feature of Google Chrome called ‘Insertable Streams’.

** There is a work-around for this problem in Zoom for Linux; see my answer to the Unix & Linux Stack Exchange question ‘Play audio output as input to Zoom’. In the case of Jitsi Meet in Linux, PulseAudio Volume Control can be used to share audio, as I explain further down.

Jitsi Meet requires no installation; it runs in a browser window. Either Google Chrome or Firefox can be used, although I find it runs better in Google Chrome. Actually, an Ubuntu 16.04 user told me that Firefox hangs when he tries to join a Jitsi Meet meeting, but Jitsi Meet works fine in Firefox in my two Gentoo Linux installations and in my family’s Lubuntu 18.04 installation. When using Google Chrome, to be able to share your screen you need to install the Google Chrome extension ‘Jitsi Meetings’ by meet.ji.si in the Google Chrome Web Store.

One of my family here at home has a laptop running Windows 10. Google Chrome, but not Firefox, displays a ‘Share audio’ tick box when the ‘Share your screen’ icon is clicked (see ‘Jitsi Meet features update, April 2020‘). The ‘Share audio’ feature is needed when, for example, you are casting via the Internet to remote players a multi-user game running on your machine. During the current COVID-19 lockdown we have been having fun playing Jackbox Games Party Pack 6 this way with family and friends in different locations (see ‘(My Solution) Best method for Virtual Couch Multiplayer‘). Each household connects a laptop to their TV via HDMI and joins the Jitsi Meet meeting. The Jackbox Games games are cast via Jitsi Meet from the laptop at my house, and the group of players in each household can view and hear the game on their TV and participate using their mobile phones as per the Jackbox Games paradigm.

Jitsi Meet provides a ‘Share audio’ function in Windows only, but I found a work-around to to be able to share any application’s audio in Linux if I ever want to use my Linux machines to cast games by Jackbox Games or other suppliers. For once, I have found PulseAudio useful! I use PulseAudio Volume Control to redirect the audio output from the desired application (be it a game, music player, video player or whatever) to the microphone input. The precise way to do this depends on the audio hardware your machine has, but an example is given in the blog post: ‘Redirect Audio Out to Mic In (Linux)‘.

My family’s desktop machine running Lubuntu 18.04 uses a Webcam with an integral microphone connected via USB, and external powered speakers connected to the machine’s Line Out green-coloured 3.5 mm jack socket. The contents of the tabs in PulseAudio Volume Control when no applications that produce audio are running are shown in the following screenshots:

PulseAudio Volume Control - Configuration

PulseAudio Volume Control - Playback

PulseAudio Volume Control - Recording

PulseAudio Volume Control - Output Devices

PulseAudio Volume Control - Input Devices

I make sure ‘All Streams’ is selected on the ‘Playback’ and ‘Recording’ tabs, ‘All Output Devices’ is selected on the ‘Output Devices’ tab, and ‘All Input Devices’ is selected on the ‘Input Devices’ tab.

Let us say I have launched Audacious to play some music and I want to cast that music to members of a Jitsi Meet meeting. When I am using Jitsi Meet for a meeting in Google Chrome, the contents of the PulseAudio Volume Control tabs on this machine are as follows:

PulseAudio Volume Control - Playback

PulseAudio Volume Control - Recording

PulseAudio Volume Control - Output Devices

PulseAudio Volume Control - Input Devices

To redirect the audio from e.g. Audacious to the meeting members, I select (click on the square button with the green disc and white tick) ‘Monitor of Built-in Audio Analogue Stereo’ on the ‘Input Devices’ tab, and on the ‘Recording’ tab I click on Chrome input: RecordStream from ‘Camera Analogue Mono’ and select Chrome input: RecordStream from ‘Monitor of Built-in Audio Analogue Stereo’, as shown below.

PulseAudio Volume Control - Recording

PulseAudio Volume Control - Input Devices

With the above settings in PulseAudio volume control, all the members of the meeting will be able to hear clearly the audio from Audacious. To switch back to my microphone to speak, I simply click on Chrome input: RecordStream from ‘Monitor of Built-in Audio Analogue Stereo’ on the ‘Recording’ tab and select Chrome input: RecordStream from ‘Camera Analogue Mono’ again.

Using Bash scripts in Linux to delete the history, cookies and cache files of Firefox, Google Chrome and Thunderbird

The browsing data stored by Firefox, Google Chrome and Thunderbird can be deleted using the respective application’s GUI. But you can also do that using a Bash script, which could be useful if you want to delete unnecessary/unwanted files before e.g. backing up your home directory, or if you want a quick and easy way to clear-out browsing data. In this post I list the scripts and Desktop Configuration files I have created in Gentoo Linux and in Lubuntu 18.04 to remove browsing data.

In the case of Thunderbird, I am not sure if it is safe to delete Thunderbird’s cache files so my script only deletes cookies. Anyway, that could be added later if it transpires there is no harm in deleting Thunderbird’s cache files.

I am using the following 64-bit versions of the two browsers and e-mail client:

  • Mozilla Firefox 74.0
  • Mozilla Thunderbird 68.5.0 in Gentoo Linux only
  • Google Chrome 80.0.3987.132 in Gentoo Linux
  • Google Chrome 67.0.3396.99 in Lubuntu 18.04

I have not tested my scripts with other versions of Firefox, Chrome and Thunderbird, nor in other installations, so please do check carefully the directory paths and commands in the script against the directory paths in your installation before selecting ‘[D]elete‘ in the running script.

In Lubuntu 18.04 I had to install sqlite3 first:

$ sudo apt install sqlite3

In Gentoo Linux it was already installed:

$ eix -I sqlite
[I] dev-db/sqlite
     Available versions:  (3) 3.29.0^t 3.30.1^t 3.31.1^t
       {debug doc icu +readline secure-delete static-libs tcl test tools ABI_MIPS="n32 n64 o32" ABI_RISCV="lp64 lp64d" ABI_S390="32 64" ABI_X86="32 64 x32"}
     Installed versions:  3.31.1(3)^t(19:53:28 13/03/20)(icu readline secure-delete -debug -doc -static-libs -tcl -test -tools ABI_MIPS="-n32 -n64 -o32" ABI_RISCV="-lp64 -lp64d" ABI_S390="-32 -64" ABI_X86="32 64 -x32")
     Homepage:            https://sqlite.org/
     Description:         SQL database engine

Firefox and Thunderbird

I created the Bash script Firefox_or_Thunderbird_-_Clear_data.sh listed below. The user can select only Firefox or only Thunderbird, or both, and the script enables the user to choose whether to just view the current situation or to delete the data. The script checks if the applications are running and will not do anything if they are. In fact, the script offers the user the option to terminate the applications if they happen to be running. The script is still usable if either Firefox or Thunderbird are not installed. The same script can be used in Gentoo and in Lubuntu 18.04, and I believe it would also work in Ubuntu but have not tested it with that distribution.

#!/bin/bash
#
# If Delete is selected for Firefox, this script deletes the entire history, cookies, site data and cache.
# If Delete is selected for Thunderbird, this script deletes the cookies and leaves the cache intact.
#
echo
echo "WARNING:"
echo "The Firefox Browser must not be running if you are going to list or delete its data files."
echo "The Thunderbird e-mail client must not be running if you are going to list or delete its data files."
echo
FIREFOX=$( ls $HOME/.mozilla/firefox 2>/dev/null | grep .default )
THUNDERBIRD=$( ls $HOME/.thunderbird 2>/dev/null | grep .default )
while true
do
   echo -n "[F]irefox, [T]hunderbird, [B]oth or [E]xit: "
   read -n1 PROMPT2
   echo
   case $PROMPT2 in
      [fF]* ) CHOICE2="F"; break;;
      [tT]* ) CHOICE2="T"; break;;
      [bB]* ) CHOICE2="B"; break;;
      [eE]* ) exit;;
      * )     echo "Invalid entry.";;
   esac
done
FRUNNING="N"
pgrep -u $USER firefox > /dev/null
if [[ $? -eq 0 ]]; then
   FRUNNING="Y"
   while true
   do
      echo
      echo -n "The Firefox browser is running. Do you wish to close it now? [Y/N]: "
      read -n1 PROMPT0
      echo
      case $PROMPT0 in
         [yY]* ) CHOICE0="Y"; break;;
         [nN]* ) CHOICE0="N"; break;;
         * )     echo "Invalid entry.";;
      esac
   done
   if [[ $CHOICE0 == "Y" ]]; then
      FPID=$( pgrep -u $USER firefox )
      FPID=$( echo $FPID | cut -d" " -f1 )
      kill -1 $FPID
      FRUNNING="N"
   fi
fi
TRUNNING="N"
pgrep -u $USER thunderbird > /dev/null
if [[ $? -eq 0 ]]; then
   TRUNNING="Y"
   while true
   do
      echo -n "The Thunderbird e-mail client is running. Do you wish to close it now? [Y/N]: "
      read -n1 PROMPT1
      echo
      case $PROMPT1 in
         [yY]* ) CHOICE1="Y"; break;;
         [nN]* ) CHOICE1="N"; break;;
         * )     echo "Invalid entry.";;
      esac
   done
   if [[ $CHOICE1 == "Y" ]]; then
      FPID=$( pgrep -u $USER thunderbird )
      FPID=$( echo $FPID | cut -d" " -f1 )
      kill -1 $FPID
      TRUNNING="N"
   fi
fi
ABORT="N"
if [[ $FRUNNING == "Y" ]]; then
   if [[ $CHOICE2 == "F" ]] || [[ $CHOICE2 == "B" ]]; then
      echo
      echo "Please quit Firefox then re-run this script."
      echo
      ABORT="Y"
   fi
fi
if [[ $TRUNNING == "Y" ]]; then
   if [[ $CHOICE2 == "T" ]] || [[ $CHOICE2 == "B" ]]; then
      echo
      echo "Please quit Thunderbird then re-run this script."
      echo
      ABORT="Y"
   fi
fi
if [[ $ABORT == "N" ]]; then
   while true
   do
      echo
      echo -n "[D]elete, [L]ist or [E]xit: "
      read -n1 PROMPT3
      echo
      case $PROMPT3 in
         [dD]* ) CHOICE3="D"; break;;
         [lL]* ) CHOICE3="L"; break;;
         [eE]* ) exit;;
         * )     echo "Invalid entry.";;
      esac
   done
   if [[ $CHOICE3 == "D" ]]; then
      if [[ $CHOICE2 == "F" ]] || [[ $CHOICE2 == "B" ]]; then
         if [ -z "$FIREFOX" ]; then
            echo "Firefox directory does not exist"
         else
            echo
            echo "Deleting Firefox History..........."
            echo "==================================="
            sqlite3 ${HOME}/.mozilla/firefox/${FIREFOX}/places.sqlite "SELECT datetime(moz_historyvisits.visit_date/1000000,'unixepoch'), moz_places.url FROM moz_places, moz_historyvisits WHERE moz_places.id = moz_historyvisits.place_id;"
            sqlite3 ${HOME}/.mozilla/firefox/${FIREFOX}/places.sqlite "delete from moz_historyvisits;"
            echo
            echo "Deleting Firefox Cookies........"
            echo "================================"
            sqlite3 ${HOME}/.mozilla/firefox/${FIREFOX}/cookies.sqlite "select datetime(creationTime/1000000,'unixepoch'),host from moz_cookies; delete from moz_cookies;"
            echo
            echo "Deleting Firefox Site Data........"
            echo "=================================="
            ls ${HOME}/.mozilla/firefox/${FIREFOX}/storage/default/ | grep http
            find ${HOME}/.mozilla/firefox/${FIREFOX}/storage/default -name "http*" -type d -exec rm -r "{}" \; -prune
            echo
            echo "Deleting Firefox Cache..........."
            echo "================================="
            NUM=$( ls -1 ${HOME}/.cache/mozilla/firefox/${FIREFOX}/cache2/entries | wc -l )
            SIZ=$( du -sbh ${HOME}/.cache/mozilla/firefox/${FIREFOX}/cache2/entries )
            SIZ=$( echo $SIZ | cut -d" " -f1 )
            echo "Files: $NUM Size: $SIZ"
            find ${HOME}/.cache/mozilla/firefox/${FIREFOX}/cache2/entries -type f -delete 2>/dev/null
            echo
         fi
      fi
      if [[ $CHOICE2 == "T" ]] || [[ $CHOICE2 == "B" ]]; then
         if [ -z "$THUNDERBIRD" ]; then
            echo "Thunderbird directory does not exist"
         else
            echo "Deleting Thunderbird Cookies........"
            echo "===================================="
            sqlite3 ${HOME}/.thunderbird/${THUNDERBIRD}/cookies.sqlite "select datetime(creationTime/1000000,'unixepoch'),host from moz_cookies; delete from moz_cookies;"
         fi
      fi
   fi
   if [[ $CHOICE3 == "L" ]]; then
      if [[ $CHOICE2 == "F" ]] || [[ $CHOICE2 == "B" ]]; then
         if [ -z "$FIREFOX" ]; then
            echo "Firefox directory does not exist"
         else
            echo
            echo "Current Firefox History........."
            echo "================================"
            sqlite3 ${HOME}/.mozilla/firefox/${FIREFOX}/places.sqlite "SELECT datetime(moz_historyvisits.visit_date/1000000,'unixepoch'), moz_places.url FROM moz_places, moz_historyvisits WHERE moz_places.id = moz_historyvisits.place_id;" | more
            echo
            echo "Current Firefox Cookies........"
            echo "==============================="
            sqlite3 ${HOME}/.mozilla/firefox/${FIREFOX}/cookies.sqlite "select datetime(creationTime/1000000,'unixepoch'),host from moz_cookies;" | more
            echo
            echo "Current Firefox Site Data........"
            echo "================================="
            ls ${HOME}/.mozilla/firefox/${FIREFOX}/storage/default/ | grep http | more
            echo
            echo "Current Firefox Cache..........."
            echo "================================="
            NUM=$( ls -1 ${HOME}/.cache/mozilla/firefox/${FIREFOX}/cache2/entries | wc -l )
            SIZ=$( du -sbh ${HOME}/.cache/mozilla/firefox/${FIREFOX}/cache2/entries )
            SIZ=$( echo $SIZ | cut -d" " -f1 )
            echo "Files: $NUM Size: $SIZ"
            echo
         fi
      fi
      if [[ $CHOICE2 == "T" ]] || [[ $CHOICE2 == "B" ]]; then
         if [ -z "$THUNDERBIRD" ]; then
            echo "Thunderbird directory does not exist"
         else
            echo "Current Thunderbird Cookies......"
            echo "================================="
            sqlite3 ${HOME}/.thunderbird/${THUNDERBIRD}/cookies.sqlite "select datetime(creationTime/1000000,'unixepoch'),host from moz_cookies;" | more
         fi
      fi
   fi
fi
printf "\n"
read -rep $'\n Press ENTER to exit ' PROMPT4

Listed below is the Desktop Configuration file Firefox_or_Thunderbird_-_Clear_data.desktop for KDE in Gentoo Linux that I created in the ~/Desktop/ directory. I downloaded a nice PNG icon from the Web, which I saved as ~/Pictures/Icons/Mozilla.png, although of course the Desktop Configuration file can be modified if the icon file were to be stored elsewhere. Obviously change the username accordingly.

[Desktop Entry]
Comment[en_GB]=Clear Firefox or Thunderbird caches and cookies
Comment=Clear Firefox or Thunderbird caches and cookies
Exec=/home/fitzcarraldo/Firefox_or_Thunderbird_-_Clear_data.sh
GenericName[en_GB]=Clear Firefox or Thunderbird caches and cookies
GenericName=Clear Firefox or Thunderbird caches and cookies
Icon=/home/fitzcarraldo/Pictures/Icons/Mozilla.png
MimeType=
Name[en_GB]=Firefox_or_Thunderbird_-_Clear_data
Name=Firefox_or_Thunderbird_-_Clear_data
Path=/home/fitzcarraldo
StartupNotify=true
Terminal=true
TerminalOptions=
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=none
X-KDE-SubstituteUID=false
X-KDE-Username=fitzcarraldo

The equivalent Desktop Configuration file I created for Lubuntu 18.04 is very similar:

[Desktop Entry]
Comment[en_GB]=Clear Firefox or Thunderbird caches and cookies
Comment=Clear Firefox or Thunderbird caches and cookies
Exec=/home/fitzcarraldo/Firefox_or_Thunderbird_-_Clear_data.sh
GenericName[en_GB]=Clear Firefox or Thunderbird caches and cookies
GenericName=Clear Firefox or Thunderbird caches and cookies
Icon=/home/fitzcarraldo/Pictures/Icons/Mozilla.png
MimeType=
Name[en_GB]=Firefox_or_Thunderbird_-_Clear_data
Name=Firefox_or_Thunderbird_-_Clear_data
Path=/home/fitzcarraldo
StartupNotify=true
Terminal=true
TerminalOptions=\s--noclose
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=none
X-LXDE-SubstituteUID=false
X-LXDE-Username=fitzcarraldo

Google Chrome

I created the following Bash script Google-Chrome_-_Clear_data.sh for the Google Chrome browser in Gentoo Linux. Different scripts have to be used in Gentoo Linux and in Lubuntu 18.04 because the paths are different.

#!/bin/bash
#
# If Delete is selected, this script deletes the entire cache, the code cache,
# the Visited Links file and the Top Sites file.
#
echo
echo "WARNING:"
echo "The Google Chrome browser must not be running if you are going to list or delete its data files."
echo
while true
do
   echo -n "[D]elete, [L]ist or [E]xit: "
   read -n1 PROMPT1
   echo
   case $PROMPT1 in
      [dD]* ) CHOICE1="D"; break;;
      [lL]* ) CHOICE1="L"; break;;
      [eE]* ) exit;;
      * )     echo "Invalid entry.";;
   esac
done
CRUNNING="N"
pgrep -u $USER chrome > /dev/null
if [[ $? -eq 0 ]]; then
   CRUNNING="Y"
   while true
   do
      echo
      echo -n "The Google Chrome browser is running. Do you wish to close it now? [Y/N]: "
      read -n1 PROMPT0
      echo
      case $PROMPT0 in
         [yY]* ) CHOICE0="Y"; break;;
         [nN]* ) CHOICE0="N"; break;;
         * )     echo "Invalid entry.";;
      esac
   done
   if [[ $CHOICE0 == "Y" ]]; then
      FPID=$( pgrep -u $USER chrome )
      FPID=$( echo $FPID | cut -d" " -f1 )
      kill -1 $FPID
      CRUNNING="N"
   fi
fi
if [[ $CRUNNING == "Y" ]]; then
   echo
   echo "Please quit Google Chrome then re-run this script."
   echo
else
   if [[ $CHOICE1 == "D" ]]; then
      echo
      echo "Deleting URLs..........."
      echo "========================"
      sqlite3 ${HOME}/.config/google-chrome/Profile\ 2/History "select datetime(last_visit_time/1000000 + (strftime('%s', '1601-01-01')),'unixepoch'),url from urls; delete from urls;"
      echo
      echo "Deleting Cookies........"
      echo "========================"
      sqlite3 ${HOME}/.config/google-chrome/Profile\ 2/Cookies "select datetime(creation_utc/1000000 + (strftime('%s', '1601-01-01')),'unixepoch'),host_key from cookies; delete from cookies;"
      if [[ -d ${HOME}/.cache/google-chrome/Profile\ 2/Cache ]]; then
         echo
         echo "Deleting Chrome Cache......."
         echo "====================="
         NUM=$( ls -1 ${HOME}/.cache/google-chrome/Profile\ 2/Cache | wc -l )
         SIZ=$( du -sbh ${HOME}/.cache/google-chrome/Profile\ 2/Cache )
         SIZ=$( echo $SIZ | cut -d" " -f1 )
         echo "Files: $NUM Size: $SIZ"
         rm -r ${HOME}/.cache/google-chrome/Profile\ 2/Cache
      fi
      if [[ -d ${HOME}/.cache/google-chrome/Profile\ 2/Code\ Cache ]]; then
         echo
         echo "Deleting Code Cache......"
         echo "========================="
         rm -r ${HOME}/.cache/google-chrome/Profile\ 2/Code\ Cache
      fi
      if [[ -f ${HOME}/.config/google-chrome/Profile\ 2/Visited\ Links ]]; then
         echo
         echo "Deleting Visited Links......"
         echo "============================"
         rm ${HOME}/.config/google-chrome/Profile\ 2/Visited\ Links
      fi
      if [[ -f ${HOME}/.config/google-chrome/Profile\ 2/Top\ Sites ]]; then
         echo
         echo "Deleting Top Sites......"
         echo "========================"
         rm ${HOME}/.config/google-chrome/Profile\ 2/Top\ Sites
      fi
   fi
   if [[ $CHOICE1 == "L" ]]; then
      echo
      echo "Current URLs..........."
      echo "======================="
      sqlite3 ${HOME}/.config/google-chrome/Profile\ 2/History "select datetime(last_visit_time/1000000 + (strftime('%s', '1601-01-01')),'unixepoch'),url from urls;" | more
      echo
      echo "Current Cookies........"
      echo "======================="
      sqlite3 ${HOME}/.config/google-chrome/Profile\ 2/Cookies "select datetime(creation_utc/1000000 + (strftime('%s', '1601-01-01')),'unixepoch'),host_key from cookies;" | more
      if [[ -d ${HOME}/.cache/google-chrome/Profile\ 2/Cache ]]; then
         echo
         echo "Current Chrome Cache............."
         echo "================================="
         NUM=$( ls -1 ${HOME}/.cache/google-chrome/Profile\ 2/Cache | wc -l )
         SIZ=$( du -sbh ${HOME}/.cache/google-chrome/Profile\ 2/Cache )
         SIZ=$( echo $SIZ | cut -d" " -f1 )
         echo "Files: $NUM Size: $SIZ"
      fi
   fi
fi
printf "\n"
read -rep $'\n Press ENTER to exit ' PROMPT2

And below is the Desktop Configuration file Google-Chrome_-_Clear_data.desktop for Gentoo Linux. I downloaded a nice PNG icon from the Web, which I saved as ~/Pictures/Icons/Google-Chrome.png, although of course the Desktop Configuration file can be adjusted if the icon file were stored elsewhere. Obviously change the username accordingly.

[Desktop Entry]
Comment[en_GB]=Clear Google Chrome cache and cookies
Comment=Clear Google Chrome cache and cookies
Exec=/home/fitzcarraldo/Google-Chrome_-_Clear_data.sh
GenericName[en_GB]=Clear Google Chrome cache and cookies
GenericName=Clear Google Chrome cache and cookies
Icon=/home/fitzcarraldo/Pictures/Icons/Google-Chrome.png
MimeType=
Name[en_GB]=Google-Chrome_-_Clear_data
Name=Google-Chrome_-_Clear_data
Path=/home/fitzcarraldo
StartupNotify=true
Terminal=true
TerminalOptions=
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=none
X-KDE-SubstituteUID=false
X-KDE-Username=

Below is the version of the script Google-Chrome_-_Clear_data.sh for Lubuntu 18.04:

#!/bin/bash
#
# If Delete is selected, this script deletes the entire cache, the code cache,
# the Visited Links file and the Top Sites file.
#
echo
echo "WARNING:"
echo "The Google Chrome browser must not be running if you are going to list or delete its data files."
echo
while true
do
   echo -n "[D]elete, [L]ist or [E]xit: "
   read -n1 PROMPT1
   echo
   case $PROMPT1 in
      [dD]* ) CHOICE1="D"; break;;
      [lL]* ) CHOICE1="L"; break;;
      [eE]* ) exit;;
      * )     echo "Invalid entry.";;
   esac
done
CRUNNING="N"
pgrep -u $USER chrome > /dev/null
if [[ $? -eq 0 ]]; then
   CRUNNING="Y"
   while true
   do
      echo
      echo -n "The Google Chrome browser is running. Do you wish to close it now? [Y/N]: "
      read -n1 PROMPT0
      echo
      case $PROMPT0 in
         [yY]* ) CHOICE0="Y"; break;;
         [nN]* ) CHOICE0="N"; break;;
         * )     echo "Invalid entry.";;
      esac
   done
   if [[ $CHOICE0 == "Y" ]]; then
      FPID=$( pgrep -u $USER chrome )
      FPID=$( echo $FPID | cut -d" " -f1 )
      kill -1 $FPID
      CRUNNING="N"
   fi
fi
if [[ $CRUNNING == "Y" ]]; then
   echo
   echo "Please quit Google Chrome then re-run this script."
   echo
else
   if [[ $CHOICE1 == "D" ]]; then
      echo
      echo "Deleting URLs..........."
      echo "========================"
      sqlite3 ${HOME}/.config/google-chrome/Default/History "select datetime(last_visit_time/1000000 + (strftime('%s', '1601-01-01')),'unixepoch'),url from urls; delete from urls;"
      echo
      echo "Deleting Cookies........"
      echo "========================"
      sqlite3 ${HOME}/.config/google-chrome/Default/Cookies "select datetime(creation_utc/1000000 + (strftime('%s', '1601-01-01')),'unixepoch'),host_key from cookies; delete from cookies;"
      if [[ -d ${HOME}/.cache/google-chrome/Default/Cache ]]; then
         echo
         echo "Deleting Chrome Cache......."
         echo "====================="
         NUM=$( ls -1 ${HOME}/.cache/google-chrome/Default/Cache | wc -l )
         SIZ=$( du -sbh ${HOME}/.cache/google-chrome/Default/Cache )
         SIZ=$( echo $SIZ | cut -d" " -f1 )
         echo "Files: $NUM Size: $SIZ"
         rm -r ${HOME}/.cache/google-chrome/Default/Cache
      fi
      if [[ -d ${HOME}/.cache/google-chrome/Default/Code\ Cache ]]; then
         echo
         echo "Deleting Code Cache......"
         echo "========================="
         rm -r ${HOME}/.cache/google-chrome/Default/Code\ Cache
      fi
      if [[ -f ${HOME}/.config/google-chrome/Default/Visited\ Links ]]; then
         echo
         echo "Deleting Visited Links......"
         echo "============================"
         rm ${HOME}/.config/google-chrome/Default/Visited\ Links
      fi
      if [[ -f ${HOME}/.config/google-chrome/Default/Top\ Sites ]]; then
         echo
         echo "Deleting Top Sites......"
         echo "========================"
         rm ${HOME}/.config/google-chrome/Default/Top\ Sites
      fi
   fi
   if [[ $CHOICE1 == "L" ]]; then
      echo
      echo "Current URLs..........."
      echo "======================="
      sqlite3 ${HOME}/.config/google-chrome/Default/History "select datetime(last_visit_time/1000000 + (strftime('%s', '1601-01-01')),'unixepoch'),url from urls;" | more
      echo
      echo "Current Cookies........"
      echo "======================="
      sqlite3 ${HOME}/.config/google-chrome/Default/Cookies "select datetime(creation_utc/1000000 + (strftime('%s', '1601-01-01')),'unixepoch'),host_key from cookies;" | more
      if [[ -d ${HOME}/.cache/google-chrome/Default/Cache ]]; then
         echo
         echo "Current Chrome Cache............."
         echo "================================="
         NUM=$( ls -1 ${HOME}/.cache/google-chrome/Default/Cache | wc -l )
         SIZ=$( du -sbh ${HOME}/.cache/google-chrome/Default/Cache )
         SIZ=$( echo $SIZ | cut -d" " -f1 )
         echo "Files: $NUM Size: $SIZ"
      fi
   fi
fi
printf "\n"
read -rep $'\n Press ENTER to exit ' PROMPT2

And below is the Desktop Configuration file Google-Chrome_-_Clear_data.desktop for Lubuntu 18.04. I downloaded a nice PNG icon from the Web, which I saved as ~/Pictures/Icons/Google-Chrome.png, although of course the Desktop Configuration file can be adjusted if the icon file were stored elsewhere. Obviously change the username accordingly.

[Desktop Entry]
Comment[en_GB]=Clear Google Chrome cache and cookies
Comment=Clear Google Chrome cache and cookies
Exec=/home/fitzcarraldo/Google-Chrome_-_Clear_data.sh
GenericName[en_GB]=Clear Google Chrome cache and cookies
GenericName=Clear Google Chrome cache and cookies
Icon=/home/fitzcarraldo/Pictures/Icons/Google-Chrome.png
MimeType=
Name[en_GB]=Google-Chrome_-_Clear_data
Name=Google-Chrome_-_Clear_data
Path=/home/fitzcarraldo
StartupNotify=true
Terminal=true
TerminalOptions=\s--noclose
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=none
X-LXDE-SubstituteUID=false
X-LXDE-Username=fitzcarraldo

Below are a few examples of the output when I launch the scripts.

Here is the output of the script that deals with Firefox and/or Thunderbird when I only list the current situation:


WARNING:
The Firefox Browser must not be running if you are going to list or delete its data files.
The Thunderbird e-mail client must not be running if you are going to list or delete its data files.
 
[F]irefox, [T]hunderbird, [B]oth or [E]xit: b 
 
The Firefox browser is running. Do you wish to close it now? [Y/N]: y 
The Thunderbird e-mail client is running. Do you wish to close it now? [Y/N]: y 
 
[D]elete, [L]ist or [E]xit: l 
 
Current Firefox History.........
================================
2020-03-19 17:27:24|https://www.accuweather.com/en/gb/united-kingdom-weather
2020-03-19 17:27:20|https://www.youtube.com/
2020-03-19 17:27:30|https://www.theguardian.com/uk
2020-03-19 17:27:38|http://www.jb.com.br/
2020-03-19 17:27:38|https://www.jb.com.br/
 
Current Firefox Cookies........
===============================
2020-03-19 17:27:20|.youtube.com
2020-03-19 17:27:20|.youtube.com
2020-03-19 17:27:20|.youtube.com
2020-03-19 17:27:22|accounts.google.com
2020-03-19 17:27:23|.doubleclick.net
2020-03-19 17:27:24|www.accuweather.com
2020-03-19 17:27:24|.accuweather.com
2020-03-19 17:27:24|.google.com
2020-03-19 17:27:24|www.accuweather.com
2020-03-19 17:27:24|www.accuweather.com
2020-03-19 17:27:25|www.accuweather.com
2020-03-19 17:27:25|.accuweather.com
2020-03-19 17:27:24|.accuweather.com
2020-03-19 17:27:25|www.accuweather.com
2020-03-19 17:27:30|.theguardian.com
2020-03-19 17:27:36|.theguardian.com
2020-03-19 17:27:36|.theguardian.com
2020-03-19 17:27:39|.denakop.com
2020-03-19 17:27:43|www.jb.com.br
2020-03-19 17:27:43|www.jb.com.br
2020-03-19 17:27:43|www.jb.com.br
2020-03-19 17:27:43|www.jb.com.br
2020-03-19 17:27:43|www.jb.com.br
2020-03-19 17:27:43|.tt-10969-0.seg.t.tailtarget.com
2020-03-19 17:27:43|.t.tailtarget.com
2020-03-19 17:27:44|www.jb.com.br
2020-03-19 17:27:44|.t.tailtarget.com
2020-03-19 17:27:44|.t.tailtarget.com
2020-03-19 17:27:44|.t.tailtarget.com
2020-03-19 17:27:43|.t.tailtarget.com
2020-03-19 17:27:44|www.jb.com.br
2020-03-19 17:27:44|.tt-10969-0.seg.t.tailtarget.com
2020-03-19 17:27:44|.t.tailtarget.com
2020-03-19 17:27:46|www.jb.com.br
2020-03-19 17:27:46|.www.jb.com.br
2020-03-19 17:27:43|www.jb.com.br
2020-03-19 17:27:43|www.jb.com.br
 
Current Firefox Site Data........
=================================
https+++www.google.com
https+++www.theguardian.com
https+++www.youtube.com
 
Current Firefox Cache...........
=================================
Files: 383 Size: 15M
 
Current Thunderbird Cookies......
=================================


 Press ENTER to exit

Here is the output of the script that deals with Firefox and/or Thunderbird when I delete only the Firefox data:

 
WARNING:
The Firefox Browser must not be running if you are going to list or delete its data files.
The Thunderbird e-mail client must not be running if you are going to list or delete its data files.
 
[F]irefox, [T]hunderbird, [B]oth or [E]xit: f 
 
[D]elete, [L]ist or [E]xit: d 
 
Deleting Firefox History...........
===================================
2020-03-19 17:27:24|https://www.accuweather.com/en/gb/united-kingdom-weather
2020-03-19 17:27:20|https://www.youtube.com/
2020-03-19 17:27:30|https://www.theguardian.com/uk
2020-03-19 17:27:38|http://www.jb.com.br/
2020-03-19 17:27:38|https://www.jb.com.br/
 
Deleting Firefox Cookies........
================================
2020-03-19 17:27:20|.youtube.com
2020-03-19 17:27:20|.youtube.com
2020-03-19 17:27:20|.youtube.com
2020-03-19 17:27:22|accounts.google.com
2020-03-19 17:27:23|.doubleclick.net
2020-03-19 17:27:24|www.accuweather.com
2020-03-19 17:27:24|.accuweather.com
2020-03-19 17:27:24|.google.com
2020-03-19 17:27:24|www.accuweather.com
2020-03-19 17:27:24|www.accuweather.com
2020-03-19 17:27:25|www.accuweather.com
2020-03-19 17:27:25|.accuweather.com
2020-03-19 17:27:24|.accuweather.com
2020-03-19 17:27:25|www.accuweather.com
2020-03-19 17:27:30|.theguardian.com
2020-03-19 17:27:36|.theguardian.com
2020-03-19 17:27:36|.theguardian.com
2020-03-19 17:27:39|.denakop.com
2020-03-19 17:27:43|www.jb.com.br
2020-03-19 17:27:43|www.jb.com.br
2020-03-19 17:27:43|www.jb.com.br
2020-03-19 17:27:43|www.jb.com.br
2020-03-19 17:27:43|www.jb.com.br
2020-03-19 17:27:43|.tt-10969-0.seg.t.tailtarget.com
2020-03-19 17:27:43|.t.tailtarget.com
2020-03-19 17:27:44|www.jb.com.br
2020-03-19 17:27:44|.t.tailtarget.com
2020-03-19 17:27:44|.t.tailtarget.com
2020-03-19 17:27:44|.t.tailtarget.com
2020-03-19 17:27:43|.t.tailtarget.com
2020-03-19 17:27:44|www.jb.com.br
2020-03-19 17:27:44|.tt-10969-0.seg.t.tailtarget.com
2020-03-19 17:27:44|.t.tailtarget.com
2020-03-19 17:27:46|www.jb.com.br
2020-03-19 17:27:46|.www.jb.com.br
2020-03-19 17:27:43|www.jb.com.br
2020-03-19 17:27:43|www.jb.com.br
 
Deleting Firefox Site Data........
==================================
https+++www.google.com
https+++www.theguardian.com
https+++www.youtube.com
 
Deleting Firefox Cache...........
=================================
Files: 383 Size: 15M
 


 Press ENTER to exit

Here is the output of the script that deals with Google Chrome when I just list the current situation:


WARNING:
The Google Chrome browser must not be running if you are going to list or delete its data files.
 
[D]elete, [L]ist or [E]xit: l 
 
Current URLs...........
=======================
2020-03-19 17:30:41|https://duckduckgo.com/
2020-03-19 17:30:44|https://www.youtube.com/
2020-03-19 17:30:49|https://www.accuweather.com/en/gb/united-kingdom-weather
2020-03-19 17:30:57|http://www.folha.uol.com.br/
2020-03-19 17:30:57|https://www.folha.uol.com.br/
 
Current Cookies........
=======================
2020-03-19 17:30:49|.accuweather.com
2020-03-19 17:31:11|.uol.com.br
2020-03-19 17:31:11|.bt.uol.com.br
2020-03-19 17:30:44|.youtube.com
2020-03-19 17:30:50|.accuweather.com
2020-03-19 17:30:57|.accuweather.com
2020-03-19 17:30:45|accounts.google.com
2020-03-19 17:30:44|.youtube.com
2020-03-19 17:30:46|.doubleclick.net
2020-03-19 17:31:08|player.mais.uol.com.br
2020-03-19 17:30:50|.google.com
2020-03-19 17:31:11|.dna.uol.com.br
2020-03-19 17:31:05|paywall.folha.uol.com.br
2020-03-19 17:30:58|.www.accuweather.com
2020-03-19 17:31:04|.smartadserver.com
2020-03-19 17:31:04|.smartadserver.com
2020-03-19 17:30:50|.scorecardresearch.com
2020-03-19 17:30:50|.scorecardresearch.com
2020-03-19 17:30:44|.youtube.com
2020-03-19 17:30:44|.youtube.com
2020-03-19 17:31:05|.uol.com.br
2020-03-19 17:30:51|www.accuweather.com
2020-03-19 17:31:10|www.folha.uol.com.br
2020-03-19 17:30:51|www.accuweather.com
2020-03-19 17:30:58|www.folha.uol.com.br
2020-03-19 17:30:51|www.accuweather.com
2020-03-19 17:31:10|www.folha.uol.com.br
2020-03-19 17:30:51|www.accuweather.com
2020-03-19 17:31:10|www.folha.uol.com.br
2020-03-19 17:30:58|www.accuweather.com
2020-03-19 17:30:58|.accuweather.com
2020-03-19 17:31:01|.uol.com.br
2020-03-19 17:30:58|.accuweather.com
2020-03-19 17:31:04|www.folha.uol.com.br
2020-03-19 17:31:04|www.folha.uol.com.br
2020-03-19 17:30:50|.accuweather.com
2020-03-19 17:31:01|.uol.com.br
2020-03-19 17:30:50|.accuweather.com
2020-03-19 17:31:01|.uol.com.br
2020-03-19 17:31:11|.uol.com.br
2020-03-19 17:31:11|.uol.com.br
2020-03-19 17:30:51|.accuweather.com
2020-03-19 17:30:51|.accuweather.com
2020-03-19 17:30:51|.accuweather.com
2020-03-19 17:31:00|.t.tailtarget.com
2020-03-19 17:31:05|www.folha.uol.com.br
2020-03-19 17:31:05|paywall.folha.uol.com.br
2020-03-19 17:30:51|.accuweather.com
2020-03-19 17:31:04|.rubiconproject.com
2020-03-19 17:30:49|www.accuweather.com
2020-03-19 17:30:50|www.accuweather.com
2020-03-19 17:31:08|.uol.com.br
2020-03-19 17:30:57|www.accuweather.com
2020-03-19 17:31:05|www.folha.uol.com.br
2020-03-19 17:31:05|www.folha.uol.com.br
2020-03-19 17:31:05|www.folha.uol.com.br
2020-03-19 17:31:05|www.folha.uol.com.br
2020-03-19 17:31:04|.rubiconproject.com
2020-03-19 17:31:06|player.mais.uol.com.br
2020-03-19 17:31:06|player.mais.uol.com.br
2020-03-19 17:31:05|.t.tailtarget.com
2020-03-19 17:30:58|.uol.com.br
2020-03-19 17:30:58|.navdmp.com
2020-03-19 17:31:04|.smartadserver.com
2020-03-19 17:31:05|www.folha.uol.com.br
2020-03-19 17:30:51|.accuweather.com
2020-03-19 17:31:04|.rubiconproject.com
2020-03-19 17:31:04|.smartadserver.com
2020-03-19 17:31:04|.smartadserver.com
2020-03-19 17:31:04|.rubiconproject.com
2020-03-19 17:31:04|.rubiconproject.com
2020-03-19 17:31:06|ivccf.ivcbrasil.org.br
2020-03-19 17:31:10|.tt-10162-1.seg.t.tailtarget.com
2020-03-19 17:31:04|.tt-12340-4.seg.t.tailtarget.com
2020-03-19 17:31:05|www.folha.uol.com.br
2020-03-19 17:31:05|www.folha.uol.com.br
2020-03-19 17:31:04|www.folha.uol.com.br
2020-03-19 17:31:04|www.folha.uol.com.br
2020-03-19 17:31:04|www.folha.uol.com.br
2020-03-19 17:31:04|www.folha.uol.com.br
2020-03-19 17:31:05|.t.tailtarget.com
2020-03-19 17:31:05|.t.tailtarget.com
2020-03-19 17:31:05|.tt-10162-1.seg.t.tailtarget.com
2020-03-19 17:31:05|.tt-12340-4.seg.t.tailtarget.com
2020-03-19 17:31:05|.t.tailtarget.com
2020-03-19 17:31:00|.t.tailtarget.com
2020-03-19 17:30:50|www.accuweather.com
2020-03-19 17:30:57|www.accuweather.com
2020-03-19 17:31:04|.rubiconproject.com
2020-03-19 17:31:04|.rubiconproject.com
2020-03-19 17:31:04|.smartadserver.com
2020-03-19 17:30:50|www.accuweather.com
2020-03-19 17:31:04|.prg.smartadserver.com
2020-03-19 17:31:22|www.folha.uol.com.br
2020-03-19 17:31:20|.uol.com.br
2020-03-19 17:31:10|.uol.com.br
 
Current Chrome Cache.............
=================================
Files: 317 Size: 8.6M


 Press ENTER to exit

Here is the output of the script that deals with Google Chrome when I delete the browser data:


WARNING:
The Google Chrome browser must not be running if you are going to list or delete its data files.
 
[D]elete, [L]ist or [E]xit: d 
 
Deleting URLs...........
========================
2020-03-19 17:30:41|https://duckduckgo.com/
2020-03-19 17:30:44|https://www.youtube.com/
2020-03-19 17:30:49|https://www.accuweather.com/en/gb/united-kingdom-weather
2020-03-19 17:30:57|http://www.folha.uol.com.br/
2020-03-19 17:30:57|https://www.folha.uol.com.br/
 
Deleting Cookies........
========================
2020-03-19 17:30:49|.accuweather.com
2020-03-19 17:31:11|.uol.com.br
2020-03-19 17:31:11|.bt.uol.com.br
2020-03-19 17:30:44|.youtube.com
2020-03-19 17:30:50|.accuweather.com
2020-03-19 17:30:57|.accuweather.com
2020-03-19 17:30:45|accounts.google.com
2020-03-19 17:30:44|.youtube.com
2020-03-19 17:30:46|.doubleclick.net
2020-03-19 17:31:08|player.mais.uol.com.br
2020-03-19 17:30:50|.google.com
2020-03-19 17:31:11|.dna.uol.com.br
2020-03-19 17:31:05|paywall.folha.uol.com.br
2020-03-19 17:30:58|.www.accuweather.com
2020-03-19 17:31:04|.smartadserver.com
2020-03-19 17:31:04|.smartadserver.com
2020-03-19 17:30:50|.scorecardresearch.com
2020-03-19 17:30:50|.scorecardresearch.com
2020-03-19 17:30:44|.youtube.com
2020-03-19 17:30:44|.youtube.com
2020-03-19 17:31:05|.uol.com.br
2020-03-19 17:30:51|www.accuweather.com
2020-03-19 17:31:10|www.folha.uol.com.br
2020-03-19 17:30:51|www.accuweather.com
2020-03-19 17:30:58|www.folha.uol.com.br
2020-03-19 17:30:51|www.accuweather.com
2020-03-19 17:31:10|www.folha.uol.com.br
2020-03-19 17:30:51|www.accuweather.com
2020-03-19 17:31:10|www.folha.uol.com.br
2020-03-19 17:30:58|www.accuweather.com
2020-03-19 17:30:58|.accuweather.com
2020-03-19 17:31:01|.uol.com.br
2020-03-19 17:30:58|.accuweather.com
2020-03-19 17:31:04|www.folha.uol.com.br
2020-03-19 17:31:04|www.folha.uol.com.br
2020-03-19 17:30:50|.accuweather.com
2020-03-19 17:31:01|.uol.com.br
2020-03-19 17:30:50|.accuweather.com
2020-03-19 17:31:01|.uol.com.br
2020-03-19 17:31:11|.uol.com.br
2020-03-19 17:31:11|.uol.com.br
2020-03-19 17:30:51|.accuweather.com
2020-03-19 17:30:51|.accuweather.com
2020-03-19 17:30:51|.accuweather.com
2020-03-19 17:31:00|.t.tailtarget.com
2020-03-19 17:31:05|www.folha.uol.com.br
2020-03-19 17:31:05|paywall.folha.uol.com.br
2020-03-19 17:30:51|.accuweather.com
2020-03-19 17:31:04|.rubiconproject.com
2020-03-19 17:30:49|www.accuweather.com
2020-03-19 17:30:50|www.accuweather.com
2020-03-19 17:31:08|.uol.com.br
2020-03-19 17:30:57|www.accuweather.com
2020-03-19 17:31:05|www.folha.uol.com.br
2020-03-19 17:31:05|www.folha.uol.com.br
2020-03-19 17:31:05|www.folha.uol.com.br
2020-03-19 17:31:05|www.folha.uol.com.br
2020-03-19 17:31:04|.rubiconproject.com
2020-03-19 17:31:06|player.mais.uol.com.br
2020-03-19 17:31:06|player.mais.uol.com.br
2020-03-19 17:31:05|.t.tailtarget.com
2020-03-19 17:30:58|.uol.com.br
2020-03-19 17:30:58|.navdmp.com
2020-03-19 17:31:04|.smartadserver.com
2020-03-19 17:31:05|www.folha.uol.com.br
2020-03-19 17:30:51|.accuweather.com
2020-03-19 17:31:04|.rubiconproject.com
2020-03-19 17:31:04|.smartadserver.com
2020-03-19 17:31:04|.smartadserver.com
2020-03-19 17:31:04|.rubiconproject.com
2020-03-19 17:31:04|.rubiconproject.com
2020-03-19 17:31:06|ivccf.ivcbrasil.org.br
2020-03-19 17:31:10|.tt-10162-1.seg.t.tailtarget.com
2020-03-19 17:31:04|.tt-12340-4.seg.t.tailtarget.com
2020-03-19 17:31:05|www.folha.uol.com.br
2020-03-19 17:31:05|www.folha.uol.com.br
2020-03-19 17:31:04|www.folha.uol.com.br
2020-03-19 17:31:04|www.folha.uol.com.br
2020-03-19 17:31:04|www.folha.uol.com.br
2020-03-19 17:31:04|www.folha.uol.com.br
2020-03-19 17:31:05|.t.tailtarget.com
2020-03-19 17:31:05|.t.tailtarget.com
2020-03-19 17:31:05|.tt-10162-1.seg.t.tailtarget.com
2020-03-19 17:31:05|.tt-12340-4.seg.t.tailtarget.com
2020-03-19 17:31:05|.t.tailtarget.com
2020-03-19 17:31:00|.t.tailtarget.com
2020-03-19 17:30:50|www.accuweather.com
2020-03-19 17:30:57|www.accuweather.com
2020-03-19 17:31:04|.rubiconproject.com
2020-03-19 17:31:04|.rubiconproject.com
2020-03-19 17:31:04|.smartadserver.com
2020-03-19 17:30:50|www.accuweather.com
2020-03-19 17:31:04|.prg.smartadserver.com
2020-03-19 17:31:22|www.folha.uol.com.br
2020-03-19 17:31:20|.uol.com.br
2020-03-19 17:31:10|.uol.com.br
 
Deleting Chrome Cache.......
=====================
Files: 317 Size: 8.6M
 
Deleting Code Cache......
=========================
 
Deleting Visited Links......
============================
 
Deleting Top Sites......
========================


 Press ENTER to exit

Update March 23, 2020: For those of you who would prefer a single script that can delete the browsing history, cookies and cache files of Google Chrome and/or Firefox and/or Thunderbird, I have now created the script clear_browser_data.sh shown below with appropriate Desktop Configuration files for Gentoo Linux and Lubuntu 18.04. In addition I have now added the ability to list and delete the history and cache files of Thunderbird, as I have checked that deleting those is not detremental to Thunderbird. Furthermore, this new script finds the directories itself rather than having them partially hard-coded in the script, so I am using the same script in both Gentoo and Lubuntu 18.04. That said, I have not tested the script with other versions of Chrome, Firefox and Thunderbird, nor with other Linux distributions, so do not select [D]elete until you have checked that the directories evaluated by the script match the directories in your installation.

#!/bin/bash
#
########################################################################
#
# Bash script to enable the user to list and/or delete browser data of:
# Google Chrome browser
# Mozilla Firefox browser
# Mozilla Thunderbird e-mail client
#
########################################################################
#
# Check for existence of the applications' directories
FIREFOX=$( ls $HOME/.mozilla/firefox 2>/dev/null | grep profiles.ini )
THUNDERBIRD=$( ls $HOME/.thunderbird  2>/dev/null | grep profiles.ini )
CHROME=$( ls -d $HOME/.config/google-chrome 2>/dev/null )
if [ -z "$CHROME" ]; then
   echo
   echo "Chrome directory does not exist"
else
   # Chrome directory locations
   #
   CLOCALST=$( find $HOME/.config/google-chrome -type f -name "Local State" )
   CCURPROF=$( cat "$CLOCALST" | awk -F "," '{for (I=1;I<=NF;I++) if ($I~/"info_cache"/) {print $(I)};}' | awk -F "info_cache" '{print $2}' | awk -F '"' '{print $3}' )   
   CHISTORY=$( find $HOME/.config/google-chrome/"$CCURPROF" -type f -name "History" )
   CCOOKIES=$( find $HOME/.config/google-chrome/"$CCURPROF" -type f -name "Cookies" )
   CVISITED=$( find $HOME/.config/google-chrome/"$CCURPROF" -type f -name "Visited Links" )
   CTOPSITS=$( find $HOME/.config/google-chrome/"$CCURPROF" -type f -name "Top Sites" )
   CCACHEDF=$( find $HOME/.cache/google-chrome/"$CCURPROF" -type d -name "Cache" )
   CCODECAC=$( find $HOME/.cache/google-chrome/"$CCURPROF" -maxdepth 2 -type d -name "Code Cache" )
   echo; echo "Chrome is using profile: $CCURPROF"
   
fi
if [ -z "$FIREFOX" ]; then
   echo
   echo "Firefox directory does not exist"
else
   # Firefox file locations. First get the current Profile Name
   # The profiles are listed in 'profiles.ini'.
   # If profiles.ini does not contain a line 'Locked=1' then the current profile
   # is followed by the line 'Default=1'. If profiles.ini does contain 'Locked=1'
   # then the current profile is followed by the line 'Locked=1'
   #
   FPROFILE=$( find $HOME/.mozilla/firefox/ -type f -name "profiles.ini" )
   if grep -q "Locked=1$" "$FPROFILE"; then
      FCURPROF=$( grep -B 1 "Locked=1$" "$FPROFILE" | grep -v Locked )
   else
      FCURPROF=$( grep -B 1 "Default=1$" "$FPROFILE" | grep -v Default )
   fi
   FCURPROF=$( echo "$FCURPROF" | cut -d"=" -f2 )
   FHISTORY=$( find $HOME/.mozilla/firefox/"$FCURPROF" -type f -name "places.sqlite" )
   FCOOKIES=$( find $HOME/.mozilla/firefox/"$FCURPROF" -type f -name "cookies.sqlite" )
   FSITEDAT=$( find $HOME/.mozilla/firefox/"$FCURPROF" -type d -name "default" )
   FCACHEDF=$( find $HOME/.cache/mozilla/firefox/"$FCURPROF" -type d -name "entries" )
   echo; echo "Firefox is using profile: $FCURPROF"
fi
if [ -z "$THUNDERBIRD" ]; then
   echo
   echo "Thunderbird directory does not exist"
else
   # Thunderbird file locations. First get the current Profile Name
   # The profiles are listed in 'profiles.ini'.
   # If profiles.ini does not contain the line 'Locked=1' then the current profile
   # is followed by the line 'Default=1'. If profiles.ini does contain 'Locked=1'
   # then the current profile is followed by the line 'Locked=1'
   #
   TPROFILE=$( find $HOME/.thunderbird/ -type f -name "profiles.ini" )
   if grep -q "Locked=1$" "$TPROFILE"; then
      TCURPROF=$( grep -B 1 "Locked=1$" "$TPROFILE" | grep -v Locked )
   else
      TCURPROF=$( grep -B 1 "Default=1$" "$TPROFILE" | grep -v Default )
   fi
   TCURPROF=$( echo "$TCURPROF" | cut -d"=" -f2 )
   THISTORY=$( find $HOME/.thunderbird/"$TCURPROF" -type f -name "places.sqlite" )
   TCOOKIES=$( find $HOME/.thunderbird/"$TCURPROF" -type f -name "cookies.sqlite" )
   TCACHEDF=$( find $HOME/.cache/thunderbird/"$TCURPROF" -type d -name "entries" )
   echo; echo "Thunderbird is using profile: $TCURPROF"
fi
#
MENU=""
while [[ $MENU != "E" ]] && [[ $MENU != "e" ]]; do
   echo
   echo -n "[C]hrome, [F]irefox, T[hunderbird or [E]xit: "
   read -n1 MENU
   echo
   case $MENU in
      [Cc] ) ;;
      [Ff] ) ;;
      [Tt] ) ;;
      [Ee] ) ;;
      * ) echo; echo " Enter 'C/c', 'F/f', 'T/t' or 'E/e'"
   esac
   #########
   # Chrome
   #########
   while [[ $MENU == "C" ]] || [[ $MENU == "c" ]]; do
      pgrep -u $USER chrome > /dev/null
      if [[ $? -eq 0 ]]; then
         echo
         echo -n "Chrome Browser is open, do you wish to close it now? [Y/N]: "
         read -n1 YN
         echo
         if [[ $YN == "Y" ]] || [[ $YN == "y" ]]; then
            CPID=$( pgrep -u $USER chrome )
            CPID=$( echo $CPID | cut -d" " -f1 )
            kill -1 $CPID
         else
            echo
            echo " Cannot list or delete browser URLs if the browser is open"
            break
         fi
      fi
      if [ -z "$CHROME" ]; then
         echo
         echo "Chrome directory does not exist"
         break
      else
         CPROMPT=""
         echo
         echo -n "[D]elete, [L]ist or [E]xit: "
         read -n1 CPROMPT
         echo
         case $CPROMPT in
            [Dd] ) echo; echo " Chrome is using profile: $CCURPROF";;
            [Ll] ) echo; echo " Chrome is using profile: $CCURPROF";;
            [Ee] ) ;;
            * ) echo; echo " Enter 'D/d', 'L/l' or 'E/e'";;
         esac
         if [[ $CPROMPT == "E" ]] || [[ $CPROMPT == "e" ]]; then MENU=""; fi
         if [[ $CPROMPT == "D" ]] || [[ $CPROMPT == "d" ]]; then
            echo
            echo " Deleting Chrome URLs............."
            echo " ================================="
            sqlite3 "$CHISTORY" "select datetime(last_visit_time/1000000 + (strftime('%s', '1601-01-01')),'unixepoch'),url from urls; delete from urls;" | sed 's/^/ /'
            echo
            echo " Deleting Chrome Cookies.........."
            echo " ================================="
            sqlite3 "$CCOOKIES" "select datetime(creation_utc/1000000 + (strftime('%s', '1601-01-01')),'unixepoch'),host_key from cookies; delete from cookies;" | sed 's/^/ /'
            if [[ -d "$CCACHEDF" ]]; then
               echo
               echo " Deleting Chrome Cache............"
               echo " ================================="
               NUM=$( ls -1 "$CCACHEDF" | wc -l )
               SIZ=$( du -sbh "$CCACHEDF" )
               SIZ=$( echo $SIZ | cut -d" " -f1 )
               echo " Files: $NUM Size: $SIZ"
               rm -r "$CCACHEDF"
            fi
            if [[ -d "$CCODECAC" ]]; then
               echo
               echo " Deleting Chrome Code Cache......."
               echo " ================================="
               NUM=$( ls -1 "$CCODECAC" | wc -l )
               SIZ=$( du -sbh "$CCODECAC" )
               SIZ=$( echo $SIZ | cut -d" " -f1 )
               echo " Files: $NUM Size: $SIZ"
               rm -r "$CCODECAC"
            fi
            if [[ -f "$CVISITED" ]]; then
               echo
               echo " Deleting Visited Links..........."
               echo " ================================="
               rm "$CVISITED"
            fi
            if [[ -f "$CTOPSITS" ]]; then
               echo
               echo " Deleting Chrome Top Sites........"
               echo " ================================="
               rm "$CTOPSITS"
            fi
         fi
         if [[ $CPROMPT == "L" ]] || [[ $CPROMPT == "l" ]]; then
            echo
            echo " Current Chrome URLs.............."
            echo " ================================="
            sqlite3 "$CHISTORY" "select datetime(last_visit_time/1000000 + (strftime('%s', '1601-01-01')),'unixepoch'),url from urls;" | sed 's/^/ /' | more
            echo
            echo " Current Chrome Cookies..........."
            echo " ================================="
            sqlite3 "$CCOOKIES" "select datetime(creation_utc/1000000 + (strftime('%s', '1601-01-01')),'unixepoch'),host_key from cookies;" | sed 's/^/ /' |more
            if [[ -d "$CCACHEDF" ]]; then
               echo
               echo " Current Chrome Cache............."
               echo " ================================="
               NUM=$( ls -1 "$CCACHEDF" | wc -l )
               SIZ=$( du -sbh "$CCACHEDF" )
               SIZ=$( echo $SIZ | cut -d" " -f1 )
               echo " Files: $NUM Size: $SIZ"
            fi
            if [[ -d "$CCODECAC" ]]; then
               echo
               echo " Current Chrome Code Cache............."
               echo " ======================================"
               NUM=$( ls -1 "$CCODECAC" | wc -l )
               SIZ=$( du -sbh "$CCODECAC" )
               SIZ=$( echo $SIZ | cut -d" " -f1 )
               echo " Files: $NUM Size: $SIZ"
            fi
         fi
         CPROMPT=""
      fi
   done
   ##########
   # Firefox
   ##########
   while [[ $MENU == "F" ]] || [[ $MENU == "f" ]]; do
      pgrep -u $USER firefox > /dev/null
      if [[ $? -eq 0 ]]; then
         echo
         echo -n "Firefox Browser is open, do you wish to close it now? [Y/N]: "
         read -n1 YN
         echo
         if [[ $YN == "Y" ]] || [[ $YN == "y" ]]; then
            FPID=$( pgrep -u $USER firefox )
            FPID=$( echo $FPID | cut -d" " -f1 )
            kill -1 $FPID
         else
            echo
            echo " Cannot list or delete browser URLs if the browser is open"
            break
         fi
      fi
      if [ -z "$FIREFOX" ]; then
         echo
         echo "Firefox directory does not exist"
         break
      else
         FPROMPT=""
         echo
         echo -n "[D]elete, [L]ist or [E]xit: "
         read -n1 FPROMPT
         echo
         case $FPROMPT in
            [Dd] ) echo; echo " Firefox is using profile: $FCURPROF";;
            [Ll] ) echo; echo " Firefox is using profile: $FCURPROF";;
            [Ee] ) ;;
            * ) echo; echo " Enter 'D/d', 'L/l' or 'E/e'";;
         esac
         if [[ $FPROMPT == "E" ]] || [[ $FPROMPT == "e" ]]; then MENU=""; fi
         if [[ $FPROMPT == "D" ]] || [[ $FPROMPT == "d" ]]; then
            echo
            echo " Deleting Firefox History........."
            echo " ================================="
            sqlite3 "$FHISTORY" "SELECT datetime(moz_historyvisits.visit_date/1000000,'unixepoch'), moz_places.url FROM moz_places, moz_historyvisits WHERE moz_places.id = moz_historyvisits.place_id;" | sed 's/^/ /'
            sqlite3 "$FHISTORY" "delete from moz_historyvisits;"
            echo
            echo " Deleting Firefox Cookies........."
            echo " ================================="
            sqlite3 "$FCOOKIES" "select datetime(creationTime/1000000,'unixepoch'),host from moz_cookies; delete from moz_cookies;" | sed 's/^/ /'
            echo
            echo " Deleting Firefox Site Data......."
            echo " ================================="
            ls "$FSITEDAT" | grep http | sed 's/^/ /'
            find "$FSITEDAT" -name "http*" -type d -exec rm -r "{}" \; -prune
            echo
            echo " Deleting Firefox Cache..........."
            echo " ================================="
            if [[ $( ls -A "$FCACHEDF" ) ]]; then # Directory not empty
               NUM=$( ls -1 "$FCACHEDF" | wc -l )
               SIZ=$( du -sbh "$FCACHEDF" )
               SIZ=$( echo $SIZ | cut -d" " -f1 )
               echo " Files: $NUM Size: $SIZ"
               find "$FCACHEDF" -type f -delete
            fi
         fi
         if [[ $FPROMPT == "L" ]] || [[ $FPROMPT == "l" ]]; then
            echo
            echo " Current Firefox History.........."
            echo " ================================="
            sqlite3 "$FHISTORY" "SELECT datetime(moz_historyvisits.visit_date/1000000,'unixepoch'), moz_places.url FROM moz_places, moz_historyvisits WHERE moz_places.id = moz_historyvisits.place_id;" | sed 's/^/ /' | more
            echo
            echo " Current Firefox Cookies.........."
            echo " ================================="
            sqlite3 "$FCOOKIES" "select datetime(creationTime/1000000,'unixepoch'),host from moz_cookies;" | sed 's/^/ /' | more
            echo
            echo " Current Firefox Site Data........"
            echo " ================================="
            ls "$FSITEDAT" | grep http | sed 's/^/ /' | more
            echo
            echo " Current Firefox Cache..........."
            echo " ================================"
            NUM=$( ls -1 "$FCACHEDF" | wc -l )
            SIZ=$( du -sbh "$FCACHEDF" )
            SIZ=$( echo $SIZ | cut -d" " -f1 )
            echo " Files: $NUM Size: $SIZ"
         fi
         FPROMPT=""
      fi
   done
   ##############
   # Thunderbird
   ##############
   while [[ $MENU == "T" ]] || [[ $MENU == "t" ]]; do
      pgrep -u $USER thunderbird > /dev/null
      if [[ $? -eq 0 ]]; then
         echo
         echo -n "Thunderbird e-mail client is open, do you wish to close it now? [Y/N]: "
         read -n1 YN
         echo
         if [[ $YN == "Y" ]] || [[ $YN == "y" ]]; then
            TPID=$( pgrep -u $USER thunderbird )
            TPID=$( echo $TPID | cut -d" " -f1 )
            kill -1 $TPID
         else
            echo
            echo " Cannot list or delete Thunderbird URLs if the e-mail client is open"
            break
         fi
      fi
      if [ -z "$THUNDERBIRD" ]; then
         echo
         echo "Thunderbird directory does not exist"
         break
      else
         TPROMPT=""
         echo
         echo -n "[D]elete, [L]ist or [E]xit: "
         read -n1 TPROMPT
         echo
         case $TPROMPT in
            [Dd] ) echo; echo " Thunderbird is using profile: $TCURPROF";;
            [Ll] ) echo; echo " Thunderbird is using profile: $TCURPROF";;
            [Ee] ) ;;
            * ) echo; echo " Enter 'D/d', 'L/l' or 'E/e'";;
         esac
         if [[ $TPROMPT == "E" ]] || [[ $TPROMPT == "e" ]]; then MENU=""; fi
         if [[ $TPROMPT == "D" ]] || [[ $TPROMPT == "d" ]]; then
            echo
            echo " Deleting Thunderbird History........."
            echo " ====================================="
            sqlite3 "$THISTORY" "SELECT datetime(moz_historyvisits.visit_date/1000000,'unixepoch'), moz_places.url FROM moz_places, moz_historyvisits WHERE moz_places.id = moz_historyvisits.place_id;" | sed 's/^/ /'
            sqlite3 "$THISTORY" "delete from moz_historyvisits;"
            echo
            echo " Deleting Thunderbird Cookies........."
            echo " ====================================="
            sqlite3 "$TCOOKIES" "select datetime(creationTime/1000000,'unixepoch'),host from moz_cookies; delete from moz_cookies;" | sed 's/^/ /'
            echo
            echo " Deleting Thunderbird Cache..........."
            echo " ====================================="
            if [[ $( ls -A "$TCACHEDF" ) ]]; then # Directory not empty
               NUM=$( ls -1 "$TCACHEDF" | wc -l )
               SIZ=$( du -sbh "$TCACHEDF" )
               SIZ=$( echo $SIZ | cut -d" " -f1 )
               echo " Files: $NUM Size: $SIZ"
               find "$TCACHEDF" -type f -delete
            fi
         fi
         if [[ $TPROMPT == "L" ]] || [[ $TPROMPT == "l" ]]; then
            echo
            echo " Current Thunderbird History.........."
            echo " ====================================="
            sqlite3 "$THISTORY" "SELECT datetime(moz_historyvisits.visit_date/1000000,'unixepoch'), moz_places.url FROM moz_places, moz_historyvisits WHERE moz_places.id = moz_historyvisits.place_id;" | sed 's/^/ /' | more
            echo
            echo " Current Thunderbird Cookies.........."
            echo " ====================================="
            sqlite3 "$TCOOKIES" "select datetime(creationTime/1000000,'unixepoch'),host from moz_cookies;" | sed 's/^/ /' | more
            echo
            echo " Current Thunderbird Cache..........."
            echo " ===================================="
            NUM=$( ls -1 "$TCACHEDF" | wc -l )
            SIZ=$( du -sbh "$TCACHEDF"  )
            SIZ=$( echo $SIZ | cut -d" " -f1 )
            echo " Files: $NUM Size: $SIZ"
         fi
         TPROMPT=""
      fi
   done
done
echo

Listed below is the Desktop Configuration file clear_browser_data.desktop for KDE in Gentoo Linux that I created in the ~/Desktop/ directory. I downloaded a nice PNG icon from the Web, which I saved as ~/Pictures/Icons/broom.png, although of course the Desktop Configuration file can be modified if the icon file were to be stored elsewhere. Obviously change the username accordingly.

[Desktop Entry]
Comment[en_GB]=Clear Chrome, Firefox or Thunderbird caches and cookies
Comment=Clear Chrome, Firefox or Thunderbird caches and cookies
Exec=/home/fitzcarraldo/clear_browser_data.sh
GenericName[en_GB]=Clear browser caches and cookies
GenericName=Clear browser caches and cookies
Icon=/home/fitzcarraldo/Pictures/Icons/broom.png
MimeType=
Name[en_GB]=clear_browser_data
Name=clear_browser_data
Path=/home/fitzcarraldo
StartupNotify=true
Terminal=true
TerminalOptions=
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=none
X-KDE-SubstituteUID=false
X-KDE-Username=fitzcarraldo

Listed below is the Desktop Configuration file clear_browser_data.desktop for LXDE in Lubuntu 18.04 that I created in the ~/Desktop/ directory. I downloaded a nice PNG icon from the Web, which I saved as ~/Pictures/Icons/broom.png, although of course the Desktop Configuration file can be modified if the icon file were to be stored elsewhere. Obviously change the username accordingly.

[Desktop Entry]
Comment[en_GB]=Clear Chrome, Firefox or Thunderbird caches and cookies
Comment=Clear Chrome, Firefox or Thunderbird caches and cookies
Exec=/home/fitzcarraldo/clear_browser_data.sh
GenericName[en_GB]=Clear browser caches and cookies
GenericName=Clear browser caches and cookies
Icon=/home/fitzcarraldo/Pictures/Icons/broom.png
MimeType=
Name[en_GB]=clear_browser_data
Name=clear_browser_data
Path=/home/fitzcarraldo
StartupNotify=true
Terminal=true
TerminalOptions=\s--noclose
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=none
X-LXDE-SubstituteUID=false
X-LXDE-Username=fitzcarraldo

Update April 5, 2020: I have modified Lines 24, 37 (a comment), 40 and 55 in the above script. The original Line 24 did not select the Chrome profile name correctly in another installation, the original Line 40 did not select the Firefox profile name correctly in another installation, and the search string for the Thunderbird profile was not tight enough in the original Line 55. The above script now works in three different installations.

Update April 25, 2020: Arrgghh! I installed Thunderbird in Lubuntu 18.04 and discovered that clear_browser_data.sh did not find the Thunderbird cached files to delete. Unlike Thunderbird in Gentoo Linux on my main laptop, the file profiles.ini for Thunderbird (but not Firefox) in my Lubuntu 18.04 installation contains a line ‘Locked=1‘, and the actual profile used by Thunderbird in Lubuntu 18.04 is the profile specified in the line before ‘Locked=1‘, not the profile specified in the line before ‘Default=1‘. Someone I know uses Ubuntu 16.04 and he tells me Firefox in his installation is like this too. So, for reasons I don’t know, profiles.ini contains ‘Locked=1‘ in some Firefox or Thunderbird installations but not in others. Anyway, I have now modified the script to cater for both cases. It checks if the profiles.ini files for Firefox and Thunderbird contain ‘Locked=1‘ and, if they do, finds the currently-used profile from the line before ‘Locked=1‘ instead of the line before ‘Default=1‘. The line numbers mentioned in my previous update will be different now.

Installing Dropbox in Gentoo Linux following the recent restrictions introduced for Dropbox for Linux

In a 2013 post I explained how I installed Dropbox in Gentoo Linux running KDE 4. The Dropbox company has recently imposed some restrictions in the Linux client, so this is to explain what I did to get Dropbox working again in my two Gentoo Linux installations, both using the ext4 filesystem (unencrypted) and, these days, KDE Plasma 5.

Both my laptops running Gentoo Linux had a version of Dropbox installed via the Portage package manager: dropbox-45.3.88 in the case of the laptop running Gentoo amd64, and dropbox-48.3.56 in the case of the laptop running Gentoo ~amd64. Recently a Dropbox window popped up, warning me to upgrade Dropbox to the latest version within seven days otherwise the client would no longer be able to sync with the remote Dropbox server. I also received an e-mail from the Dropbox company titled ‘[Action required] We’re updating Linux system requirements‘ informing me that the only supported Linux distributions from now on would be Ubuntu 14.04 or higher and Fedora 21 or higher, and furthermore that the client will only work on an unencrypted ext4 filesystem. As both my Gentoo installations use unencrypted ext4, I was OK on that score, but I still had the problem that an up-to-date Dropbox ebuild is not available for Gentoo and the old Dropbox versions I was using no longer sync. However, I managed to install the latest version of Dropbox (currently 55.4.171) in Gentoo, and it works fine. The Dropbox client’s icon is on the KDE Plasma 5 Panel, and the local Dropbox directory is being sync’ed correctly. Below I explain what I did.

1. I selected ‘Quit Dropbox’ from the old Dropbox client’s menu, and the Dropbox icon disappeared from the Panel.

2. I removed the Dropbox daemon from the list of script files to be started at login (‘System Settings’ > ‘Startup and Shutdown’ > ‘Autostart’).

3. I unmerged (uninstalled) the dropbox package:

clevow230ss /home/fitzcarraldo # emerge --ask --depclean dropbox

4. I deleted the directories ~/.dropbox and ~/.dropbox-dist but kept the directory ~/Dropbox and its contents.

fitzcarraldo@clevow230ss ~ $ rm -rf ~/.dropbox ~/.dropbox-dist

5. I followed the instructions under ‘Dropbox Headless install via command line‘ on the Dropbox Website to re-install the latest version of the daemon and client:

fitzcarraldo@clevow230ss ~ $ cd ~ && wget -O - "https://www.dropbox.com/download?plat=lnx.x86_64" | tar xzf -

6. I configured KDE Plasma 5 to start ~/.dropbox-dist/dropboxd at login (‘System Settings’ > ‘Startup and Shutdown’ > ‘Autostart’ > ‘Add Script…’).

7. I launched ~/.dropbox-dist/dropboxd manually from a Konsole window. The Dropbox client icon appeared on the Panel and I was prompted to login to my Dropbox account via a Web browser, as per the instructions on the Dropbox Website (see link in in Step 5):

If you’re running Dropbox on your server for the first time, you’ll be asked to copy and paste a link in a working browser to create a new account or add your server to an existing account. Once you do, your Dropbox folder will be created in your home directory.

8. I logged in to my Dropbox account via the Firefox browser. As soon as I had logged in via the browser, a message appeared in the browser window informing me that “Your computer was successfully linked to your account”, and the Dropbox client icon appeared on the Panel and showed that the contents of ~/Dropbox were being synchronised.

Everything seems to be working as before. The Dropbox icon on the Panel has the same menu items it had previously. ‘Preferences…’ shows the Dropbox version as v55.4.171. I have not ticked ‘Start Dropbox on system startup’ under Dropbox Preferences because I configured automatic startup using KDE Plasma 5 ‘System Settings’ as described in Step 6 above, and the Dropbox daemon is indeed started automatically when I login.

The Dropbox Website’s instructions (see link in Step 5) also include the following:

Download this Python script to control Dropbox from the command line. For easy access, put a symlink to the script anywhere in your PATH.

I did download that Python script and made it executable:

fitzcarraldo@clevow230ss ~/Dropbox $ chmod +x dropbox.py

However the Python 3.6 interpreter in my Gentoo Linux installations report a syntax error in the script when I run it, I assume because it was written for a different version of Python:

fitzcarraldo@clevow230ss ~/Dropbox $ ./dropbox.py 
  File "./dropbox.py", line 233
    except OSError, e:
                  ^
SyntaxError: invalid syntax

Anyway, as the Dropbox client icon is on the KDE Plasma 5 Panel and I can control Dropbox from there, I see no need for the Python script.

9. My Gentoo installations have a Bash script ~/dbox.sh that I had created to be launched by a Desktop Configuration file ~/Desktop/Dropbox.desktop with a nice icon which I double-click on if I want to relaunch the Dropbox daemon (if I previously quit Dropbox from the client’s menu, for example). I had to modify ~/dbox.sh by replacing the command ‘dbus-launch dropbox start > /dev/null‘ with the command ‘/home/fitzcarraldo/.dropbox-dist/dropboxd‘ as shown below.

dbox.sh

#!/bin/bash
notify-send 'Launching Dropbox' 'Daemon will be (re)started in 20 seconds' --icon=dialog-information
sleep 20s
ps auxww | awk '$0~/dropbox/&&$0!~/awk/{print $2}' | xargs kill
/home/fitzcarraldo/.dropbox-dist/dropboxd

Dropbox.desktop

[Desktop Entry]
Comment[en_GB]=(re)launch Dropbox daemon
Comment=(re)launch Dropbox daemon
Exec=/home/fitzcarraldo/dbox.sh
GenericName[en_GB]=Dropbox
GenericName=Dropbox
Icon=kipi-dropbox
MimeType=
Name[en_GB]=Dropbox
Name=Dropbox
Path=
StartupNotify=true
Terminal=false
TerminalOptions=
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=none
X-KDE-SubstituteUID=false
X-KDE-Username=fitzcarraldo

10. At the moment Dropbox is working fine again in my Gentoo installations. However, I noticed that Gentoo Linux user zsitvaij posted the following comment in a Gentoo Forums thread:

On every dropbox update, I have to remove ~/.dropbox-dist/dropbox-lnx./libdrm.so.2 to avoid having it crash on launch, works fine after until they update again.

I do not know if that will be necessary in my case, as I have not yet had to upgrade Dropbox from the Version 55.4.171 that I recently installed. When a new version of Dropbox becomes available I will update this post to confirm whether or not I had to do anything to keep Dropbox working.

Addendum (5 October 2019): With reference to my addendum of 31 August 2018, the Python script dropbox.py that can be downloaded from the Dropbox Web site has been updated and is now written in Python 3, so you can ignore my addendum of 31 August 2018.

Addendum (1 October 2018): With reference to my addendum of 2 September 2018, if you are using OpenRC it is possible to automate the deletion of the file ~/.dropbox-dist/dropbox-lnx.x86_64-/libdrm.so.2 by creating a Bash script /etc/local.d/40dropbox.start containing the following:

#!/bin/bash
if [ -e /home/fitzcarraldo/.dropbox-dist/dropbox-lnx.x86_64-*/libdrm.so.2 ]
then
    rm /home/fitzcarraldo/.dropbox-dist/dropbox-lnx.x86_64-*/libdrm.so.2
fi

Replace my username with your username, obviously. Of course the conditional test could be dispensed with and the script could just contain the shebang line and the rm line, which would still work even if the file does not exist, but it feels a bit tidier to only attempt to delete the file if it actually exists.

Addendum (2 September 2018): I have just installed Dropbox Version 56.4.94 in my Gentoo ~amd64 installation and I had to use the command shown below once in order to stop the daemon segfaulting when I entered the command ~/.dropbox-dist/dropboxd in a Konsole window:

fitzcarraldo@clevow230ss ~/Dropbox $ rm ~/.dropbox-dist/dropbox-lnx.x86_64-56.4.94/libdrm.so.2

Addendum (31 August 2018): The Python script dropbox.py that can be downloaded from the Dropbox Web site (see Step 8 above) is old, as can be seen in the comments in the header of the script:

# Dropbox frontend script
# This file is part of nautilus-dropbox 2015.10.28.

It is written in Python 2. Although I do not need to use it, I managed to get it to run in my Gentoo installations by replacing the shebang line ‘#!/usr/bin/python‘ with ‘#!/usr/bin/env python2‘. This works in my Gentoo installations because they have both Python 2.7 and Python 3.6 installed. When I now run dropbox.py I see the following:

fitzcarraldo@clevow230ss ~/Dropbox $ ./dropbox.py 
Dropbox command-line interface

commands:

Note: use dropbox help  to view usage for a specific command.

 status       get current status of the dropboxd
 throttle     set bandwidth limits for Dropbox
 help         provide help
 stop         stop dropboxd
 running      return whether dropbox is running
 start        start dropboxd
 filestatus   get current sync status of one or more files
 ls           list directory contents with current sync status
 autostart    automatically start dropbox at login
 exclude      ignores/excludes a directory from syncing
 lansync      enables or disables LAN sync
 sharelink    get a shared link for a file in your dropbox
 proxy        set proxy settings for Dropbox

fitzcarraldo@clevow230ss ~/Dropbox $ ./dropbox.py status
Up to date
fitzcarraldo@clevow230ss ~/Dropbox $ ./dropbox.py running
fitzcarraldo@clevow230ss ~/Dropbox $ ./dropbox.py filestatus ~/Dropbox/Getting\ Started.pdf 
/home/fitzcarraldo/Dropbox/Getting Started.pdf: up to date
fitzcarraldo@clevow230ss ~/Dropbox $

Notice that the command ./dropbox.py running does not return anything even though the daemon is definitely running, so I do not trust the script anyway.

Syncing browser bookmarks between browsers and machines in Linux

I use several computers and various browsers (predominantly Firefox, Chrome and Chromium) and was fed up with bookmarking a site on one machine and later not finding it on another machine. For quite some time I had therefore been looking for a simple way of synchronising browser bookmarks across all my machines and browsers, and I finally found one. Below I explain what I did.

I wanted to avoid storing my bookmarks on a third-party company’s server, so that ruled out tools such as Xmarks, EverSync, Google Bookmarks and the like. I wanted the bookmark database to reside on one of my own servers that is already accessible securely via the Internet. Apparently Xmarks optionally does enable you to use your own server providing you use only Firefox, but I use various browsers (Firefox is the default browser on my main laptop whereas Chrome is the default browser on my backup laptop, for example). Furthermore, I prefer to use open-source solutions whenever possible.

Although I was looking for a GUI solution, it turns out that the command-line bookmark manager Buku does a good job in a drop-down terminal such as Yakuake, Guake or Tilda. Buku is quite powerful, yet simple to use. It is certainly practical to use in a drop-down terminal (I’m currently using it with Yakuake in KDE, and with Tilda in LXDE). Not only can you click on links to open pages in the default browser, you can also easily configure your desktop environment to use a keyboard shortcut to bookmark directly from the browser window (see the instructions in the Buku Wiki for details).

Of course, if you only want to use Buku as a local bookmark manager on a machine, you can just install it and use it solely on that machine.

It is not difficult to set up a centralised Buku database that is then synchronised with any machine on which Buku is installed. If you do not have your own Cloud server (ownCloud or Nextcloud, for example), you could use Dropbox instead. The instructions are given in the Buku Wiki. Basically, I did the following to configure several machines to use Buku via the Cloud:

1. Use each browser’s bookmark manager to export the bookmarks to a file.

2. Install Buku on each machine (see ‘Installation‘ on the package’s GitHub repository page if your Linux distribution’s package manager does not offer Buku).

3. Launch Buku once on each machine to create the local database:

$ buku -p
DB file is being created at /home/fitzcarraldo/.local/share/buku/bookmarks.db.
You should encrypt it.
[ERROR] 0 records

4. On one machine, move the Buku database file (~/.local/share/buku/bookmarks.db) to a folder on the machine that is already being synced with the Cloud, then set up a symlink to it. For example:

fitzcarraldo@clevow230ss ~ $ ls -la ~/.local/share/buku/bookmarks.db
lrwxrwxrwx 1 fitzcarraldo fitzcarraldo 51 Mar 21 13:17 /home/fitzcarraldo/.local/share/buku/bookmarks.db -> /media/NTFS/Windows/ownCloud/Bookmarks/bookmarks.db

5. Allow the Cloud client on the other machines to download the bookmarks.db file into their local Cloud sync folder, then delete the local Buku database on each machine (~/.local/share/buku/bookmarks.db) and create a symlink to the Cloud-synchronised database file. For example, in addition to the symlink shown above on the machine clevow230ss, I have the following symlinks on two other machines:

fitzcarraldo@aspirexc600:~$ ls -la ~/.local/share/buku/bookmarks.db
lrwxrwxrwx 1 fitzcarraldo fitzcarraldo 42 Mar 21 16:05 /home/fitzcarraldo/.local/share/buku/bookmarks.db -> /home/fitzcarraldo/ownCloud/Bookmarks/bookmarks.db
fitzcarraldo@meshedgedx ~ $ ls -la /home/fitzcarraldo/.local/share/buku/bookmarks.db
lrwxrwxrwx 1 fitzcarraldo users 42 Mar 26 19:15 /home/fitzcarraldo/.local/share/buku/bookmarks.db -> /home/fitzcarraldo/ownCloud/Bookmarks/bookmarks.db

6. Use Buku on each machine to import the browser bookmark files that you created in Step 1. See the Buku documentation for the command. You can find documentation and a demo video on the above-mentioned GitHub page. The commands ‘man buku‘ and ‘buku --help‘ also list the commands. The man(ual) page also contains several examples to help you.

7. Use Buku as normal on each machine. You will be able to search the synchronised database, add bookmarks and edit them (title, URL, comment and tags), delete bookmarks, print bookmarks, click on links to view the pages in the default browser, and so on.

Looking through a flat list of bookmarks in a terminal window to find something is not as fast as in a GUI but, overall, Buku is a decent bookmark manager and its options are easy to learn and use. Buku’s comprehensive search options of course help to find bookmarks, but it is still not quite as ergonomic as a GUI bookmark manager in my opinion. The ability to have multiple tags in Buku does help, as you can search for either any or all tags. In a browser’s bookmark manager I would copy the same bookmark into different folders if the Web page covers multiple topics.

In summary, Buku is a viable bookmark manager and I like it. It is extremely easy to configure for use with a Cloud server, and I have set it up to synchronise bookmarks on all my machines. I have already imported into Buku the 1,300+ bookmarks from the various browsers on my machines, and deleted the bookmarks in those browsers, so I am using Buku in earnest. I just kept a few of the most-used bookmarks on the browser’s Bookmarks Toolbar, but I’m using Buku on my machines for all the other bookmarks.

If I do have to use a third-party machine running Windows or Linux without Buku installed, I would not be able to access my bookmarks from my Cloud server. To partially get around that, I created a cron job for my user account on each of my machines to periodically run Buku and print the bookmarks to a text file synced on my Cloud server. That way I can at least search through the text file remotely via the Cloud’s Web browser interface (or via WebDAV or via OpenVPN) if I cannot find the Web page I want in a search engine on the third-party machine.

fitzcarraldo@clevow230ss ~ $ crontab -l | grep -v \#
6,26,46 * * * * rm /media/NTFS/Windows/ownCloud/Bookmarks/*.txt; sleep 30s && /usr/bin/buku -p --nc > /media/NTFS/Windows/ownCloud/Bookmarks/Buku_bookmarks_backup.txt
fitzcarraldo@aspirexc600:~$ crontab -l | grep -v \#
1,21,41 * * * * rm /home/fitzcarraldo/ownCloud/Bookmarks/*.txt; sleep 30s && /usr/local/bin/buku -p --nc > /home/fitzcarraldo/ownCloud/Bookmarks/Buku_bookmarks_backup.txt
fitzcarraldo@meshedgedx ~ $ crontab -l | grep -v \#
11,31,51 * * * * rm /home/fitzcarraldo/ownCloud/Bookmarks/*.txt; sleep 30s && /usr/bin/buku -p --nc > /home/fitzcarraldo/ownCloud/Bookmarks/Buku_bookmarks_backup.txt

Below is a small taste of searching the bookmark database using Buku on any of my machines. Output is colour-coded (user-configurable), and links are clickable in a terminal window. You can search for any keyword(s), all keywords, sub-strings, just a tag or tags, regular expression matches, and so on. You can make titles immutable (read-only) if you want, or allow Buku to update them with the title from the Web site page. There is even a command that will check and list broken links. I will leave you to study the Buku documentation.

fitzcarraldo@aspirexc600:~$ buku -S Brazil samba
1. Kaká e Mário Monteiro são os novos carnavalescos da Imperatriz Leopoldinense [159]
   > http://www.sidneyrezende.com/editoria/carnaval
   +  Notícias sobre Carnaval 2016, escolas de samba, desfiles do Grupo Especial, Série A, ensaios técnicos, enredos, carnavalescos, bateria, mestre-sala, porta-bandeira, samba. Mangueira, Unidos da Tijuca, Vila Isabel, Beija-Flor, Grande Rio, Imperatriz, Mocidade, Portela, Salgueiro, União da Ilha, Viradouro, São Clemente, Porto da Pedra, Império da Tijuca, Império Serrano, Estácio de Sá, Caprichosos de Pilares, Tradição, Cubango, Em Cima da Hora, Inocentes de Belford Roxo, Alegria da Zona Sul, Unidos de Padre Miguel, Unidos de Bangu, Renascer de Jacarepaguá, Acadêmicos da Rocinha, Acadêmicos de Santa Cruz, Paraíso de Tuiuti, União de Jacarepaguá, União do Parque Curicica.
        
   # brazil,carnaval

2. Samba do Tuiuti 2018  Versão Acústica - YouTube [1270]
   > https://www.youtube.com/watch?v=yUxfwAzHOeY
   # brazil,carnaval,music,samba,video

buku (? for help) q

In this post I have only scratched the surface of what Buku can do. For example, a simple Buku command will encrypt (AES256) the bookmark database so you can prevent others viewing your bookmarks after you have finished searching the database, should you decide to store the database on a third-party Cloud server such as Dropbox. The search and editing tools are comprehensive yet straightforward, and you will quickly learn how to use them. I take my hat off to its developer, Arun Prakash Jana from Bangalore, India. He and the other contributors to Buku have done a great job, and I recommend you give Buku a try.

xdotool comes to the rescue

In a previous post I explained how I implemented a method for adding my current location and the local time to my e-mail signature wherever I happen to be in the World, irrespective of the time on the laptop’s hardware clock and system clock. In that post I described how I created a keyboard shortcut using the Linux application AutoKey. Unfortunately AutoKey has not been updated for several years and no longer works properly in KDE Plasma 5 on my laptops. Therefore I decided to replace it with a KDE keyboard shortcut, and this is to explain how I did it.

First create a custom shortcut in KDE:

  1. ‘System Settings’ > ‘Shortcuts’ > ‘Custom Shortcuts’
  2. ‘Edit’ > ‘New’ > ‘Global Shortcut’ > ‘Command/URL’, and name the New Action ‘Insert current time’
  3. On the Comment pane for ‘Insert current time’, add the comment ‘Insert current time at specified location’ (without the quotes)
  4. On the Trigger pane, configure the shortcut to be Ctrl+Alt+Space
  5. On the Action pane, enter the Command/URL as ‘/home/fitzcarraldo/timezone_signature_GeoNames.sh‘ (without the quotes)
  6. Click ‘Apply’

Next modify the Bash script timezone_signature_GeoNames.sh so that it contains the following (obviously change the username and path to suit):

#!/bin/bash

place=$(kdialog --title "Current Location" --inputbox "Enter your location:")

placetime=$(perl /home/fitzcarraldo/now1.pl $place)

# xdotool does not output a space in a string, so we have to extract each field from the string
# and print each field individually, separated by a space character.

city=$(echo $placetime | awk -F "|" '{print $1}')
country=$(echo $placetime | awk -F "|" '{print $2}' | sed 's/[)(]//g')
region=$(echo $placetime | awk -F "|" '{print $4}')

datetime=$(/usr/bin/zdump $region | awk -F " " '{print $2" "$3" "$4" "$5" "$6" "$7}')
dayofweek=$(echo $datetime | awk -F " " '{print $1}')
month=$(echo $datetime | awk -F " " '{print $2}')
day=$(echo $datetime | awk -F " " '{print $3}')
time=$(echo $datetime | awk -F " " '{print $4}')
year=$(echo $datetime | awk -F " " '{print $5}')
timezone=$(echo $datetime | awk -F " " '{print $6}')

activewindow=$(xdotool getactivewindow)

xdotool type --window $activewindow "Sent from:"
for oneword in $city; do
    xdotool key --window $activewindow space
    sleep 0.1s
    xdotool type --window $activewindow --delay 100 $oneword
done
xdotool key --window $activewindow comma
for oneword in $country; do
    xdotool key --window $activewindow space
    sleep 0.1s
    xdotool type --window $activewindow --delay 100 $oneword
done
xdotool key --window $activewindow Return
xdotool type --window $activewindow "Local time now: "
xdotool type --window $activewindow $dayofweek
xdotool type --window $activewindow " "
xdotool type --window $activewindow $month
xdotool type --window $activewindow " "
xdotool type --window $activewindow $day
xdotool type --window $activewindow " "
xdotool type --window $activewindow $time
xdotool type --window $activewindow " "
xdotool type --window $activewindow $year
xdotool type --window $activewindow " "
if [ ${timezone:0:1} = "-" ]; then
    timezone="UTC-"${timezone#*-}
elif [ ${timezone:0:1} = "+" ]; then
    timezone="UTC+"${timezone#*+}
fi
xdotool type --window $activewindow $timezone
xdotool type --window $activewindow " "
xdotool key --window $activewindow Return
xdotool key --window $activewindow Return
echo

The Perl script now1.pl is listed in my my earlier post. Notice that the script timezone_signature_GeoNames.sh in my earlier post was much simpler. This was because the AutoKey shortcut took care of sending the text to the currently active window. Without AutoKey, I now had to do this myself in the script timezone_signature_GeoNames.sh, and the command xdotool came to the rescue. The developer explains what xdotool does as follows:

This tool lets you simulate keyboard input and mouse activity, move and resize windows, etc. It does this using X11’s XTEST extension and other Xlib functions.

Additionally, you can search for windows and move, resize, hide, and modify window properties like the title. If your window manager supports it, you can use xdotool to switch desktops, move windows between desktops, and change the number of desktops.

So I installed xdotool via the Gentoo package manager:

# emerge xdotool
# eix xdotool
[I] x11-misc/xdotool
     Available versions:  3.20150503.1-r1^t ~3.20160805.1^t {examples}
     Installed versions:  3.20150503.1-r1^t(22:51:30 02/04/17)(-examples)
     Homepage:            http://www.semicomplete.com/projects/xdotool/
     Description:         Simulate keyboard input and mouse activity, move and resize windows

Anyway, my Bash script using xdotool works a treat with Thunderbird (and KWrite, LibreOffice Writer, etc.). I used to experience a problem with certain characters, for example a colon was printed as a semi-colon (see the xdotool bug report xdotool writes the wrong case #121), but that no longer happens in my current KDE Plasma 5 installation:

Sent from: Galeão International Airport, Brazil
Local time now: Thu Jul 6 15:11:40 2017 UTC-03

What a useful tool xdotool is!

Stuttering audio in Linux: PulseAudio strikes again

I unmasked PulseAudio 10.0 back in January 2017 and installed it in my Gentoo Stable amd64 installation, and everything worked fine… until a couple of days ago, when the audio in streaming YouTube videos started to stutter every so often. It sounded rather like a scratched LP jumping. At first I thought the problem lay with Firefox, but the stuttering audio also occurred in Chrome. Then I wondered if my Internet connection was to blame; perhaps the ISP’s service had deteriorated. But a Windows 10 machine on my home network didn’t suffer from the problem, so that seemed to rule out the Internet connection. I tested the broadband throughput, and it was circa 32 Mbps, actually a little higher than the last time I tested it last year.

Now, Gentoo is a rolling distribution and I update my laptops regularly, but I couldn’t think what had been upgraded in the last couple of months that could be causing the problem. Although PulseAudio had not been upgraded since January, I began to wonder if PulseAudio could be involved, as my audio woes in the past have usually been due to PulseAudio.

I have always had PulseAudio installed with USE=”-realtime”:

user $ eix -I pulseaudio
[I] media-sound/pulseaudio
     Available versions:  10.0 {+X +alsa +alsa-plugin +asyncns bluetooth +caps dbus doc equalizer +gdbm +glib gnome gtk ipv6 jack libressl libsamplerate lirc native-headset neon ofono-headset +orc oss qt4 realtime selinux sox ssl system-wide systemd tcpd test +udev +webrtc-aec zeroconf ABI_MIPS="n32 n64 o32" ABI_PPC="32 64" ABI_S390="32 64" ABI_X86="32 64 x32"}
     Installed versions:  10.0(16:07:53 19/04/17)(X alsa alsa-plugin asyncns bluetooth caps dbus gdbm glib gnome gtk ipv6 jack orc qt4 ssl tcpd udev webrtc-aec zeroconf -doc -equalizer -libressl -libsamplerate -lirc -native-headset -neon -ofono-headset -oss -realtime -selinux -sox -system-wide -systemd -test ABI_MIPS="-n32 -n64 -o32" ABI_PPC="-32 -64" ABI_S390="-32 -64" ABI_X86="32 64 -x32")
     Homepage:            http://www.pulseaudio.org/
     Description:         A networked sound server with an advanced plugin system

but I wondered if PulseAudio’s real-time scheduling was somehow the cause of the problem, so I edited /etc/pulse/daemon.pa and added ‘realtime-scheduling = no‘ (I assume the default is ‘yes‘, as it was commented as such in the file):

; realtime-scheduling = yes
realtime-scheduling = no

Problem solved. PulseAudio is indeed a demon. 😡

Using the ClamAV daemon to scan files placed in my Downloads directory in Gentoo Linux

In a previous post I explained how to automatically detect files placed in my Downloads directory in Linux and scan them for viruses. The method I described in that post used clamscan, the command-line anti-virus scanner of ClamAV. Now, in addition ClamAV has a daemon (a program that runs continuously in the background), clamdscan, that you can enable. So I decided to switch to using clamdscan, as its response to downloaded files is much faster because the process waiting for new files to appear in ~/Downloads/ does not have to load clamscan from disk each time a new file arrives. Anyway, if you want to monitor a download directory in Gentoo Linux (running OpenRC) by using the ClamAV daemon — which will also download virus signature database updates automatically — then the procedure to set this up is given below.

1. Install clamav if it is not installed already:

root # emerge clamav

2. Add the service to the default runlevel:

root # rc-update add clamd default

The daemon will be launched automatically next time the computer boots.

3. The first download of the virus database has to be done manually:

root # freshclam

4. Start the daemon now:

root # rc-service clamd start

5. Create the Bash script ~/monitorDownloadsGUI with the following contents:

#!/bin/bash

DIR=$HOME/Downloads

# Get rid of old log file, if any
rm $HOME/virus-scan.log 2> /dev/null

IFS=$(echo -en "\n\b")

# Optionally, you can use shopt to avoid creating two processes due to the pipe
shopt -s lastpipe
inotifywait --quiet --monitor --event close_write,moved_to --recursive --format '%w%f' $DIR | while read FILE
# Added '--recursive' so that a directory copied into $DIR also triggers clamscan/clamdscan, although downloads
# from the Web would just be files, not directories.
do
# Have to check file length is nonzero otherwise commands may be repeated
if [ -s $FILE ]; then
# Replace 'date >' with 'date >>' if you want to keep log file entries for previous scans.
date > $HOME/virus-scan.log
clamdscan --fdpass --move=$HOME/virus-quarantine $FILE >> $HOME/virus-scan.log
kdialog --title "Virus scan of $FILE" --msgbox "$(cat $HOME/virus-scan.log)"
fi
done

Make it executable:

user $ chmod +x ~/monitorDownloadsGUI

6. Create the directory ~/virus-quarantine/ to store infected files pending investigation/deletion:

user $ mkdir ~/virus-quarantine

7. Install kdialog if it is not already installed:

root # emerge kdialog

8. Use ‘System Settings’ > ‘Startup and Shutdown’ > ‘Autostart’ to add the script ~/monitorDownloadsGUI to the list of script files that are automatically started each time you log in to KDE.

9. Log out then back in again, and you should see that everything is running as expected:

user $ rc-status | grep clam
 clamd                                                             [  started  ]

user $ ps -ef | grep clam | grep -v grep
clamav    1920     1  0 01:48 ?        00:00:00 /usr/sbin/clamd
clamav    1929     1  0 01:48 ?        00:00:00 /usr/bin/freshclam -d

user $ ps -ef | grep GUI | grep -v grep
fitzcarraldo      9143  8971  0 13:56 ?        00:00:00 /bin/bash /home/fitzcarraldo/.config/autostart-scripts/monitorDownloadsGUI.sh

10. To test, surf to http://www.eicar.org/ and download one of the EICAR test files into your ~/Downloads/ directory. You should see a pop-up KDialog window with a message similar to the following:

Virus scan of /home/fitzcarraldo/Downloads/eicarcom2.zip — KDialog

Mon 27 Feb 14:05:26 GMT 2017
/home/fitzcarraldo/Downloads/eicarcom2.zip: Eicar-Test-Signature FOUND
/home/fitzcarraldo/Downloads/eicarcom2.zip: moved to ‘/home/fitzcarraldo/virus-quarantine/eicarcom2.zip’

———– SCAN SUMMARY ———–
Infected files: 1
Time: 0.001 sec (0 m 0 s)

Note that the above-mentioned pop-up window may be preceded by one or more pop-up windows with an error message. I’m using the Chrome browser at the moment, but you may get a similar message if you are using another browser. Here is an example:

Virus scan of /home/fitzcarraldo/Downloads/.com.google.Chrome.Uh3oGm — KDialog ?

Mon 27 Feb 14:16:30 GMT 2017
/home/fitzcarraldo/Downloads/.com.google.Chrome.Uh3oGm: Access denied. ERROR

———– SCAN SUMMARY ———–
Infected files: 0
Total errors: 1
Time: 0.000 sec (0 m 0 s)

Read the error message and click ‘OK’, as this is not an actual problem; it is inotifywait detecting temporary files in the ~/Downloads/ directory during the download process. With larger files sometimes several such messages are displayed, presumably because the file being downloaded is being opened and closed more than once during the downloading process. This issue does not occur if you copy or move a file into ~/Downloads/ from another directory in your installation; try it and see for yourself. Then you only get the one pop-up window with the scan result for the file you put in ~/Downloads/.

Also have a look in ~/virus-quarantine/ and you will see the EICAR test file in that directory. You can delete it if you want (it is not infected with a real virus, so does no harm).

In future be sure to read the messages in the pop-up windows before clicking ‘OK’, as they will inform you that an infected file has been moved to the quarantine directory.

That’s all there is to it. Very simple, and quite handy if you want to check quickly that files you download don’t have a malware payload. Just make sure you download all files into ~/Downloads/ or they will not be checked automatically. Also, if you are given e.g. a USB pen drive with a file on it, you can copy the file to ~/Downloads/ if you want it to be scanned for malware.

BT Broadband and Netflix on a smart TV: a solution at last?

The fix I described in an earlier post stopped working after a couple of weeks, and my family was again unable to access Netflix on our smart TV. Some people had reported that replacing their BT Home Hub 3 with a BT Home Hub 5 resolved the Netflix problem with their smart TVs, so I decided to buy a second-hand BT Home Hub 5 and can report that Netflix is again accessible via the Netflix app on my LG smart TV.

A post by an owner of a Sony smart TV reinforces my suspicion that the problem is due to a combination of providers:

The problem is that netflix app adds 8.8.4.4 as a DNS server. Using anything other than the homehub default gateway as the DNS server returns an error from parental controls as it uses that to apply said controls. No other app on my Sony smart TV does that and just uses what the DHCP server on the homehub hands out. The netflix app has to stop adding that backup IP address for DNS. Is it Sony setting that value or Netflix? Considering it is happening on non-Sony TVs the finger looks to be pointing at Netflix.

Anyway, I just hope the problem is finally solved in my case. The price I paid for the second-hand BT Home Hub 5 was reasonable, and it does have some advantages over the BT Home Hub 3 I was using previously, such as support for 802.11ac Wi-Fi and no need for an external DSL modem, so I am satisfied with the outcome although my opinion of BT is even lower now.

BT Broadband could be cause of Netflix app’s ui-113 message

A couple of months ago I posted regarding a problem with the Netflix app on my LG smart TV (Netflix – Not fit for purpose?). We use BT Infinity broadband with a BT HomeHub 3. The Netflix app on the TV stopped working in early January and always displayed a Netflix ‘ui-113’ message when trying to connect. As we are paying good money to Netflix, we resorted to trying various DNS server addresses posted on the Web for US Netflix, which only work for a short time. Although US Netflix has more content than UK Netflix, we want the latter as it has UK programmes not available on US Netflix. Not to mention that we live in the UK. And it seems my family is not the only one suffering: BT Broadband Users Suffer Problems with Netflix on UK Smart TVs.

Today I found a YouTube video regarding a different Netflix error code (‘nw-2-5’) but, having tried everything else, I tried the suggested fix anyway (Enable Parental Controls then Disable Parental Controls then Delete Parental Controls) and then changed the DNS server address setting in the TV back to the default 192.168.1.254 for the BT Home Hub. Although the Netflix app first displays the ‘ui-113’ or ‘nw-2-5’ messages, if I retry a few times it now manages to connect to UK Netflix. After a couple of months of hassle with Netflix, that is progress.

The fix suggested in the above-mentioned YouTube video consisted of enabling then disabling and deleting BT Parental Controls via the user’s account page on the BT Web site. Even though I had never previously enabled BT Parental Controls, I logged in to the BT Web site, enabled Parental Controls, and then disabled and deleted them as per the instructions given in the aforementioned YouTube video.

So it seems that BT is either the cause of the problem or a major contributor. I suspect the blame may lie with more than one company, though, because: a) the Netflix app’s ‘ui-113’ and ‘nw-2-5’ messages occur even after I made sure BT Parental Controls really are disabled; b) it is touch and go whether the app is successful in accessing the Netflix site at the first attempt; c) other devices accessing Netflix via my home network don’t suffer from the problem. I just hope LG, Netflix and BT are working together to solve it properly, because the current situation is completely unacceptable.